配置 Orleans PubSub 存储:让流订阅元数据在集群重启后依然存活
配置 Orleans PubSub 存储让流订阅元数据在集群重启后依然存活【免费下载链接】orleansCloud Native application framework for .NET项目地址: https://gitcode.com/gh_mirrors/or/orleansOrleans 流Stream通过 pub/sub 汇合点rendezvous连接生产者和消费者而名为PubSubStore的 grain 存储提供程序负责持久化显式订阅元数据。本文基于官方文档 pubsub-storage.md 展开讲解PubSubStore的持久化取舍、Azure Table Storage 生产级配置以及订阅生命周期管理并结合仓库源码说明其内部实现原理帮助你在开发与生产环境中做出正确的配置决策。理解 PubSubStore 在 Orleans 流架构中的角色Orleans 的流系统是一个虚拟流virtual stream实现生产者向逻辑流 ID 发送事件消费者订阅该流 ID两者互不知道对方的存在。连接它们的正是发布/订阅汇合点pub/sub rendezvous——它维护着哪个流被谁订阅了的映射关系。在默认配置下这个汇合点由 grain 承载因此需要把订阅元数据持久化到某个 grain 存储提供程序中这个提供程序被命名为PubSubStore。该名称在源码中被定义为一个常量任何需要默认 pub/sub 存储的组件都会引用它// src/Orleans.Core.Abstractions/Providers/ProviderConstants.cs public const string DEFAULT_PUBSUB_PROVIDER_NAME PubSubStore;从源码结构看PubSubStore是 Orleans 流系统中的约定俗成的存储槽位流订阅管理器StreamSubscriptionManagerAdmin.cs在构造时请求ExplicitGrainBasedAndImplicit类型的 pub/sub 运行时该运行时内部的订阅记录 grain 使用PubSubStore作为其持久化状态流检查点 grainStreamCheckpointGrain.cs通过[PersistentState(StateName, ProviderConstants.DEFAULT_PUBSUB_PROVIDER_NAME)]直接绑定到PubSubStore用于持久化持久流persistent stream队列的消费位置grain 检查点器GrainStreamQueueCheckpointer.cs默认使用PubSubStore作为检查点存储。也就是说只要你使用持久流提供程序如 Azure Event Hubs、Azure Queue、Kinesis、SQS并启用 grain 检查点UseGrainCheckpointerPubSubStore就承担着订阅元数据 队列消费位置双重持久化职责。即使你只使用AddMemoryStreams流提供程序在默认情况下也期望存在一个名为PubSubStore的存储提供程序。三种持久化形态的取舍形态配置方式持久性适用场景内存存储AddMemoryGrainStorage(PubSubStore)集群内存状态丢失即订阅记录丢失开发、单元测试、演示持久存储AddAzureTableGrainStorage(PubSubStore, ...)等跨 silo 重启、集群重启存活生产环境隐式订阅[ImplicitStreamSubscription]特性由 grain 元数据派生不产生订阅记录订阅与流 ID 存在确定映射关系时其中隐式订阅值得特别说明它不经过显式订阅记录而是从 grain 的元数据[ImplicitStreamSubscription(namespace)]中推导出该 grain 订阅了哪个流因此不写入PubSubStore也不受存储持久性影响。仓库中的示例 ImplicitSubscriptions.cs 展示了典型写法[ImplicitStreamSubscription(TemperatureStreams.Namespace)] public sealed class DeviceTelemetryGrain : Grain, IDeviceTelemetryGrain, IAsyncObserverTemperatureReading, IStreamSubscriptionObserver { public Task OnSubscribed(IStreamSubscriptionHandleFactory handleFactory) { var handle handleFactory.CreateTemperatureReading(); return handle.ResumeAsync(this); } // ... }开发环境用内存存储快速起步在开发与测试阶段使用内存存储是官方推荐的方式。仓库中的流配置示例 Configuration.cs 给出了完整的 silo 配置// memory_silo 片段 builder.UseOrleans(siloBuilder { siloBuilder .AddMemoryStreams(TemperatureStreams.ProviderName) .AddMemoryGrainStorage(PubSubStore); });对应的客户端侧同样只需要添加流提供程序客户端本身不直接使用PubSubStore// memory_client 片段 builder.UseOrleansClient(clientBuilder { clientBuilder.AddMemoryStreams(TemperatureStreams.ProviderName); });需要注意内存存储的订阅记录在集群状态丢失时会一并消失。如果 silo 全部重启且没有其他持久化副本之前创建的显式订阅会丢失消费者需要重新执行订阅逻辑。生产环境以 Azure Table Storage 持久化 PubSubStore对于生产环境官方文档推荐使用 Azure Table Storage 作为PubSubStore的持久化后端并优先使用托管标识managed identity而非连接字符串。方式一托管标识推荐// pubsub_managed_identity 片段 var endpoint new Uri(configuration[AZURE_TABLE_STORAGE_ENDPOINT]!); var credential new DefaultAzureCredential(); hostBuilder.UseOrleans(siloBuilder { siloBuilder.AddAzureTableGrainStorage( PubSubStore, options options.TableServiceClient new TableServiceClient(endpoint, credential)); });托管标识方式通过DefaultAzureCredential依次尝试环境凭据、托管标识、Azure CLI 等多种认证链避免了在配置文件中硬编码密钥适合部署在 Azure 容器应用、AKS、VM 等支持托管标识的环境中。AZURE_TABLE_STORAGE_ENDPOINT指向 Table 服务的终结点形如https://account.table.core.windows.net/。方式二连接字符串// pubsub_connection_string 片段 hostBuilder.UseOrleans(siloBuilder { siloBuilder.AddAzureTableGrainStorage( PubSubStore, options options.TableServiceClient new TableServiceClient(connectionString)); });连接字符串方式适合本地开发、测试以及无法使用托管标识的受限环境。同样的配置模式也适用于其他持久化后端例如AddDynamoDBGrainStorageOrleans.Clustering.DynamoDB、AddAdoNetGrainStorageOrleans.Persistence.AdoNet或AddCosmosGrainStorageOrleans.Persistence.Cosmos只需将存储提供程序名称指定为PubSubStore即可。集群身份与存储的对应关系官方文档强调了一条关键原则使用稳定的 Orleans service ID并在集群重启之间保持相同的持久化配置。服务 IDservice ID是 Orleans 集群的逻辑标识。pub/sub 订阅记录的存储键派生自服务 ID因此修改 service ID → 从 pub/sub 系统的角度看订阅注册表变成逻辑上全新的旧订阅记录不再被新集群识别删除或重建底层表 → 订阅记录全部丢失相当于新建注册表存储配置不一致 → 不同 silo 可能读写不同的表导致订阅状态不一致。生产环境中应把 service ID 视为需要刻意维护、保持不变的部署标识。订阅生命周期激活、恢复与移除持久化PubSubStore只保证订阅记录谁订阅了哪个流得以保存但它不保存消费者的 observer 实例。文档明确指出即使使用持久化的PubSubStore显式消费者在激活后也必须调用StreamSubscriptionHandleT.ResumeAsync()将当前 observer 实例挂接到订阅句柄上。同样持久化的事件存储durable event storage也不会让订阅记录自动变得持久——事件存储与订阅元数据是两个独立层次需要根据恢复需求分别配置。仓库中的显式订阅示例 ExplicitSubscriptions.cs 完整展示了这一生命周期管理是可直接套用的实战模板public override async Task OnActivateAsync(CancellationToken cancellationToken) { _stream TemperatureStreams.Get(this, this.GetPrimaryKeyString()); var handles await _stream.GetAllSubscriptionHandles(); foreach (var handle in handles) { await handle.ResumeAsync(this); } } public async Task SubscribeAsync() { var handles await _stream.GetAllSubscriptionHandles(); if (handles.Count 0) { await _stream.SubscribeAsync(this); } } public async Task UnsubscribeAsync() { var handles await _stream.GetAllSubscriptionHandles(); foreach (var handle in handles) { await handle.UnsubscribeAsync(); } }这段代码体现了显式订阅的三个核心操作SubscribeAsync首次订阅时创建订阅记录并持久化到PubSubStore。代码先检查GetAllSubscriptionHandles()是否已有句柄避免重复创建订阅ResumeAsyncgrain 激活OnActivateAsync时从存储中取回所有订阅句柄并重新挂接当前实例实现grain 重启后恢复订阅UnsubscribeAsync不再需要时移除订阅。文档建议在订阅不再被需要时主动调用它防止PubSubStore中堆积无用的订阅记录。运维指南备份、命名与替换官方文档给出四条直接可执行的运维建议像备份其他应用元数据一样备份并监控PubSubStore。订阅记录属于业务元数据丢失后显式订阅需要逐个重建保持提供程序名称稳定。从 pub/sub 系统的视角看提供程序名称是流身份stream identity的一部分重命名提供程序等于改变了流身份会导致既有订阅失效及时清理订阅。通过StreamSubscriptionHandleT.UnsubscribeAsync()移除不再需要的订阅控制存储增长与系统开销替换PubSubStore前先规划好显式订阅的重建方案。无论是更换存储后端还是迁移到新集群都要预先设计如何重新创建既有显式订阅例如在 grain 激活逻辑中通过SubscribeAsync幂等重建。底层原理从源码看 PubSub 汇合点的运作为了更稳妥地配置PubSubStore有必要理解它在 Orleans 流实现中的位置。流提供程序的 pub/sub 类型由StreamPubSubOptions控制其默认值是ExplicitGrainBasedAndImplicit显式基于 grain 隐式// src/Orleans.Streaming/PersistentStreams/Options/PersistentStreamProviderOptions.cs public class StreamPubSubOptions { public StreamPubSubType PubSubType { get; set; } DEFAULT_STREAM_PUBSUB_TYPE; public const StreamPubSubType DEFAULT_STREAM_PUBSUB_TYPE StreamPubSubType.ExplicitGrainBasedAndImplicit; }该配置通过ConfigureStreamPubSub扩展方法应用到持久流提供程序上ClusterClientPersistentStreamConfigurator.cs。基于 grain 的显式订阅意味着每个流 ID 对应一个订阅管理器 grain其状态持久化在PubSubStore中——这正是本文配置项存在的原因。此外使用持久流提供程序如 Event Hubs、Kinesis、Azure Queue时队列消费位置checkpoint也是关键状态。若启用UseGrainCheckpointer检查点会默认存入PubSubStore见 PersistentStreamConfiguratorExtension.cs 的UseGrainCheckpointer及其对GrainStreamQueueCheckpointerOptions.StorageProviderName默认值为PubSubStore的说明见 GrainStreamQueueCheckpointerOptions.cs。因此在规划持久化时要同时覆盖订阅元数据与检查点数据两个层面。总结一套配置决策清单决策点建议开发/测试环境AddMemoryGrainStorage(PubSubStore)接受重启即丢失生产环境持久化后端 稳定 service ID 保持配置一致优先托管标识订阅恢复grain 激活时调用ResumeAsync重新挂接 observer订阅清理不再需要时调用UnsubscribeAsync存储替换提前规划显式订阅的重建视同元数据迁移PubSubStore虽小却是 Orleans 流系统可靠性的基石之一。理解它的持久化边界、正确配置存储后端并配合完整的订阅生命周期管理才能在集群重启、滚动升级等场景下保持流的投递连续性。若要深入理解流系统内部的汇合点与 pulling agent 设计可继续阅读 Orleans streams implementation。【免费下载链接】orleansCloud Native application framework for .NET项目地址: https://gitcode.com/gh_mirrors/or/orleans创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Akka Classic Cluster Metrics 扩展实战指南:集群指标采集、自适应负载均衡与 Sigar 配置

