前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我司用了6 年的分布式锁,28个赞

我司用了6 年的分布式锁,28个赞

作者头像
大数据技术架构
发布2019-08-28 16:02:06
4060
发布2019-08-28 16:02:06
举报

前言

提到数据一致性、操作原子性,诸如此类的一些与并发有关的词汇时不知道你第一时间会联想到什么呢?我相信大多数人可能会想到「锁」,为什么是锁呢,这个我不多说,大家心里应该都明白。

在单体应用时代,我们使用jvm提供的锁就可以很好的工作,但是到了分布式应用时代,JVM提供的锁就行不通了,那么势必要借助一些跨JVM的临界资源来支持锁的相关语义,比如redis,zookeeper等。

步入正题

我今天就来分享下我司基于redis来实现的分布式锁,2013年投入使用,也算是久经沙场。

但是也存在一些设计上的缺陷,这个我后面也会提到,希望大家秉着互相学习的态度文明交流,别一上来就说这不行那不行,还是那句话「适合自己的才是最好的」。

加锁过程分析

我第一次读代码的时候,有这么几个疑惑:

Q1:为什么不使用 SET key value [expiration EX seconds|PX milliseconds] [NX|XX] 这个指令来实现key的自动过期呢,反而放到应用代码判断key是否过期?

A1:我们的分布式锁开发的时候SET命令还不支持NX、PX,所以才想出这种办法来实现key过期,NX、PX在2.6.12以后开始支持;

Q2:已经判断了当前key对应的时间戳已经过期了,为什么还要使用getset再获取一次呢,直接使用set指令覆盖不可以吗?

A2:这里其实牵扯到并发的一些事情,如果直接使用set,那有可能多个客户端会同时获取到锁,如果使用getset然后判断旧值是否过期就不会有这个问题,设想一下如下场景:

  1. C1加锁成功,不巧的是,这时C1意外的奔溃了,自然就不会释放锁
  2. C2,C3尝试加锁,这时key已存在,所以C2,C3去判断key是否已过期,这里假设key已经过期了,所以C2,C3使用set指令去设置值,那两个都会加锁成功,这就闯大祸了;

如果使用getset指令,然后判断下返回值是否过期就可以避免这种问题,假如C2跑的快,那C3判断返回的时间戳已经过期,自然就加锁失败;

释放锁过程分析

Q1:为什么释放锁时还需要判断key是否过期呢,直接del不是性能更高吗?

A1:考虑这样一种场景:

  1. C1获取锁成功,开始执行自己的操作,不幸的是C1这时被阻塞了;
  2. C2这时来获取锁,由于C1被阻塞了很长时间,所以key对应的value已经过期了,这时C2通过getset加锁成功;
  3. C1尘封了太久终于被再次唤醒,对于释放锁这件事它可是认真的,伴随着一波del操作,悲剧即将发生;
  4. C3来获取锁,好家伙,居然一下就成功了,接着就是一波操作猛如虎,接着就是一堆的客诉过来了;

为什么会这样呢?回想C1被唤醒以后的事情,居然敢直接del,C2活都没干完呢,锁就被C1给释放了,这时C3来直接就加锁成功,所以为了安全起见C3释放锁时得分成两步:

  1. 判断value是否已经过期
  2. 如果已过期直接忽略,如果没过期就执行del。

这样就真的安全了吗?安全了吗?安全了吗?假如第一步和第二步之间相隔了很久是不是也会出现锁被其他人释放的问题呢?是吧?是的!有没有别的解决办法呢?听说借助lua就可以解决这个问题了。

正视自己的缺点

Q1:Redis锁的过期时间小于业务的执行时间该如何续期?

A1:这个暂时没有实现,据说有一个叫Redisson的家伙解决了这个问题,我们也有部分业务在使用,未来有可能会切换到Redisson。

Q2:怎么实现的高可用?

A2:我们采用Failover机制,初始化redis锁的时候会维护一个redis连接池,加锁或者释放锁的时候采用多写的方式来保障一致性,如果某个节点不可用的时候会自动切换到其他节点,但是这种机制可能会导致多个客户端同时获取到锁的情况,考虑这种情况:

  1. C1去redis1加锁,加锁成功后会写到redis2,redis3;
  2. C2也去redis1加锁,但是此时C2到redis1的网络出现问题,这时C2切换到redis2去加锁,由于第一步中的redis多写并不是原子的,所有就有可能导致C2也获取锁成功;

针对这种情况,目前有些业务方是通过数据库唯一索引的方式来规避的,未来会修复这个bug,具体方案目前还没有。

推荐阅读:1:面试题:InnoDB中一棵B+树能存多少行数据?2:大数据正当时,理解这几个术语很重要3:全网最细致的 HBase 内核解析4:全文搜索引擎Elasticsearch,这篇文章给讲透了5:揭开 ClickHouse 快的面纱
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大数据技术架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 我今天就来分享下我司基于redis来实现的分布式锁,2013年投入使用,也算是久经沙场。
  • 但是也存在一些设计上的缺陷,这个我后面也会提到,希望大家秉着互相学习的态度文明交流,别一上来就说这不行那不行,还是那句话「适合自己的才是最好的」。
    • 加锁过程分析
      • 释放锁过程分析
        • 正视自己的缺点
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档