项目中用到了Redis分布式锁,了解一下背后的原理
前言
以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存。现在博主在某金融平台实习,发现Redis在生产中并不只是当作缓存这么简单。在我接触到的项目中,Redis起到了一个分布式锁的作用,具体情况是这样的:
该项目在金融平台中负责某块业务,是一个分布式系统,线上大概跑着10个左右的实例。其中有一个步骤需要用户支付一定的费用,Redis分布式锁在其中大概处于这么一个位置:
可以看到在上分布式锁之后,系统做了两个查询校验,然后向数据库中插入了一条订单记录,接着才解锁进入支付流程。
从业务的角度考虑分布式锁是好理解的,它保证了查询及插入数据整个流程的原子性,防止查询校验的时候查到脏数据,使得支付前订单信息落表的操作串行化执行。
尽管从业务上来说很好理解,但使用Redis作为分布式锁对我来说是个新知识,我打算结合项目中的代码,深挖一下这个知识点。
正文
1. 为什么要使用分布式锁
在实际项目中见过分布式锁后,就不难理解为什么要使用分布式锁了:总结来说就是分布式系统要访问共享资源,为了避免并发访问资源带来错误,我们为共享资源添加一把锁,让各个访问互斥,保证并发访问的安全性,这就是使用分布式锁的原因。
2. Redis中分布式锁的实现
redis中使用分布式锁很简单,只要使用setnx指令对某个key上锁就行:
setnx lock test //上锁
del lock test //解锁
当某个key没有被占用的时候,setnx指令会返回1,否则返回0,这就是Redis中分布式锁的使用原理。
当然我们还可以在上锁之后使用expire指令给锁设置过期时间。
看到这里你可能会有疑问,如果我们的程序流程不使用指令解锁,靠redis设置时间过期来解锁,貌似会出问题。假如我们的服务进程在执行setnx之后和执行expire指令之前挂掉了,那这个锁岂不是永远都不能被释放?
没错,这确实是个问题,当时人们在Redis的开源社区提出了一堆解决方案专门来解决这个问题,可实现方式都极为复杂。后来Redis的作者在Redis 2.8版本中加入了set指令的扩展参数,使得setnx指令和expire指令能够同时执行,具体使用像下面这个样子:
set lock test ex 5 nx
ex:设置键的过期时间
nx:只在键不存在时,才对键进行设置操作
从此以后,Redis成为了分布式锁的宠儿。
3. 分布式锁在Redis集群中遇到的麻烦
在学习了Redis中分布式锁的使用后,很快我们便发现了新的问题。在企业中,Redis基本上都是集群部署的,集群部署避免不了要面对某个节点宕机的问题。
我们考虑这么一种情况:假设我们在redis的主节点上添加了一把分布式锁,不幸的是主节点挂掉了,而且主节点上的锁还没有同步到从节点上,如果此时有客户端来请求获得同一把锁,那么它将顺利地获得锁,之前那把锁会被无情地忽视掉,这就是分布式锁在Redis集群中遇到的麻烦。
Redis的作者为了解决这个问题提出了一个叫Redlock的算法,它的原理是这样的:当上锁的时候,把set指令发送给过半的节点,只要过半的锁set成功,就认为这次加锁成功;当解锁的时候,会向所有的节点发送del指令。
从这个算法的原理可以看出,由于Redlock需要同时对多个节点进行读写,因此使用Redlock加分布式锁的性能要比单机Redis低很多。因为主从复制出纰漏的概率极低,所以如果对分布式加锁过程有一定的容错率的话,可以考虑直接使用set指令;如果追求高可用性,可以考虑使用Redlock算法。
当然,高可用性的分布式锁不只有Redis的Redlock,我们还可以用zookeeper或者支持事务的数据库做分布式锁。
简述zookeeper的分布式锁原理:假设zk用某个节点作为分布式锁,当不同的客户端到zk竞争这把锁的时候,zk会按顺序给不同的客户端创建一个子节点,挂在作为分布式锁的节点下面。假设第一个来到的客户端为A,第二个来到的是B,分布式节点下挂的第一个节点就是A,B紧跟着A,且B会监听着A的生命状态,当A释放锁后A会被删除,这时B监听到A被删除,B接能上位获得分布式锁了。
在公司的项目中,虽然Redis是以集群的方式部署的,但还是使用最基本的set指令获取分布式锁,因为这种方式的性能远远高于Redlock算法,也高于zk,数据库等分布式锁实现方式。
虽然在高性能与低概率的错误中选择了高性能,但项目中还是做了其他工作对错误情况进行兜底的,比如在公司的项目中对主从复制时的错误情况会抛出异常,然后根据异常会进行一些重试的操作。
总结
这次对Redis分布式锁的探索算是加深了自己对Redis的理解,但我知道Redis的用处还远远不止分布式锁和缓存,留着后面继续探索吧。
扩展阅读:
项目中用到了Redis分布式锁,了解一下背后的原理的更多相关文章
- Redis分布式锁的实现
前段时间,我在的项目组准备做一个类似美团外卖的拼手气红包[第X个领取的人红包最大],基本功能实现后,就要考虑这一操作在短时间内多个用户争抢同一资源的并发问题了,类似于很多应用如淘宝.京东的秒杀活动场景 ...
- springboot项目:Redis分布式锁的使用(模拟秒杀系统)
模拟秒杀系统: 第一步:编写Service package com.payease.service; /** * liuxiaoming * 2017-12-14 */ public interfac ...
- Redis专题(3):锁的基本概念到Redis分布式锁实现
拓展阅读:Redis闲谈(1):构建知识图谱 Redis专题(2):Redis数据结构底层探秘 近来,分布式的问题被广泛提及,比如分布式事务.分布式框架.ZooKeeper.SpringCloud等等 ...
- 面试官:你真的了解Redis分布式锁吗?
什么是分布式锁 说到Redis,我们第一想到的功能就是可以缓存数据,除此之外,Redis因为单进程.性能高的特点,它还经常被用于做分布式锁. 锁我们都知道,在程序中的作用就是同步工具,保证共享资源在同 ...
- 利用redis分布式锁的功能来实现定时器的分布式
文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...
- redis咋么实现分布式锁,redis分布式锁的实现方式,redis做分布式锁 积极正义的少年
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- spring boot redis分布式锁
随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁.分布式锁的实现有很多种,比如基于数据库. zookeeper 等,本文主要介绍使用 Redis 做分布式锁的方式,并封装成spring b ...
- Redis分布式锁的正确实现方式
前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...
- Redis分布式锁---完美实现
这几天在做项目缓存时候,因为是分布式的所以需要加锁,就用到了Redis锁,正好从网上发现两篇非常棒的文章,来和大家分享一下. 第一篇是简单完美的实现,第二篇是用到的Redisson. Redis分布式 ...
随机推荐
- docker 使用:镜像和容器
docker 镜像 docker image是一个极度精简版的Linux程序运行环境,官网的java镜像包括的东西更少,除非是镜像叠加方式的如centos+java7,需要定制化build的一个安装包 ...
- python 自动发送邮件遇到的问题
在学习自动化测试高级应用,根据内容写关于自动发送邮件出现了几个问题以及解决办法: 问题1: 代码写好之后,运行的时候,出现如下报错: SMTPAuthenticationError: (550, '\ ...
- 创业的游戏 明星APP上市前后的冰火两重天
明星APP上市前后的冰火两重天" title="创业的游戏 明星APP上市前后的冰火两重天"> 当下,似乎只有创业才是能够实现笑看风云变幻的那条"黄金通道 ...
- Proto3使用指南
这篇指南讲述如何使用Protocol Buffers来结构化你的Protocol Buffer数据,包括.proto文件语法以及如何从.proto文件生成你的访问类型.本文主要涵盖了proto3的语法 ...
- 码海拾遗:简述C++(一)
C++是Bjarne Stroustrup博士于1982年,在C语言的基础上引入并扩充了面向对象的概念后发明的一种新的程序语言.就与C语言的渊源而言,C++可以说是C语言的超集,它兼容C的一切(可能是 ...
- Java运行 Unsupported major.minor version 51.0 错误
今天写了简单的Java程序,运行的时候不知道为啥出现这个问题 happy@happy-HP-Compaq-dx7518-MT:~/Study/CrazyJava$ java FieldTest Exc ...
- 记一次MySQL表分区操作
最近一次日常迭代中,业务线需要对一张大表进行联合查询,查询性能可想而知,测试过程中服务接口直接响应超时,导致服务不可用,最后临时对该表进行分区操作,暂时缓解性能问题.由于是第一次操作表分区,姑且记录一 ...
- dns原理介绍及实践问题总结
1 问题引入: a) 域名劫持: dns过程中某个环节被攻击/篡改,导致dns结果为劫持者的服务器.例如竞争对手将你方的app下载地址篡改为他方的app下载地址. b) 对现网用户进行监控时,发现个别 ...
- Java和C++引用的区别
Java的引用实际上是对指针的一个封装. C++的引用是变量的一个别名. Java的定义出来的变量(除了基本类型)其实就是一个引用,指向真正的对象. C++可以通过将引用传入函数,在函数内修改所引用的 ...
- layer打开弹窗时传递参数(content:)
在使用layer打开弹窗时,我希望带一些参数过去,进行某些判断.直接就可以用链接+参数的方式即可. js var userGrade=Mrant layer.open({ title: '权限管理', ...