知识卡片
用冷备而非双写解决session一致性
内容
[[360消息系统的六大组件架构]]中Register Service承担着全局session存储的职责,一个自然的问题是:如何保证Room Server和Register Server之间连接状态的一致性与可用性?团队早期考虑过双写方案,但最终放弃了,转而选择用冷备来解决——原因是实时状态的双写同步代价太高,而且容易产生脏数据(两份状态各自独立写入、一旦出现写入时序错乱或网络分区,两边数据就可能对不上)。冷备的具体做法是:如果Register挂了,就调用所有Room实例,让它们把各自持有的用户连接状态重新刷入指定的(新)Register,以此重建session数据——这是一种”故障发生后再补救”而非”时刻保持两份数据实时同步”的思路。这个取舍背后的逻辑是:session信息本质上可以从”当前持有连接的Room实例”这一权威数据源重新推导出来(每个Room都确切知道自己hold住了哪些用户连接),所以Register这份数据某种程度上是可以被”重建”而非必须被”实时复制”的派生数据;既然可以重建,就没有必要为了防止Register故障而承担双写的实时同步代价和脏数据风险,只需要在真正发生故障时,付出一次性的全量重刷代价即可。这条设计思路可以泛化成一条更一般的判断标准:当某个组件持有的数据能够从另一个更权威、更分布式的数据源重新推导出来时,优先选择”故障后按需重建”而不是”平时就实时双写同步”,往往能用更低的日常复杂度换取同样可接受的故障恢复能力,只是要接受重建过程中存在的一段短暂空窗期。
参考来源
- 位置:《高可用架构(第1卷)》第1章《高可用架构案例精选》"1.4 如何实现支持数亿用户的长连消息系统:Golang高并发案例"节,"1.4.6 疑问与解惑"(源文件:_epub-src/OEBPS/Text/Chapter1_4_7.xhtml)
- 结论依据:原文说明"一致性是通过冷备解决的,早期考虑双写,但实时状态双写同步代价太高,而且容易有脏数据,比如register挂了,调用所有room,通过重新刷入指定register来解决",直接支撑本卡片结论。
- 原始内容:一致性是通过冷备解决的,早期考虑双写,但实时状态双写同步代价太高,而且容易有脏数据,比如register挂了,调用所有room,通过重新刷入指定register来解决。