- 系统拆分
- 缓存
- MQ
- 分库分表
- 读写分离
- ElasticSearch
分布式锁
- 使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高?
redis 分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能。
zk 分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小。
RedLock 算法
CAP 原则
CAP 定理(CAP theorem),又被称作布鲁尔定理(Brewer’s theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
- 一致性(Consistency) (等同于所有节点访问同一份最新的数据副本)
- 可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据)
- 分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择。)
事实上,任何系统只可同时满足其中两个,无法三者兼顾,即所有分布式系统只能满足 CP 或者 AP
BASE 理论
BASE 是 Basically Available (基本可用)、Soft-state (软状态)和 Eventually Consistent (最终一致性) 的缩写,是对 CAP 原则的一致性和可用性进行权衡之后得到的结果。
其核心思想是即使系统无法做到强一致性,但应用可以采用适当的方式使系统达到最终一致性。
Basically Available (基本可用) 即表示系统在出现故障时候,还能够提供部分服务。
Soft-state (软状态) 与硬状态相反,表示系统不同节点之间的数据存在中间状态,可能存在一定的延时,但不影响系统的整体可用性。
Eventually Consistent (最终一致性) 描述系统之间的数据副本,经过一段时间的同步之后,最终达到一个一致的状态。
分布式事物一致性
分布式事务一致性解决方案分为两种类型:
- 强一致性
即事务的操作是同步进行,包括:两阶段提交协议、三阶段提交协议。
- 最终一致性
包括 TCC 模式、补偿模式、可靠事件模式
- 分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?
XA协议:XA 协议是由 X/Open 组织提出的分布式事务处理规范,主要定义了事务管理器 TM 和局部资源管理器 RM 之间的接口。目前主流的数据库,比如 oracle、DB2 都是支持 XA 协议的。
两阶段提交协议
当一个事务跨越多个节点时,需要引入一个协调者去控制每个节点的操作结果。即事务管理者(协调者)负责控制所有资源管理者(参与者)准备流程和提交流程。
第一阶段:协调者向参与者发起准备命令,询问参与者是否预提交成功(执行操作,但不提交)。
第二阶段:协调者根据参与者的响应结果,发起提交命令或者回滚命令(有参与者没有准备好或者执行失败)。
缺点:
同步阻塞:参与者需要听从协调者的调度,在此期间处于阻塞状态;
单点故障:协调者若发生故障,参与者将一直等待;
数据不一致:协调者向参与者发送 commit 请求时发生故障,导致一部分参与者执行了 commit 请求。
三阶段提交协议
在两阶段提交基础上,引入超时机制解决同步阻塞问题
并加入预备阶段,尽早发现有问题的参与者,只有预备节点完成,才会执行后续的准备和提交阶段。
缺点:
数据不一致:参与者无法及时收到协调者请求时,会默认 commit。
TCC 方案
TCC 的全称是: Try 、 Confirm 、 Cancel 。
Try 阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行锁定或者预留。
Confirm 阶段:这个阶段说的是在各个服务中执行实际的操作。
Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,就是执行已经执行成功的业务逻辑的回滚操作。(把那些执行成功的回滚)
这种方案说实话几乎很少人使用,我们用的也比较少,但是也有使用的场景。因为这个事务回滚实际上是严重依赖于你自己写代码来回滚和补偿了,会造成补偿代码巨大,非常之恶心。
SAGA 方案
业务流程中每个参与者都提交本地事务,若某一个参与者失败,则补偿前面已经成功的参与者。下图左侧是正常的事务流程,当执行到 T3 时发生了错误,则开始执行右边的事务补偿流程,反向执行 T3、T2、T1 的补偿服务 C3、C2、C1,将 T3、T2、T1 已经修改的数据补偿掉。
并不需要这么强的一致性,只需要保证最终一致性即可
适用场景是:
- 业务流程长、业务流程多;
- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口。
优势
- 一阶段提交本地事务,无锁,高性能;
- 参与者可异步执行,高吞吐;
- 补偿服务易于实现,因为一个更新操作的反向操作是比较容易理解的。
缺点
- 主业务向从服务发起业务调用,先记录 待发送 状态至数据库中,并向消息队列投递消息;
- 主业务根据消息队列的响应结果成功与否进行判断,响应成功将消息改为 已发送 状态,否则改为 结束 状态
- 消息队列向从服务发送消息,根据从服务 ACK 结果进行判断;ACK 响应成功进行下一步,ACK 响应失败或者超时,消息队列或者定时任务将待发送的记录进行重发。
从业务消费成功,向主服务发送已完成消息,主业务将记录改为 已完成 状态。
最大努力通知方案
系统 A 本地事务执行完之后,发送个消息到 MQ;
- 这里会有个专门消费 MQ 的最大努力通知服务,这个服务会消费 MQ 然后写入数据库中记录下来,或者是放入个内存队列也可以,接着调用系统 B 的接口;
- 要是系统 B 执行成功就 ok 了;要是系统 B 执行失败了,那么最大努力通知服务就定时尝试重新调用系统 B,反复 N 次,最后还是不行就放弃。