利用多写Redis实现分布式锁原理与实现分析(转)
利用多写Redis实现分布式锁原理与实现分析
一、关于分布式锁
关于分布式锁,可能绝大部分人都会或多或少涉及到。 我举二个例子:
场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能在某一个时刻会有二笔一样的单子同时到达系统后台。
场景二:在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、使用数据库乐观锁,包括主键防重,版本号控制。但是这两种方法各有利弊。
- 使用主键冲突的策略进行防重,在并发量非常高的情况下对数据库性能会有影响,尤其是应用数据表和主键冲突表在一个库的时候,表现更加明显。其实针对是否会对数据库性能产生影响这个话题,我也和一些专业的DBA同学讨论过,普遍认可的是在mysql数据库中采用主键冲突防重,在大并发情况下有可能会造成锁表现象,比较好的办法是在程序中生产主键进行防重。
- 使用版本号策略
这个策略源于mysql的mvcc机制,使用这个策略其实本身没有什么问题,唯一的问题就是对数据表侵入较大,我们要为每个表设计一个版本号字段,然后写一条判断sql每次进行判断。
2、Zookeeper防重策略
利用ZK确实是一个不错的方案,流程如下:
以前的版本中普遍传言说它的性能不好,但是后续的版本性能得到了较大提高,经过系统压测还是能够支撑较大并发量的,经过压测三台Zookeeper能搞住20000tps。
用zookeeper的优点大概有:高可用、公平锁、心跳保持锁。
3、Redis防重策略
关于主从Redis方案最简单的实现流程如下:
表面来看,这个方案似乎很管用,但是这里存在一个问题:在我们的系统架构里存在一个单点故障,如果Redis的master节点宕机了怎么办呢?有人可能会说:加一个slave节点!在master宕机时用slave就行了!但是其实这个方案明显是不可行的,因为这种方案无法保证第1个安全互斥属性,因为Redis的复制是异步的。 总的来说,这个方案里有一个明显的竞争条件(race condition),举例来说:
- 客户端A在master节点拿到了锁。
- master节点在把A创建的key写入slave之前宕机了。
- slave变成了master节点
- B也得到了和A还持有的相同的锁(因为原来的slave里还没有A持有锁的信息)
于是我就在想,我该如何做才能让Redis在分布式锁这一块能够达到高可用呢?
于是基于Tedis的思想(http://www.oschina.net/p/tedis) 我自己写了一套针对分布式锁的双写Redis框架。
二、双写Redis的架构图
说明:
组件名叫YeeRedisGroup,基本服务主要有四个,当数据到来的时候,会分别插入二个Redis服务,这二个Redis服务采用的是异地双活的方案,当其中一个Redis服务挂了以后,会将这个Redis服务从可用队列中摘除,放入重试队列中,另一个Redis则会继续使用。同样读取Redis的时候只会从可用队列中读取第一个Redis服务继续读取。
三、双写Redis的类图结构
说明:这个图其实没什么可说的,大家自己看就可以了。
四、双写Redis的时序图

说明:这个图主要就是说明了整体系统交互流程是怎样的。
五、故障容错流程图
六、故障重试流程图
七、主动通知与主动查询流程图
八、Redis
利用多写Redis实现分布式锁原理与实现分析(转)的更多相关文章
- Redis实现分布式锁原理与实现分析
一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子: 场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能在某一个时刻会有二笔一样的单子同时到达系统后台. ...
- spring boot 利用redisson实现redis的分布式锁
原文:http://liaoke0123.iteye.com/blog/2375469 利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的. redis官方推荐的分布式锁实现 ...
- 基于Redis的分布式锁和Redlock算法
1 前言 前面写了4篇Redis底层实现和工程架构相关文章,感兴趣的读者可以回顾一下: Redis面试热点之底层实现篇-1 Redis面试热点之底层实现篇-2 Redis面试热点之工程架构篇-1 Re ...
- 身为一枚优秀的程序员必备的基于Redis的分布式锁和Redlock算法
1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手锏功能,是基于Redi ...
- 关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法.变量. 在一个进程中,也就是一个jvm 或者说应用中,我们很容易去处理控制,在j ...
- 利用redis实现分布式锁
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...
- 【Redis】利用 Redis 实现分布式锁
技术背景 首先我们需要先来了解下什么是分布式锁,以及为什么需要分布式锁. 对于这个问题,我们可以简单将锁分为两种--内存级锁以及分布式锁,内存级锁即我们在 Java 中的 synchronized 关 ...
- Redis、Zookeeper实现分布式锁——原理与实践
Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...
- 利用redis实现分布式锁知识点总结及相关改进
利用redis实现分布式锁知识点总结及相关改进 先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/800383 ...
随机推荐
- postgresql 获取刚刚插入的数据主键id
postgresql不支持last_insert_id()方法,恶心到啦: 不过还好它有其他的解决方案: 创建一个测试数据表: CREATE TABLE test.test18 ( id serial ...
- netbeans项目中排除node_modules文件夹
由于项目中的javascript使用了gulp编译技术,所以在web目录下有js的源码目录,其中又有gulp所使用的nodeJS模块,node_modules下面小文件很多,所以造成netbeans扫 ...
- UNIX环境高级编程笔记之文件I/O
一.总结 在写之前,先唠几句,<UNIX环境高级编程>,简称APUE,这本书简直是本神书,像我这种小白,基本上每看完一章都是“哇”这种很吃惊的表情.其实大概三年前,那会大三,我就买了这本书 ...
- node.js 的 os 模块
Node.js的os module 提供了一系列跟操作系统相关的操作函数,比较简单,所以功能也就十分有限.我们可以去官网看各个函数的介绍: http://nodejs.org/api/os.html ...
- 【开源框架】EFW框架中的系统权限与页面子权限详解
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://pan.baid ...
- 三十一、【WCF路由中间件】WCFHosting服务主机的路由器与负载均衡和实现思路
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://pan.baid ...
- 封装Js事件代理方法
// 封装事件代理 function delegateEvent(element, tag, event, listener) { // 判断是否支持addEventlistener if(eleme ...
- maven -- 问题解决(二)解决“Could not calculate build plan”问题
错误提示如下:(eclipse+maven) Could not calculate build plan: Failure to transfer org.apache.maven.plugins: ...
- ionic 通过下载apk升级App
上篇通过更新文件升级APP,如果遇到了比如更新插件之类的问题,上篇是无法解决的,所以为了解决这个问题,需要下载apk文件升级APP. 1.配置文件如下:{'appVersion':'1.0.0', ...
- [转载]百度编辑器-Ueditor使用
前段时间发表过一篇关于“KindEditor在JSP中使用”的博文.这几天在沈阳东软进行JavaWeb方面的实习工作,在一个CMS系统的后台和博客板块中又要用到文本编辑器,突然发现了这个——百度编辑器 ...