写点什么

如何实现分布式锁,聊聊你的想法?

用户头像
卢卡多多
关注
发布于: 1 小时前
如何实现分布式锁,聊聊你的想法?

1.如何实现分布式锁:

防止超卖:


单机版 synchronized(this) {代码块}


但是有多个服务器,Nginx 配置负载均衡之后--开始使用锁就不能是 synchronized,因为他是对于进程来说的--比如是简单的 Jvm 的底层来说的;


如果是多个服务器,多个进程,同一个资源库存减--会出现超卖(意思是 68 买了两次,出现两个 67);

1.1 所以这里我们优化成升级一下:

setnx: 分布式锁,(set if not exist )就加锁


如果存在--这个锁就不加了;

1.2 防止死锁:

finally: 删掉这个锁;

1.3 如果说,在执行这个过程中,还没有删除锁,进程被直接 kill -9 杀死了,

我们直接可以对数据进行原子性操作:----setnx 加一个过期时间,


锁自动释放掉; 也可能是 10 秒钟;


可能一般的互联网公司--并发需求不那么大的,这个 setnx 加防止死锁(过期时间)


也能抗住一些并发;

高可用;高并发

但是我们这次要了解的是,真正的互联网公司怎么使用缓存来做秒杀;

1.保证在互联网公司,高并发可以的状态需要注意的点

保证多个线程争夺时,redis 缓存中过期时间已经失效, 导致第一个线程对库存还未来得及操作,第二个线程已经对--可以拿到新的锁进程操作,接着壹号线程为了防止死锁,删除了第二个线程所在的锁---,以此类推,全乱了;


我自己线程的锁可能被别的线程释放了;


优化:可以将添加锁的时候,我们将数据直接对线程生成一个 id,当我删除的时候,再去对比一下加锁中的 id,和我正在执行的 client 是同一个吗;


锁超时失效的问题;


分线程开始使用—测试主线程是否存在索结构,开展锁续命的操作


这里 的逻辑代码已经有框架给我们完成了,Redission(分布式版本下的 jedis)


多数场景下我们使用的 Jedis,但是使用的过程中,分布式高性能,高并发的架构中,使用的一般是升级版本--Redission


引入依赖:

redission 分布式的实现原理:


1.将加锁的步骤用 Lua 脚本的特性展示出来,变成简单的--原子性操作;


2.加锁成功会开启后台的子线程,是否还持有锁,如果持有延长锁的时间


然后结束释放:


当然在此期间,线程 2 都处于一个尝试 while 循环加锁的操作:


如果说当前系统宕机了,死锁了,可以被找到过期时间自动释放掉;

lua 脚本:原子命令

redission 的对象--然后可以得到相应的 lock ;


底层还是类似于 setnx 的写法,(以为加锁和过期时间必须要一条语句,否则就会出现原子性问题)


但是 lua 脚本可以,redis 支持读取很多条的 redis 命令进行原子性操作,


也就是说一个字符串中存在很多条的 redis 加 lock,过期时间的操作,我们 lua 脚本在执行的过程中会直接实现将数据变化的问题---直接会解决原子性问题


lock 之后,timeTask 的定时任务:


默认


 private  long lockWatchdogTimeout=30*1000   //看门狗的时间          执行定时任务的时间是 看门狗时间/3=10
复制代码


单机版的使用 redis,分布式锁实现非超卖的问题,这个就是互联网公司常见的写法


已经是比较完美的了;但是如果是集群架构那就另当别论了;


同一个商品逻辑加锁被多个线程共同所执行:


分布式锁一般会把并行的问题化为串行的逻辑,但是也会将性能变为安全的;


性能损坏;


redis 的单机的性能 QPS 可以接近 10 万了


可以满足大多数,性能提升(激增)


RedLock:

zookeeper 的结构来实现分布式:

CAP 的结构:


c:一致性


A:可用性


P:分区容错性;


zookeeper 保持的事 Cp:


主线程加锁之后,不会立马告知客户端开启业务代码,而是开始数据通同步到子节点,并且半数以上才可以;(保证数据)


redis 的集群架构: AP 架构;


zab 底层的选举机制---数据一致性(可以得到已经同步到最新数据的节点上,当 leader 节点)、


集群架构:


主从,哨兵等架构就不一样了

发布于: 1 小时前阅读数: 2
用户头像

卢卡多多

关注

努力寻找生活答案的旅途者 2020.04.12 加入

公众号:卢卡多多,欢迎一起交流学习

评论

发布
暂无评论
如何实现分布式锁,聊聊你的想法?