引言-WHY
-
一致性的定义
在数据有多分副本的情况下,如果网络、服务器或者软件出现故障,会导致部分副本写入成功,部分副本写入失败。这就造成各个副本之间的数据不一致,数据内容冲突。
这里有几个关键词
- 分布式环境
- 多副本
-
数据不一致的场景
- 网络
graph TD
A(应用程序)-->|读写|B(master)
B-.-|网络异常,数据同步失败|C(slave)
A-->|读|C
subgraph 数据库集群
B
C
end
网络问题导致master和slave的两个副本的数据不一致。
- 硬件故障
还是拿mysql作为例子。
mysql的架构大致如下(做过大量简化,事实上mysql的实现会复杂很多):
graph TB
subgraph 存储引擎
subgraph 后台线程
A(Master Thread)
B(IO Thread)
C(Purge Thread)
D(Page Cleaner Thread)
end
E(buffer Pool)
end
G(clent)-->E
E-->A
A-->|check point|F(硬盘)
如果在写入buffer pool成功后,机器断电或者硬盘故障,buffer pool的数据将和硬盘的数据不一致。(事实上mysql的redo log机制可以尽力补偿这部分数据)
- 程序
我们拿直播业务的公会分成的一个业务架构举例
graph LR
A((用户))-->|1.送礼|B(送礼服务)
B-->|2.扣费|C(消费服务)
C-->|3.通知|D(星豆分成模块)
D-->|4.增加主播星豆|C
D-->|5.通知|E(公会分成模块)
由于公会分成的模块不支持幂等,因此在步骤5通知公会分成失败无法通过重试来保证数据的一致性。因此公会分成和主播的分成有可能会不一致。
- 为什么我们需要一致性
酷七条-数据一定不能错
业务属性:营收业务
拿去年419的截图。火箭漫天飞。对公司造成重大损失。
- 弱一致性业务。
- 强一致性业务。
一致性问题是如何产生的
单点是不存在一致性问题的。
graph LR
client((clent))
subgraph cluster
A((node A,value=8))
B((node B))
C((node C))
end
client-->|set 8|A
client设置了一个值8到node A,如何让副本node B和node C都保持一致。
讲讲经典的CAP理论(去网上偷一张图)。
一致性协议对比 |名称 | 描述 | CAP选型 | 开源软件 | |- | - | - | - | |主从同步 | 数据库的主从同步 | C | mysql | |2PC | 两段提交 | * | fescar、mysql的group commit | |paxos | quorum 协议 | CP | ocean base | |raft | quorum 协议。paxos的工业实现版本,比paxos更易于理解和实现。增加了节点uncommit的状态 | CP | consul | |zab | zookeeper的一致性实现算法。 | CP | zookeeper |
mysql的主从同步-CA
脑裂问题(重点)
CAP定律
一致性协议&开源工具[重点]
MHA架构,可以顺便介绍下半同步
graph TD
R((user request))
subgraph regionA
M(master)
S1(slave1)
end
subgraph regionB
S2(slave2)
S3(slave3)
end
C(consul cluster)
R-->|w/r|M
R-->|r|S1
M-->|binlog sync|S1
M-->|binlog sync|S2
M-->|binlog sync|S3
金钱模块的一致性架构
有没有更好的方案?代理、SDK层面解决
留一道思考题?如果出现的网络场景不是不可用,而是失败率很高,应该如何解决?
仲裁节点和MHA
mha config使用consul实现,保证数据的强一致。MHA SDK在网络分区的场景下通知业务,由业务决定具体的降级方案
交由给代理层/rpc中间件解决