Akka Classic Cluster Metrics 扩展实战指南:集群指标采集、自适应负载均衡与 Sigar 配置

后端并发编程异步编程 【免费下载链接】akka-core A platform to build and run apps that are elastic, agile, and resilient. SDK, libraries, and hosted environments. 项目地址: https://gitcode.com/gh_mirrors/ak/akka-core 点击查看 免费下载 导读 本文基…

2026/9/24 21:41:37 阅读更多 →
Windows上OpenClaw安装、配置与彻底卸载实战指南

Windows上OpenClaw安装、配置与彻底卸载实战指南

1. 写在前面:为什么我建议你在Windows上折腾OpenClawOpenClaw这个项目,最近在AI自动化和个人助理圈子里热度一直没降过。简单说,它是一个开源的个人AI助理框架,能够把大模型接到微信、飞书、Telegram、Discord这些聊天渠道里&…

2026/9/24 21:40:36 阅读更多 →
含间隙铰关节机构动力学建模与MATLAB/ADAMS联合仿真解析

含间隙铰关节机构动力学建模与MATLAB/ADAMS联合仿真解析

说实话,做机构动力学这些年,最让我头疼的不是刚体动力学那套套路,而是“理想运动副”和“真实运动副”之间的那道鸿沟。教科书里转动副就是5个约束方程,轴上插个销子就完事。可实际装配完你会发现,你说它有约束&#x…

