多群集配置
多群集配置确定哪些群集当前是多群集的一部分。 此配置不会自动更改,而是由操作员控制。 因此,它与群集中使用的成员身份机制有很大的差别,后者自动确定作为群集一部分的 silo 集。
我们对服务中的群集使用以下术语:
- 如果某个群集至少有一个活动 silo,则该群集处于活动状态,否则处于非活动状态。
- 如果某个群集是当前多群集配置的一部分,则表示已加入该群集,否则未加入该群集。
活动/非活动状态与已加入/未加入状态无关:所有四种组合都是可行的。
特定服务的所有群集通过 gossip 网络进行连接。 gossip 网络传播配置和状态信息。
注入配置
操作员通过将配置更改注入到多群集网络来发出这些更改。 可将配置注入到任一群集,并从该群集传播到所有活动群集。 每个新配置包含一个构成多群集的群集 ID 列表。 它还包含一个 UTC 时间戳,用于跟踪它在 gossip 网络中的传播情况。
最初,多群集配置为 null,即,多群集列表是空的(不包含任何群集)。 因此,操作员必须首次注入多群集配置。 注入后,此配置将持久保存在已连接的所有 silo(运行时)和指定的所有 gossip 通道(如果这些通道是持久性的)中。
我们对新配置的注入施加了一些限制,操作员必须遵守这些限制:
- 每个新配置可以添加多个群集或删除一些群集(但不能同时执行这两项操作)。
- 当仍在处理先前的配置更改时,操作员不应发出新配置。
这些限制确保协议(例如单实例协议)即使在配置发生更改的情况下也能正确保持激活互相排斥。
管理 grain
可以使用 Orleans 管理 Grain 在任何群集中的任何节点上注入多群集配置。 例如,若要注入由三个群集 { us1, eu1, us2 } 组成的多群集配置,可将一个可枚举字符串传递给管理 grain:
var clusters = "us1,eu1,us2".Split(',');
var mgtGrain = client.GetGrain<IManagementGrain>(0);
mgtGrain.InjectMultiClusterConfiguration(clusters, "my comment here"));
InjectMultiClusterConfiguration(IEnumerable<String>, String, Boolean) 的第一个参数是群集 ID 的集合,它将定义新的多群集配置。 第二个参数是(可选的)注释字符串,可用于使用任意信息(例如谁注入了配置以及为何注入)来标记配置。
第三个参数是可选的,它是一个名为 checkForLaggingSilosFirst
的布尔参数,默认值为 true。 这意味着,系统会尽最大努力检查是否有任何 silo 尚不符合当前配置,如果找到此类 silo,则拒绝更改。 这有助于检测是否违反了每次只能有一个配置更改处于挂起状态这一限制(不过,无法保证在所有情况下都遵守此限制)。
默认配置
在预先知道多群集配置并且每次部署都是新的(用于测试)的情况下,我们可以提供默认配置。 全局配置支持可选属性 DefaultMultiCluster,该属性采用逗号分隔的群集 ID 列表:
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.Configure<MultiClusterOptions>(options =>
{
options.DefaultMultiCluster = new[] { "us1", "eu1", "us2" };
})
})
.Build();
使用此设置启动 silo 后,它会检查当前的多群集配置是否为 null,如果是,则使用当前 UTC 时间戳注入给定配置。
警告
持久性多群集 gossip 通道(基于 Azure 表)保留最后注入的配置,除非显式删除这些通道。 在这种情况下,重新部署群集时指定 DefaultMultiCluster
将不起作用,因为存储在 gossip 通道中的配置不为 null。>
Gossip 通道
操作员还可将配置直接注入到 gossip 通道中。 通道中的更改将被周期性的后台 gossip 自动拾取和传播,不过速度可能非常缓慢(使用管理 grain 要快得多)。 传播时间粗略估计为 30 秒(或者为全局配置中指定的任何 gossip 间隔)乘以所有群集中 silo 总数的二进制对数。 但由于 gossip 对是随机选择的,因此它们的速度可能快得多,也可能慢得多。
如果使用基于 Azure 表的 gossip 通道,则操作员只需通过编辑 OrleansGossipTable
中的配置记录,使用某个用于编辑 Azure 表中数据的工具来注入新的配置。 配置记录的格式如下:
名称 | 类型 | 值 |
---|---|---|
PartitionKey | 字符串 | ServiceId |
RowKey | 字符串 | "CONFIG" |
群集 | String | 群集 ID 的逗号分隔列表,例如“us1,eu1,us2” |
评论 | String | 可选的注释 |
GossipTimestamp | DateTime | 配置的 UTC 时间戳 |
注意
在存储中编辑此记录时,还必须将 GossipTimestamp
设置为比当前值更新的值(否则将忽略更改)。 最方便且建议的方法是删除 GossipTimestamp
字段 - 然后,gossip 通道实现会自动将其替换为正确的当前时间戳(使用 Azure 表时间戳)。
群集过程
在多群集中添加或删除群集时,通常需要在某个更大的上下文中进行协调。 在多群集中添加/删除群集时,我们建议始终遵循下面所述的过程。
添加群集的过程
- 启动新的 Orleans 群集并等待所有接收器启动并运行。
- 注入包含新群集的配置。
- 开始将用户请求路由到新群集。
删除群集的过程
- 停止将新用户请求路由到群集。
- 注入不再包含群集的配置。
- 停止群集的所有 silo。
以这种方式删除群集后,可以按照添加新群集的过程重新添加群集。
未加入的群集上的活动
可能有短暂的一段时间,群集同时处于活动状态和未加入状态:
- 新启动的群集可能在其进入多群集配置之前开始执行代码(处于群集添加过程的步骤 1 和 2 之间的状态)
- 在 silo 关闭之前(处于群集删除过程的步骤 2 和 3 之间的状态),正在解除分配的群集可能仍会执行代码。
在这种中间状态下,可能会出现以下情况:
- 对于全局单实例 grain:grain 可能在未加入的群集上具有重复激活。
- 对于版本受控的 grain:当 grain 状态发生更改时,未加入的群集上的激活不会收到通知。