一 分布式事务解决方案
目前比较多的解决方案有几个:
一、结合MQ消息中间件实现的可靠消息最终一致性二、TCC补偿性事务解决方案
三、最大努力通知型方案
第一种方案:可靠消息最终一致性,需要业务系统结合MQ消息中间件实现,在实现过程中需要保证消息的成功发送及成功消费。即需要通过业务系统控制MQ的消息状态
第二种方案:TCC补偿性,分为三个阶段TRYING-CONFIRMING-CANCELING。每个阶段做不同的处理。TRYING阶段主要是对业务系统进行检测及资源预留
CONFIRMING阶段是做业务提交,通过TRYING阶段执行成功后,再执行该阶段。默认如果TRYING阶段执行成功,CONFIRMING就一定能成功。
CANCELING阶段是回对业务做回滚,在TRYING阶段中,如果存在分支事务TRYING失败,则需要调用CANCELING将已预留的资源进行释放。
第三种方案:最大努力通知xing型,这种方案主要用在与第三方系统通讯时,比如:调用微信或支付宝支付后的支付结果通知。这种方案也是结合MQ进行实现,例如:通过MQ发送http请求,设置最大通知次数。达到通知次数后即不再通知。
二 分布式锁实现
完全分布式锁是全局同步的,这意味着在任何时刻没有两个客户端会同时认为它们都拥有相同的锁,使用 Zookeeper 可以实现分布式锁,需要首先定义一个锁节点(lock root node)。
需要获得锁的客户端按照以下步骤来获取锁:
- 保证锁节点(lock root node)这个父根节点的存在,这个节点是每个要获取lock客户端共用的,这个节点是PERSISTENT的。
2. 第一次需要创建本客户端要获取lock的节点,调用 create( ),并设置节点为EPHEMERAL_SEQUENTIAL类型,表示该节点 为临时的和顺序的。如果获取锁的节点挂掉,则该节点自动失效,可以让其他节点获取锁。
3. 在父锁节点(lockroot node)上调用 getChildren( ) ,不需要设置监视标志。 (为了避免“羊群效应”).
4. 按照Fair竞争的原则,将步骤3中的子节点(要获取锁的节点)按照节点顺序的大小做排序,取出编号最小的一个节点做为 lock的owner,判断自己的节点id
是否就为owner id,如果是则返回,lock成功。如果不是则调用 exists( )监听比自己小的前一位的id,关注它锁释放的操作 (也就是exist watch)。
5. 如果第4步监听exist的watch被触发,则继续按4中的原则判断自己是否能获取到lock。
6. 释放锁:需要释放锁的客户端只需要删除在第2步中创建的节点即可。
注意事项:
一个节点的删除只会导致一个客户端被唤醒,因为每个节点只被一个客户端watch,这避免了“羊群效应”。
分布式锁总结解决方法:
这里利用zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watcher机制,来简单实现分布式锁。
主要思想:
1、开启10个线程,在disLocks节点下各自创建名为sub的EPHEMERAL_SEQUENTIAL节点;
2、获取disLocks节点下所有子节点,排序,如果自己的节点编号最小,则获取锁;
3、否则watch排在自己前面的节点,监听到其删除后,进入第2步(重新检测排序是防止监听的节点发生连接失效,导致的节点删除情况);
4、删除自身sub节点,释放连接;