Java实战技术架构设计乱七八糟风暴

利用多写Redis实现分布式锁原理与实现分析

2016-10-01  本文已影响8042人  小程故事多

在我写这篇文章的时候,其实我还是挺纠结的,因为我这个方案本身也是雕虫小技拿出来显眼肯定会被贻笑大方,但是我最终还是拿出来与大家分享,我本着学习的态度和精神,希望大家能够给与我指导和改进方案。

一、关于分布式锁

关于分布式锁,可能绝大部分人都会或多或少涉及到。 我举二个例子:
场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能在某一个时刻会有二笔一样的单子同时到达系统后台。

场景二:在App中下订单的时候,点击确认之后,没反应,就又点击了几次。在这种情况下,如果无法保证该接口的幂等性,那么将会出现重复下单问题。 在接收消息的时候,消息推送重复。如果处理消息的接口无法保证幂等,那么重复消费消息产生的影响可能会非常大。

类似这种场景,我们有很多种方法,可以使用幂等操作,也可以使用锁的操作。
我们先来解释一下什么是幂等操作: 所谓幂等,简单地说,就是对接口的多次调用所产生的结果和调用一次是一致的。扩展一下,这里的接口,可以理解为对外发布的HTTP接口或者Thrift接口,也可以是接收消息的内部接口,甚至是一个内部方法或操作。

在分布式环境中,网络环境更加复杂, 因前端操作抖动、网络故障、消息重复、响应速度慢等原因,对接口的重复调用概率会比集中式环境下更大,尤其是重复消息在分布式环境中很难避免。Tyler Treat也在《You Cannot Have Exactly-Once Delivery》一文中提到:
Within the context of a distributed system, you cannot have exactly-once message delivery.

分布式环境中,有些接口是天然保证幂等性的,如查询操作。有些对数据的修改是一个常量,并且无其他记录和操作,那也可以说是具有幂等性的。其他情况下,所有涉及对数据的修改、状态的变更就都有必要防止重复性操作的发生。通过间接的实现接口的幂等性来防止重复操作所带来的影响,成为了一种有效的解决方案。

于是我们根据以上内容就可以讲一下使用分布式锁的方法有哪些。

1、使用数据库乐观锁,包括主键防重,版本号控制。但是这两种方法各有利弊。

2、Zookeeper防重策略
利用ZK确实是一个不错的方案,流程如下:

Paste_Image.png

以前的版本中普遍传言说它的性能不好,但是后续的版本性能得到了较大提高,经过系统压测还是能够支撑较大并发量的,经过压测三台Zookeeper能搞住20000tps。
用zookeeper的优点大概有:高可用、公平锁、心跳保持锁。

3、Redis防重策略
关于主从Redis方案最简单的实现流程如下:

Paste_Image.png

表面来看,这个方案似乎很管用,但是这里存在一个问题:在我们的系统架构里存在一个单点故障,如果Redis的master节点宕机了怎么办呢?有人可能会说:加一个slave节点!在master宕机时用slave就行了!但是其实这个方案明显是不可行的,因为这种方案无法保证第1个安全互斥属性,因为Redis的复制是异步的。 总的来说,这个方案里有一个明显的竞争条件(race condition),举例来说:

于是我就在想,我该如何做才能让Redis在分布式锁这一块能够达到高可用呢?
于是基于Tedis的思想(http://www.oschina.net/p/tedis) 我自己写了一套针对分布式锁的双写Redis框架。

二、双写Redis的架构图

Paste_Image.png
说明:
组件名叫YeeRedisGroup,基本服务主要有四个,当数据到来的时候,会分别插入二个Redis服务,这二个Redis服务采用的是异地双活的方案,当其中一个Redis服务挂了以后,会将这个Redis服务从可用队列中摘除,放入重试队列中,另一个Redis则会继续使用。同样读取Redis的时候只会从可用队列中读取第一个Redis服务继续读取。

三、双写Redis的类图结构

Paste_Image.png
说明:这个图其实没什么可说的,大家自己看就可以了。

四、双写Redis的时序图


Paste_Image.png
说明:这个图主要就是说明了整体系统交互流程是怎样的。

五、故障容错流程图

Paste_Image.png

六、故障重试流程图

Paste_Image.png

七、主动通知与主动查询流程图

Paste_Image.png

八、Redis 􏰏􏲀􏲑􏰊􏰐􏲈􏲒􏲑􏰊􏲏􏰣􏰝可用队列与重试队列结构图

Paste_Image.png

九、项目阐述

上面项目的最终压测结果还没有出来,并且项目也还没有最终开源,在此我是非常想和大家进行交流,我觉得可能的缺点是客户端相对比较重,有大量的逻辑都在客户端上面进行,从我个人是本着交流与学习的态度勇于接受各种批评与指正,谢谢。

上一篇 下一篇

猜你喜欢

热点阅读