简单总结一下分布式锁

MySQL等数据库做分布式锁

锁表的设计:主键、要锁定的资源字段(唯一索引)、有效开始时间、有效结束时间,flag(锁是否有效)
加锁,就是插入一条记录,如果要锁定的资源已经上锁了,肯定是插不了记录的,因为有唯一索引
解锁,就是把数据删掉
定时任务,定时去检查锁是否过期,过期修改flag

Redis做分布式锁

  • 1.单点Redis分布式锁

redis指令为:setnx [key] [value] ex 10
10秒,ex要放到同一个指令,保证原子性
存在的问题:如果业务时间比较长,可能10秒到了,锁过期了,业务还没完,就会导致别的线程获得锁
解决:获得锁的时候,开一个线程去续期(看门狗watch dog);@Async getKey,如果等于我的预期值,就进行续期
如果业务执行完了,就getKey,如果是自己加的锁,就del key(释放锁);必须判断是不是自己的

  • 2.Redis主从

Redis会有单点故障问题,解决方案就是主从,1主2从3哨兵

  • 3.红锁

Redis主从集群存在问题:
一个线程获取了锁,返回成功,然后主挂了,key还没同步到从;另一个线程来拿锁,可以setnx成功,也就是加锁成功,也就是说,两个线程拿到了同一把锁,超卖了
Redis主从集群的问题 解决:
红锁,多台Redis,比如5台(1,2,3,4,5),这五台之间没有关系。服务分别去1,2,3,4,5(按顺序)加锁,过半成功就返回,没过半就是失败–没拿到锁。红锁最少3个

红锁的几个相关疑问:
5台挂了一台怎么办??
程序认为还是5台,依旧需要3台才算过半。只要Redis还或者三台,就问题不大
如果抢锁失败了,就会释放调自己已经抢了的锁,所以,如果几个线程一起过来抢,大家都没抢到也没有问题,数据还是对的(加锁的目的就是为了保证数据一致性),就释放掉,重新抢

重启问题
一个线程,拿到了三个锁,第三台被重启了
然后第二个线程,拿到了3,4,5的锁,也加锁成功,这就是红锁的问题
解决方案:第三台—挂了的,延迟启动,24H之后再重启(时间短一点也可以,比如理论上几分钟就好了)

  • ZK+MySQL乐观锁

JVM的STW问题:(JVM集群)去Redis拿锁(集群),加锁
加锁成功,然后返回,执行业务
此时STW,续期的线程也停了,此时key过期了;此时其他线程来加锁,也就也加锁成功了
STW完了,业务继续执行,(比如要把10变9,但这里变成了8,超卖了)
这个问题,鸵鸟,Redis解决不了
其实ZK也不能解决,也就是建立一个临时节点,STW的时候,临时节点没了
之际上很多公司就是用一台Redis做锁的,稳定性已经很高很高了
如果真要解决(阿里都不这么用),乐观锁:ZK 再加一个MySQL,双写,为了保证数据一致性
先到ZK加锁,ZK写A000(假设),然后写到MySQL,此时STW,另一个线程来ZK写A001(为什么加1?ZK的特性,节点是递增的),然后去MySQL更新了version为A001,然后之前的线程的JVM STW好了,再到MySQL查,发现版本不一样了,就回滚,数据一致性就可以保证了

最后
最简单实用的就是Redis一台搞定,主要还是看业务量,看需求
追求并发,用redis,追求数据一致性,用zk

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值