恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Orleans 详解:Grain 激活与生命周期全流程实战指南(Activation / Deactivation / 迁移)
首页
资讯中心
/
Orleans 详解:Grain 激活与生命周期全流程实战指南(Activation / Deactivation / 迁移)
Orleans 详解:Grain 激活与生命周期全流程实战指南(Activation / Deactivation / 迁移)
发布时间:2026/9/25 17:40:45
后端微服务【免费下载链接】orleansCloud Native application framework for .NET项目地址https://gitcode.com/gh_mirrors/or/orleans点击查看免费下载本文聚焦于 Orleans 中 Grain 的按需激活activation与完整生命周期管理从激活创建、状态加载、停用回收到生命周期阶段参与、共享激活装配shared activation setup以及跨 Silo 迁移。结合当前仓库的官方文档与核心源码实现帮助你在实际项目中正确控制 Grain 的生存期、编写可靠的OnActivateAsync/OnDeactivateAsync逻辑并安全地使用迁移等高级能力。核心思想激活是身份的临时实现不是身份本身Orleans 中的 Grain 引用grain reference代表一个稳定的逻辑身份grain identity。激活activation只是该身份在某个 Silo 上临时的、内存中的实现。Orleans 会按需激活 Grain也会回收空闲激活以释放资源而调用方持有的引用在激活变化前后始终有效——这正是 Orleans 分布式编程模型的基础。官方文档对这一点描述得非常直白Orleans activates grains on demand and deactivates idle activations to reclaim resources. Activation is an implementation detail of a grains stable logical identity见 docs/site/src/content/docs/grains/grain-lifecycle.md。配套的实现文档 Activation lifecycle and migration 则给出了运行时视角的完整状态机[*] -- Creating: message needs activation Creating -- Activating: instance and context created Activating -- Valid: OnActivateAsync completes Valid -- Deactivating: collection, failure, migration, or request Deactivating -- Invalid: stop accepting new turns Invalid -- [*]: unregister and dispose Valid -- Migrating: migration selected Migrating -- Deactivating: dehydrate state Deactivating -- Creating: target rehydrates same grain identity激活Activation按需创建与OnActivateAsync当路由找不到有效激活时目标 Silo 的Catalog.GetOrCreateActivation会创建或获取一个ActivationData。从实现文档看创建过程包含多个独立步骤解析 Grain 类型、实现类、共享类型元数据、存储 facet 与激活装配器activation configurators创建 Grain 上下文grain context、每激活的WorkItemGroup与 Grain 实例注册本地激活并按目录策略注册其地址通知IActivationLifecycleObserver.OnCreateActivation在激活调度器上运行生命周期启动与OnActivateAsync将激活标记为有效释放排队的请求进入调度。对应用开发者而言需要在激活流程中挂接初始化逻辑的地方就是OnActivateAsync。Orleans 会通过依赖注入创建 Grain 类、建立其 Grain 上下文、加载已配置的持久化状态然后调用OnActivateAsync。官方示例取自 GrainSnippets.cs展示了带CancellationToken的覆写方式public sealed class DeviceGrain( IDeviceConnectionFactory connectionFactory) : Grain, IDeviceGrain { private IDeviceConnection? _connection; public override async Task OnActivateAsync( CancellationToken cancellationToken) { _connection await connectionFactory.ConnectAsync( this.GetPrimaryKeyString(), cancellationToken); await base.OnActivateAsync(cancellationToken); } }有两个关键约束必须牢记只有带CancellationToken的签名。OnActivateAsync接受一个CancellationToken不存在无参重载。如果激活失败Orleans 不会让该激活对外提供调用服务而是拒绝或重路由请求并拆除不完整的激活见 docs/site/src/content/docs/implementation/activation-lifecycle.md。不要在激活期间做多余的工作。激活可能在回收、迁移、Silo 重启或故障之后被重新创建因此激活逻辑必须可重复、尽量轻量。源码层面OnActivateAsync的默认实现直接返回Task.CompletedTask其语义在 src/Orleans.Core.Abstractions/Core/Grain.cs 中有明确注释该方法在 Grain 激活流程的末尾、任何消息被派发之前调用对声明了持久化状态的 Grain它会在State属性填充之后被调用。停用DeactivationOnDeactivateAsync与DeactivationReasonOrleans 可能在多种场景下停用一个激活激活空闲、Silo 正在关闭、应用主动请求停用、发生迁移或出现错误使激活失效。停用回调的完整签名是public override async Task OnDeactivateAsync( DeactivationReason reason, CancellationToken cancellationToken) { if (_connection is not null) { await _connection.DisposeAsync(); } await base.OnDeactivateAsync(reason, cancellationToken); }停用是尽力而为的best effort。官方文档明确提醒如果进程突然终止或在某些故障场景下OnDeactivateAsync不会执行。因此持久化重要状态应该放在改变它的那次操作本身中完成而不是只依赖停用回调。例如对GrainTGrainState应通过WriteStateAsync在业务方法内写盘而不是等到OnDeactivateAsync。DeactivationReason是一个只读结构体包含ReasonCode、Description和可选的Exception见 src/Orleans.Core.Abstractions/Core/DeactivationReason.cs。DeactivationReasonCode枚举定义于 src/Orleans.Core.Abstractions/Core/IGrainBase.cs给出了各种停用原因可用于日志与诊断原因码含义ShuttingDown进程正在关闭ActivationFailedGrain 激活失败DirectoryFailure分布式目录内部故障如目录分区所在进程失败ActivationIdle激活空闲被回收ActivationUnresponsive激活对命令或请求无响应DuplicateActivation同一 Grain 的另一个实例被激活IncompatibleRequest收到本地进程无法处理的请求ApplicationError应用错误ApplicationRequested应用请求停用对应DeactivateOnIdleMigrating激活正在迁移到新位置RuntimeRequested运行时请求停用HighMemoryPressure运行时检测到低内存并强制停用从运行时的停用流程看见 docs/site/src/content/docs/implementation/activation-lifecycle.md停用首先阻止新的应用 turn 开始再根据原因排空或拒绝待处理工作在激活调度器上执行OnDeactivateAsync与生命周期 stop 回调最后注销目录地址、移除本地激活、释放资源并发布停用事件。主动影响激活生存期DeactivateOnIdle与DelayDeactivationDeactivateOnIdle当前工作完成后停用调用DeactivateOnIdle()可以让 Orleans 在当前请求和排队的后续工作全部完成后停用该 Grain。典型场景是提供一个关闭/结束操作后续对该 Grain 的调用会触发一次全新的激活。public Task Close() { DeactivateOnIdle(); return Task.CompletedTask; }源码中的注释说明了它的语义见 src/Orleans.Core.Abstractions/Core/Grain.cs该方法将当前激活标记为在当前 Grain 方法调用结束后停用并移除下一次对该 Grain 的调用将使用不同的激活通常意味着运行时自动创建新激活。DelayDeactivation延迟回收注意只是提示调用DelayDeactivation(TimeSpan)可以让一个本应空闲的激活在指定时间段内保持可用。这是一个提示不是持久性保证——故障和关闭仍然可能移除该激活。TimeSpan参数的语义见 src/Orleans.Core.Abstractions/Core/Grain.cs正值在该时间跨度内阻止该激活被垃圾回收GCTimeSpan.Zero取消之前DelayDeactivation的设置让激活回归常规的激活垃圾回收策略Timeout.InfiniteTimeSpan无限期延迟停用DeactivateOnIdle会覆盖/撤销当前的保持存活设置使该 Grain 立即可被停用。Grain 定时器默认不会延长激活寿命默认情况下Grain 定时器不会让激活保持存活。只有当定时器活动应当延长激活生命周期时才应设置GrainTimerCreationOptions.KeepAlive。该选项的定义见 src/Orleans.Core.Abstractions/Timers/GrainTimerCreationOptions.csKeepAlive false默认定时器回调不会延长激活寿命如果 Grain 只处理定时器回调而没有其他消息空闲回收期一到就会被回收KeepAlive true定时器回调会延长激活寿命如果定时器周期短于 Grain 的空闲回收期该 Grain 不会因空闲被回收。同文件中的Interleave选项则控制定时器回调是否允许与其它定时器和 Grain 调用交错执行默认false对标记了[Reentrant]的 Grain 始终允许交错。注意旧的RegisterTimer已被标记为[Obsolete]应改用带GrainTimerCreationOptions的RegisterGrainTimer扩展方法。生命周期阶段与参与者Lifecycle stages and participantsGrain 生命周期暴露了有序的阶段常量定义在 src/Orleans.Core.Abstractions/Runtime/GrainLifecycleStage.cs阶段常量数值用途GrainLifecycleStage.Firstint.MinValue最早的订阅点GrainLifecycleStage.SetupState1000状态设置与加载GrainLifecycleStage.Activate2000Grain 激活与停用回调GrainLifecycleStage.Lastint.MaxValue最晚的订阅点关键规则当一个组件的启动依赖另一个组件完成时应使用不同的阶段同一阶段内的回调可以并发执行。需要有序的激活作用域行为的组件可以实现ILifecycleParticipantIGrainLifecycle并通过IGrainContext.ObservableLifecycle订阅。官方示例展示了一个CacheParticipant它订阅SetupState阶段的启动/停止回调public sealed class CacheParticipant : ILifecycleParticipantIGrainLifecycle { public void Participate(IGrainLifecycle lifecycle) { lifecycle.SubscribeCacheParticipant( GrainLifecycleStage.SetupState, OnStart, OnStop); } private Task OnStart(CancellationToken cancellationToken) Task.CompletedTask; private Task OnStop(CancellationToken cancellationToken) Task.CompletedTask; }运行时会对实现了参与者接口的 Grain 对象调用Participate。而服务类非 Grain 对象则必须有一个明确的登记所有者enrollment owner例如 facet factory或下面介绍的共享激活装配机制。GrainTGrainState的源码展示了底层行为其构造函数会通过RuntimeContext.Current!.ObservableLifecycle订阅SetupState阶段的LifecycleObserver见 src/Orleans.Core.Abstractions/Core/Grain.cs该观察者在OnStart中读取持久化状态并实现了IGrainMigrationParticipant以支持迁移时状态随行——这正是持久化状态组件自动参与迁移的实现基础。共享激活装配Shared activation setup对于同一种 Grain 实现类上的多个功能可以使用IConfigureGrainTypeComponents来按类型选择功能并用GrainTypeSharedContext.AddActivationSetup注册可复用的装配动作。官方示例通过应用自有的ICachedGrain标记接口选择目标类public interface ICachedGrain : IGrain; public sealed class CacheSetupConfigurator(GrainClassMap grainClasses) : IConfigureGrainTypeComponents { public void Configure( GrainType grainType, GrainProperties properties, GrainTypeSharedContext shared) { if (grainClasses.TryGetGrainClass(grainType, out Type? grainClass) typeof(ICachedGrain).IsAssignableFrom(grainClass)) { shared.AddActivationSetup(static context { CacheParticipant cache context.ActivationServices .GetRequiredServiceCacheParticipant(); cache.Participate(context.ObservableLifecycle); }); } } }然后将装配器注册为单例、将功能状态注册为作用域服务siloBuilder.ConfigureServices(services { services.AddScopedCacheParticipant(); services.AddSingletonIConfigureGrainTypeComponents, CacheSetupConfigurator(); });这套机制的关键行为官方文档明确列出Orleans 在共享的 Grain 类型上下文中缓存选定的装配动作每个激活在其 Grain 构造函数完成且IGrainContext.GrainInstance被赋值之后按注册顺序运行这些动作所有装配动作完成之后运行时才会调用 Grain 对象的Participate方法并启动生命周期回调每个无状态 workerstateless worker激活会用自己的上下文运行同一套共享装配共享动作只对选中的 Grain解析CacheParticipant。解析发生在激活作用域内因此构造注入与装配共享同一个作用域服务若需要接口注入可注册一个解析该具体服务的别名工厂。普通的具名、键控和参与者接口的 DI 注册仍保留其显式登记行为不同激活的装配动作可以并发运行。因此共享动作必须保持无状态或者保证捕获的共享数据可并发安全访问激活专属状态应放入激活作用域装配动作只能在共享类型配置期间添加应使用同步的装配动作来登记服务与生命周期回调为异步初始化和关闭做准备每个功能只指定一个登记所有者确保订阅只建立一次。装配失败的行为装配异常会使激活失败跳过剩余的装配动作与生命周期启动并触发 Grain 与激活作用域的释放下一次全新的激活会解析全新的作用域状态并重新运行缓存的装配。实现层面参见 Orleans runtime lifecycleIConfigureGrainTypeComponents在创建共享上下文时完成类型选择与组合GrainTypeSharedContext在装配器结束后密封装配注册激活构建时运行时在赋值完整构造的 Grain 对象并记录创建之后按添加顺序执行装配动作随后登记 Grain 对象并启动生命周期。Grain 迁移Migration保活内存状态的跨 Silo 移动迁移migration会将激活移动到另一个 Silo同时保留参与迁移的内存状态。它与持久化存储不同迁移状态在源进程于传输完成前失败时仍然会丢失因此迁移不能替代持久化存储。MigrateOnIdle当前工作完成后请求迁移public Task RequestMigration() { MigrateOnIdle(); return Task.CompletedTask; }该请求是建议性的只有当放置策略placement选中了另一个兼容的 Silo 时才会真正发生迁移。Orleans 会把当前的RequestContext携带到放置决策中见 src/Orleans.Core.Abstractions/Core/Grain.cs 的注释迁移捕获当前RequestContext使其对激活的放置导演placement director可见以便在选择新位置时考虑它。IGrainMigrationParticipant自定义可迁移状态需要随迁移存活的自定义激活状态可以实现IGrainMigrationParticipantpublic sealed class SessionGrain : Grain, ISessionGrain, IGrainMigrationParticipant { private int _sequence; public void OnDehydrate(IDehydrationContext context) { context.TryAddValue(sequence, _sequence); } public void OnRehydrate(IRehydrationContext context) { context.TryGetValue(sequence, out _sequence); } }OnDehydrate在源侧将状态写入迁移上下文脱水OnRehydrate在目标侧读取并恢复状态再水合。由 Orleans 提供的持久化状态组件会自动参与迁移——正如上文所述GrainTGrainState内部的生命周期观察器实现了IGrainMigrationParticipant会把存储状态通过StorageMigratedKey标记随迁移携带见 src/Orleans.Core.Abstractions/Core/Grain.cs。从实现文档的时序可以看出完整迁移流程Activation lifecycle and migrationActivationMigrationManager创建MigrationContext要求注册的迁移参与者脱水状态源激活以Migrating原因停用并注销或转移目录注册目标 Silo 接受迁移请求创建激活并执行再水合OnRehydrate目标注册激活、运行OnActivateAsync直到激活达到稳定状态。迁移状态不等同于持久化的 Grain 状态IGrainMigrationParticipant面向的是必须随实况移动的运行时或应用组件内存状态参与者写入的迁移上下文数据应是可版本化的并且必须容忍在另一个 Silo 上被再水合。ImmovableAttribute排除自动迁移使用ImmovableAttribute可以将某类 Grain 排除在自动迁移之外例如自动激活再分区 / 再平衡。需要注意的是它不会阻止显式的MigrateOnIdle请求。自动激活重分区repartitioning与重平衡rebalancing都使用迁移来改善本地性或集群平衡且两者均为实验性功能需在 Grain placement 中查看其状态与配置。实现文档也强调迁移是一种机制而非策略——显式迁移 API 可以请求移动而实验性的激活重平衡器与重分区器是两种选择性启用opt-in的集群级策略。常见问题与最佳实践小结综合官方文档与源码实践中有几条值得固化的经验激活会随时重建。不要假设激活是长命的把初始化做轻把清理做对。持久化必须发生在业务操作中而非只依赖OnDeactivateAsync。停用是尽力而为。进程崩溃可以绕过一切停用回调正确性不能建立在OnDeactivateAsync总会执行的前提上。定时器默认不保活。需要靠定时器维持激活时显式设置GrainTimerCreationOptions.KeepAlive true并注意其周期应短于空闲回收期。生命周期阶段用于表达依赖顺序。同一阶段内回调并发跨阶段才有先后保证。共享装配适合一次配置、多激活复用但共享动作必须无状态或并发安全激活专属状态放进激活作用域。迁移是有损的移动不是备份关键数据始终要落盘。进一步阅读Grain lifecycle 官方文档本文的核心来源Activation lifecycle and migration运行时实现激活创建、回收、停用与迁移的协议细节Orleans runtime lifecycle生命周期协议Silo 与 Grain 生命周期共同的阶段遍历机制Grain placement放置策略、ImmovableAttribute与实验性自动迁移服务核心源码OnActivateAsync/OnDeactivateAsync/DeactivateOnIdle/DelayDeactivation/MigrateOnIdle定义于 src/Orleans.Core.Abstractions/Core/Grain.csGrainLifecycleStage定义于 src/Orleans.Core.Abstractions/Runtime/GrainLifecycleStage.csDeactivationReasonCode定义于 src/Orleans.Core.Abstractions/Core/IGrainBase.cs全部示例代码见 docs/site/src/content/docs/snippets/compiled/Grains/GrainSnippets.cs 中的activate_grain、deactivate_grain、deactivate_on_idle、lifecycle_participant、activation_setup、activation_setup_registration、migrate_on_idle、migration_participant等代码片段赞分享后端微服务【免费下载链接】orleansCloud Native application framework for .NET项目地址https://gitcode.com/gh_mirrors/or/orleans点击查看免费下载相关推荐Orleans Grain 定时器Grain Timers完全指南激活级周期性任务调度Orleans Grain 定时器Grain Timers完全指南激活级周期性任务调度 导读 本文基于 Orleans 官方文档 grains/timer后端微服务Orleans 激活生命周期与迁移全解从 ActivationData 状态机到跨 Silo 热迁移的实现与调优Orleans 激活生命周期与迁移全解从 ActivationData 状态机到跨 Silo 热迁移的实现与调优 导读 在 Orleans 分布式应用中G后端微服务Orleans Grain Extensions 完全指南为 Grain 激活附加运行时接口Orleans Grain Extensions 完全指南为 Grain 激活附加运行时接口 导读 本文深入讲解 Orleans 框架中的 Grain ext后端微服务上一篇基于噪声信道Noisy Channel模型的重排序实战unilm/InfoXLM 中 fairseq 神经机器翻译重排序脚本全解析下一篇ParlAI Humpback基于 Instruction Backtranslation 的 LLM 自对齐实战解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考