2026/9/24 21:40:36 阅读更多 →

最新新闻

钢筋计数数据集解析:VOC标注转YOLO格式与训练实践

钢筋计数数据集解析:VOC标注转YOLO格式与训练实践

简介:面向钢筋计数算法开发与计算机视觉目标检测实践,这份资源提供VOC格式的训练集标注文件,适用于钢筋盘点、工地物料统计等场景,帮助研究者省去从零采集和标注图像的繁琐过程。压缩包内共568个XML文件,每个XML对应一…

2026/9/24 23:17:10 阅读更多 →
5 分钟装好 Everywhere:Windows 安装到快捷键唤起 AI 助手

5 分钟装好 Everywhere:Windows 安装到快捷键唤起 AI 助手

5 分钟装好 Everywhere:Windows 安装到快捷键唤起 AI 助手 【免费下载链接】Everywhere On-screen aware AI assistant for your desktop. Uses current app context, multiple LLMs, and MCP tools to help you act across apps. 项目地址: https://gitcode.com/…

2026/9/24 23:17:10 阅读更多 →
一个人啃下12种工控协议:从Modbus到OPC UA的实战避坑指南

一个人啃下12种工控协议:从Modbus到OPC UA的实战避坑指南

1. 一个人啃下12种工控协议,到底难在哪先说说我自己的情况。我不是自动化科班出身,大学学的是计算机,毕业后在一家小公司做上位机开发。第一次接触工控协议是2019年,客户拿着一台西门子S7-1200过来说“你把这个PLC的数据读到我的系…

