无状态工作线程粒度

默认情况下,Orleans 运行时在群集中创建的谷物激活不超过一个。 这是虚拟执行组件模型最直观的表达式,其中每个粒度对应于具有唯一类型/标识的实体。 但是,有时应用程序需要执行与系统中特定实体无关的功能性无状态操作。 例如,如果客户端发送具有压缩有效负载的请求,这些请求需要解压缩才能路由到目标粒度进行处理,则此类解压缩/路由逻辑不会绑定到特定实体,并且可以轻松横向扩展。

StatelessWorkerAttribute 应用于粒度类时,它会向Orleans运行时指示该类的粒度应被视为无状态工作粒度。 无状态工作线程粒度具有以下属性,使它们的执行与普通粒度类大不相同:

  1. 运行时 Orleans 能在群集中不同的独立节点上创建多个无状态工作单元的激活。
  2. 只要存储区兼容,无状态工作单元在本地执行请求,这样不会产生额外的网络或序列化成本。 如果本地储存筒仓不兼容,则请求将转发到兼容的筒仓。
  3. 如果现有工作粒子繁忙,Orleans 运行时会自动创建额外的无状态工作粒子的激活。 默认情况下,每个孤岛的最大激活数受计算机上的 CPU 核心数的限制,除非使用可选 maxLocalWorkers 参数显式指定它。
  4. 由于第 2 点和第 3 点,无状态工作单元激活无法单独寻址。 对无状态辅助角色粒度的两个后续请求可能会由不同的激活处理。

无状态工作者粒度提供了一种简单的方法,用于创建自动管理的粒度激活池,以便根据实际负载自动进行扩展和缩减。 运行时始终按相同顺序扫描可用的无状态辅助角色粒度激活。 因此,它始终将请求调度到找到的第一个空闲本地激活,只有当所有之前的激活都繁忙时,才会调度到最后一个。 如果所有激活都繁忙且尚未达到激活限制,则会在列表末尾再创建一个激活,并将请求调度到该激活。 这意味着当无状态工作粒度的请求速率增加并且现有激活都繁忙时,运行时将激活池扩展直至达到限制。 相反,当负载下降且激活次数较少时,列表尾部的激活不会接收请求。 它们变为空闲状态,最终由标准激活收集过程停用。 因此,激活池最终会收缩以匹配负载。

以下示例定义了一个具有默认最大激活数量限制的无状态工作者粒度类MyStatelessWorkerGrain

[StatelessWorker]
public class MyStatelessWorkerGrain : Grain, IMyStatelessWorkerGrain
{
    // ...
}

调用无状态工作粒与调用其他粒子相同。 唯一的区别在于,在大多数情况下,使用单个粒度 ID,例如或 0Guid.Empty。 如果希望具有多个无状态工作单元池(每个 ID 一个),则可以使用多个粒度 ID。

var worker = GrainFactory.GetGrain<IMyStatelessWorkerGrain>(0);
await worker.Process(args);

此示例定义了一个无状态工作器Grain类,每个Silo的激活数不超过一个。

[StatelessWorker(1)] // max 1 activation per silo
public class MyLonelyWorkerGrain : ILonelyWorkerGrain
{
    //...
}

请注意,StatelessWorkerAttribute 不会更改目标类(grain)的可重入性。 与其他任何粒度一样,默认情况下,无状态工作线程粒度不重新进入。 可以通过向粒度类添加一个 ReentrantAttribute 来显式使它们重新进入。

国家

“无状态工作者”的“无状态”部分并不意味着无状态工作者不能有状态或仅限于执行功能操作。 像其他任何粒子一样,无状态工作粒子可以加载并保留它在内存中需要的任何状态。 但是,由于可以在群集中的相同接收器和不同接收器上创建无状态工作粒度的多个激活,因此没有简单的机制来协调不同激活所持有的状态。

几种有用的模式涉及无状态工作器持有状态。

横向扩展的热门缓存项

对于吞吐量较高的热缓存项,将每个项保存在无状态工作者粒度中可以带来以下优势:

  1. 它会自动在孤岛内横向扩展,并跨群集中的所有孤岛进行横向扩展。
  2. 它使数据始终在收到客户端请求的存储仓本地可用,这通过客户端网关接收请求,使得请求能够在不经由其他存储仓进行额外网络跳转的情况下得到应答。

化简样式聚合

在某些情况下,应用程序需要计算群集中特定类型的所有粒度的某些指标,并定期报告聚合。 示例包括报告每个游戏地图的玩家数或 VoIP 呼叫的平均持续时间。 如果成千上万或数百万的颗粒将它们的指标报告给单个全局聚合器,聚合器将立即过载,无法处理大量的报告。 替代方法是将此任务转换为双步(或更多)化简式聚合。 第一层聚合涉及报告粒度将其指标发送到无状态工作者预聚合粒度。 运行时 Orleans 会自动在每个孤堆上创建无状态工作微粒的多个激活。 由于 Orleans 在没有远程调用或消息序列化的情况下在本地处理所有此类调用,因此此聚合的成本明显低于远程情况。 现在,每个无状态预聚合工作单元激活可以独立或与其他本地激活协调,将其聚合后的报告发送到全局最终聚合器,或在必要时发送到另一个归约层,而不造成过载。