[RFC] 将 Orleans 与 Event Sourcing 持久化后端从 Garnet 切换为 MongoDB #3457
jason-aelf
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
背景
目前 Aevatar 的部分 Orleans runtime state 和 Event Sourcing state 由 Garnet / Redis-compatible provider 承载。本讨论评估是否将这些非缓存持久化状态切换为 MongoDB,并明确开源 provider 的覆盖范围、当前实施阻塞项以及测试环境的切换边界。
当前 Garnet 中的数据全部属于测试数据,可以整体丢弃。本讨论不设计生产数据迁移,也不建议为这些测试数据建设 export/import、双写、回填或兼容读取能力。
TL;DR
RPO=0:客户端已经收到成功响应的写入仍可能位于尚未复制的 AOF tail 中。Orleans.Providers.MongoDB可以覆盖 named grain storage、reminders 和 clustering,但当前 Orleans 10 兼容性与 Protobuf serialization 尚未验证。IEventStore没有可直接替换的 MongoDB 开源实现,需要实现 MongoDB adapter 并通过与现有 Garnet 实现共享的 contract tests。为什么考虑替换 Garnet
Garnet Cluster 的数据丢失窗口
Garnet Cluster 的 sharding 与 replication 解决的是不同问题:sharding 只分布 key space,不会自动为每个 shard 提供冗余;每个 primary 仍需要单独配置 replica。
replica 通过异步复制跟随 primary 的 AOF offset,因此存在两类确认窗口:
WaitForCommit时,primary 返回成功不代表写入已经完成本地 AOF commit。WaitForCommit,它也只等待 primary 本地 AOF commit,不等待 replica 确认。Garnet 当前不支持 Redis
WAIT和WAITAOF,应用无法通过标准命令要求 replica 或多个 AOF 实例确认后再把写入视为成功。因此 primary 突然不可恢复时,已确认但尚未复制的 AOF tail 可能丢失,promotion 后的 replica 会表现为状态或版本水位回退。故障转移能力边界
Garnet Cluster 是 passive cluster。Garnet 节点维护 slot、primary-replica 和 replication 状态,但完整的故障检测、选主、promotion、fencing 与客户端 topology convergence 需要由 Kubernetes operator 或其他外部 control plane 负责。
当原 primary 仍可访问时,普通
CLUSTER FAILOVER可以暂停写入并等待 replica offset 追平后再 promotion,从而降低计划切换的数据丢失风险。但 primary 突然故障或使用CLUSTER FAILOVER FORCE时,无法保证复制尾部已经追平。因此 Garnet Cluster 可以提供分片、副本和故障恢复基础,但不能单独承诺“客户端确认成功的写入绝不丢失”。这与 committed domain events、actor state 等业务权威持久态的目标存在差距。
MongoDB 本身也不自动等于零数据丢失。未来生产部署仍必须明确 replica set、journaling、write concern、read concern、transaction、故障转移以及备份恢复策略。
哪些状态需要切换
UseMongoDBReminders(...);需要验证 Orleans 10、多 silo ownership、重启与注销行为PubSubStoreUseMongoDBClustering(...);生产环境要求 MongoDB replica set 与 transaction 支持GarnetEventStoreIEventStoreadapter这些状态在生产语义上都不能当作普通缓存。但当前 Garnet 数据只是测试数据,所以“状态很重要”与“本次必须保留旧数据”是两个不同问题。
建议的测试环境切换边界
建议将六类状态作为同一个测试环境重置边界处理:
PubSubStore、membership 和 event stream;不能保留旧 grain snapshot 却清空 event stream,也不能保留 callback state 却清空 reminder registration。即使旧数据没有保留价值,这类混合状态仍会制造版本、恢复和调度不一致。
如果未来出现必须保留的生产数据,应另行编写生产切换 ADR 和数据迁移方案,不应为当前测试数据提前建设迁移基础设施。
开源支持与实施阻塞项
仓库当前使用 Microsoft Orleans
10.0.1,中央包版本声明了Orleans.Providers.MongoDB9.5.0,但尚未实际引用。当前已知边界如下:9.5.0依赖 Orleans9.0.1相关包;上游 Orleans 10 WIP PR #158 已关闭且未合并。PubSubStore可以由 Mongo named grain storage 承载,但现有 Redis-specific cleanup/maintenance 逻辑必须替换。Orleans.Providers.MongoDB不实现 AevatarIEventStore;MongoDB adapter 必须保持 optimistic concurrency、atomic batch append、ordered read、Protobuf payload、corruption detection 和 compaction contract。采用 MongoDB 前需要验证
10.0.1下 provider 可以编译、启动并通过 multi-silo integration tests。PubSubStore可以从空 store 完成 producer/subscriber registration,并具备新的 maintenance 实现。IEventStoreadapter 通过与 Garnet 实现共享的 contract tests。本次希望确认的问题
Orleans.Providers.MongoDB,应优先完成 Orleans 10 兼容性验证,还是直接维护仓库内可控的适配/fork?IEventStoreadapter 作为独立实现,并要求它与GarnetEventStore共享同一组 contract tests?范围外
IRuntimeSecretStore、tool admission ledger、identity assertion replay guard 和 workflow webhook replay admission 不属于本讨论范围。这些 secret 或 TTL admission/replay state 需要按各自的一致性、过期和故障转移要求单独评估。参考资料
All reactions