2026/9/24 23:17:10 阅读更多 →
Java生态构建RAG知识库实战:LangChain4j+LangGraph4j全流程解析

Java生态构建RAG知识库实战:LangChain4j+LangGraph4j全流程解析

前阵子帮一个全Java技术栈的团队搭企业内部知识库问答系统,方案评审时对方给了个硬约束:不引入Python服务,不新增运维组件,所有代码必须能在现有Java工程里跑起来。我翻遍了GitHub上热门的RAG参考项目,几乎清一色Pytho…

2026/9/24 23:17:09 阅读更多 →
Windows PCIe DMA驱动开发实战:PLX芯片WDM驱动源码解析与避坑指南

Windows PCIe DMA驱动开发实战:PLX芯片WDM驱动源码解析与避坑指南

简介:这份资源是面向Windows内核驱动开发者的PCIe DMA驱动参考实现,重点解决PCIe设备在Windows下进行DMA传输、内存分配与中断响应等核心问题,适合具备一定驱动基础、希望深入理解KMDF/WDM框架与硬件交互的中高级开发者。压缩包共24个文件&am…

2026/9/24 23:17:09 阅读更多 →
C#消消乐实战:从数据结构到GDI+双缓冲的完整实现解析

C#消消乐实战:从数据结构到GDI+双缓冲的完整实现解析

简介:这是一份基于C#语言开发的开心消消乐游戏完整源码,面向具备初步C#语法知识、想通过具体项目掌握WinForms窗体应用或消除类游戏设计的学习者,也可用于课程设计、毕业设计或兴趣开发。项目围绕用户消除图案并达成目标的玩法展开&#xff0…

2026/9/24 23:16:08 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →