关于数据同步一致性问题的思考
Apr 1, 2011
存在的问题
按照目前公司产品中数据同步采用的发布订阅的规则,假设以下的场景:
- 在 A 系统中将某条学生记录 stu_0 做了修改:stu_0 -> stu_A1,并将修改后的记录发送到了 MQ 中。
- 在 B 系统接收到 MQ 中的 A1 之前,B 系统也将学生记录 stu_0 做了修改:修改为 stu_B1 并发送到了 MQ 中。
- 现在在 MQ 中有两条记录需要同步,按 FIFO 顺序为 stu_A1、stu_B1。
- A 系统接收到 stu_B1,做了修改:stu_A1 -> stu_B1。
- B 系统接收到 stu_A1,做了修改:stu_B1 -> stu_A1。
- C 系统接收到 stu_A1、stu_B1,做了修改:stu_0 -> stu_A1 -> stu_B1。
|
|
最终,B 和 A、C 中的同一条记录内容并不相同,A、B、C 三个系统的数据出现了不一致的情况。
解决方案的思考
发起修改操作的系统订阅自身发送的数据
如果 A、B、C 系统都能够按照 MQ 中的数据的顺序去修改记录,那么该条记录最终在各个系统中都将是 stu_B1,即可以实现最终一致性。
这要求 A、B、C 系统都必须订阅 MQ 中的数据,包括自身系统发送到 MQ 中的数据。
优点:可以实现数据的最终一致性。
缺点:
- 在 RabbitMQ 中是否可以实现这样的配置?
- 对于发起修改操作的系统来说,会重复执行一次更新操作。
对每条记录引入一个在各个系统中唯一的版本号
以上述场景为例,我们给学生记录添加一个全局的版本号,假设初始数据为 stu_0,数据同步流程如下:
- 先在 A 系统中修改数据:stu_0 -> stu_1
- 后在 B 系统中修改数据:stu_0 -> stu_2
- B 系统接收到 A 系统修改后的数据,和当前记录进行版本比对,发现 stu_2 > stu_1,所以丢弃该数据的修改。
- A 系统接收到 B 系统修改后的数据,和当前记录进行版本比对,发现 stu_1 < stu_2,对数据做了修改:stu_1 -> stu_2
- C 系统依次接收到 A、B 系统修改后的数据,对数据做了修改:
- 第一次版本比对发现 stu_0 < stu_1,对数据做了修改:stu_0 -> stu_1
- 第二次版本比对发现 stu_1 < stu_2,对数据做了修改:stu_1 -> stu_2
优点:在数据在各个系统同步时,可以避免一些过期数据的更新操作。
缺点:必须添加版本字段,并且要管理全局版本号,系统的复杂度和开发、测试工作量都会增加。
最终三个系统中该条记录均为 stu_2,保持了数据的最终一致性。