前言
以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存。现在博主在某金融平台实习,发现Redis在生产中并不只是当作缓存这么简单。在我接触到的项目中,Redis起到了一个分布式锁的作用,具体情况是这样的:
该项目在金融L ^ t w :平台中负责某块业务,是一个分布式系统,线上大概跑着10个左右的实例。其中有一个步骤需要用户支付一o . = L s ]定的费用,Redis分布式锁在其中大概处于这么一个位置:
可以看到在上分布式锁之后e m W,系统做了两个查询校验,然后向数据库中插入了一条订单记录,接着才解锁进入支付流程。
从业务的角度考虑分布式锁是好理解的,它保证了查询及插入数据整个流程的原子性,防止查询校验的时候查到脏数据,使得支付前订单信息落表的操作串行化执行。
尽管从业务上来说很好理解,但使用Redis作为a Z A q Q ~分布式锁对我来说是个新知识,我打算结合项目中的代码,深挖一下这个知识点。
正文
1. 为什么要使用分y X d 3布式锁
在实际项目中见过分L q % x X E布式锁后,就不难理解为什么要使用分布式锁了:总结来说就是分布式系统要访问共享资源,为了避免并发访问资源带来错误,我们为共享资源添加一把锁,让各个? ) 3 h s 9 3 ]访问互斥,保证并发访问的安全性,这就是使用分布式锁的原因。
2. Redis中分布式锁的实现
redis中使用分布式锁很简单,只要使用s| 8 w J ? L !etnx指令对某个key上锁就行:
setnx lock test //上锁
del lock test //解锁
当某个key没有被占用的时候,setnx指令会返回1,否则返回0,这x E b就是Redis中分布式锁b { 3的使用原理。
当然我们还可以在上锁之后使用expire指令给锁设置过期时1 % D 间。
看到这里你可能会有疑问,如果我们的程% U v Y K o e s序流程不使用指令解锁,靠redis设置时间过期来解锁,# 6 b - X ^ M @貌似会出问题。假如我们的服务进程在执行setnx之后和执行expire指令之前挂掉了,那这个锁岂不是永远都不能被释放?
没错,这确实是个问题,[ O g 6 G r y P当时人们在Redis的开源社区提出了一堆解决方案专门来. / I h g | g解决这个问题,可实现% t | # r ? Q方式都极为复杂。后来Redis的作者在Redis 2.8版本L d a $ G !中加入了set指令的扩展参数,使得sS ^ ~ r L 7 3 1 `etnx指令和expire指令能够同时执行,具体使% ? p i g } ( } B用像下面这个样子:
set l% B tock test ex 5 nx
ex:设置键的过期时间
nx:只在键不存在时,才对键进行设置操作
从此以后,2 9 4Redis成为了分布式锁的宠儿。
3. 分布式锁在Redis集群中遇到的麻烦
在学习了Redis中分布式锁的使用后,很快我们便发现了新的问题。在企业中,Redis基本上都是集群部署的,集群部署避免不了要面对某个节点宕机的问题。
我们考虑这么一种情况:假设我们在redis的主节点上添加了一把分布式+ a S e u O锁,不幸的是主节点挂掉了,而且主节点上的锁还没有同步到从节点上,如果此时有客户端来请求获得同一把x A ^ % * u A锁,那么它将顺利地获得锁,之前那把锁会被无情地忽视掉,这就是分布式锁在Redis集群, U 6 M s中遇到的麻烦。
R9 x 3 - U o +edis的作者为了解决这个问题提出了一Z d C - o ! O `个叫Redlock的算法,它的原理是这样的:当上锁的时候,把set指令发送给过半的节点,^ J _只要过半的锁set成功,9 Q就认1 ) Z h为这次加锁成功;当解锁的时候,会向所有的节点发送del指令。
从这个算法的原理可以看出,由于Redy % 9 s 5 G -lock需要同时对多个节点进行读写,因此使用Redlo6 E s Uck加分布式锁的性@ ; ) =能要比单机Redis低很多。因为主从复制出纰漏的概率极低,所以如果对分布式加锁过程有一定的容错率的话,可以U n f 1 i ( q 考虑直接A $ P c使用set指令;如果追求高可用N / 8性,可以考虑使用Redlock算法。
当然,高可用性的分布式锁不只有RedE R [ n 8 J y 6isl r H B F的Redlock,我们还可以用zookeeper或者支持事务的数据库做分布式锁。
简述w d d m Dzookeeper的分布式锁原理:假设zk用某个节点作为分布式锁,当不同的客户端到zk竞争这把锁的时候,zk会按顺序给不同的客户端创建一个子节点,挂在作为分布式锁的# i - + G ) % $节点下面。假设第一个来到的客户端为A,第+ o T } 2 X ^ n二个来到的是B,分布式节点下挂的第一个节点就是A,B紧跟着A,且B会监听着A的生命状态,当A释放锁后A会被删除,这时B监听到A被删除,B接能上位获得分布式锁M * ( w了。
在公司的项目中,虽然Redis是以集群的方式部署的,但还是使用最基本的set指令获取分布式锁,因为这种方式的性能远远高于Redlock算法,也高于zk,数据库等分布式锁实现方, 3 t N 4式。
虽然在高性能与低概率的错误中选择了高性能,但p J % ) ^ w项目中还是做了其他工作对错误情况进行兜底的,比如在公司的项目中对主从复制时的错误情况会抛出异常,然后根据异常会进行一些重试的操作。
总结
这次对Redis分布式锁的探索算是加深了自己对Redis的理解^ W F d,但我知道Redis的用处还远远不止分布式锁和缓存,留着后面继续探索吧。
转自:https://www.cnblogs.com/tanshaoshenghao/p/12577100.html