分布式锁

Posted terry-wu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式锁相关的知识,希望对你有一定的参考价值。

1)锁的概念

技术图片

 

同步方式:

  • 原子变量
  • volatile

锁的性能优化

  • 缩小锁的范围
  • 减小锁的粒度
  • 锁分段

锁的分类

  • 公平锁:synchronized, ReentrantLock
  • 非公平锁: ReentrantLock, CAS(自旋锁)
  • 独享锁: synchronized, ReentrantLock
  • 共享锁:Semaphore

2)分布式锁

  • 互斥性:在任意时刻只有一个客户端可以获取锁
  • 防死锁:即使有一个客户端持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁
  • 持锁人解锁:加锁与解锁必须为同一客户端,客户端自己不能把别人的加的锁给解开了
  • 可重入:当一个客户端获取对象锁后,这个客户端可以再次获取本对象上的锁

A. Redis分布式锁

1)加锁流程

技术图片

 

2)Redis分布式锁算法

a. 加锁:
  • setnx命令,set if not exists
  • 设置锁的有效时间防止死锁
  • 设置一个随机值用来标识锁的持有人
b. 解锁:
  • 检查是否持有锁
  • 删除锁
c. 使用lua脚本保证解锁操作的原子性
if redis.call("get", KEYS[1]) == ARGV[1]
then return redis.call("del", KEYS[1])
else return 0
end 

B. 基于数据库的分布式锁

1)实现方式

  • 新建一张锁表
  • 获取锁时插入一条数据
  • 解锁时删除数据

2)主要问题:

  • 可用性差,数据库挂掉会导致业务系统不可用,连接数量有限
  • 锁的失效时间难以控制,容易造成死锁
  • 非阻塞锁,未获得锁的线程需要需次出发获得锁操作
  • 非重入锁,同一个线程在没有释放锁之前无法再次获取该锁

C. 基于zk的分布式锁

1)实现方式:

每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的临时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。

当释放锁的时候,只需将这个临时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。

2)主要问题:

性能一般,加减锁的时候需要通过Leader创建或删除临时节点

D.  分布式锁比较

1)理解成本

数据库 > 缓存 > Zookeeper

2)复杂性

Zookeeper > 缓存 > 数据库

3)性能

缓存 > Zookeeper > 数据库

4)可靠性

Zookeeper > 缓存 > 数据库

3)幂等性

处理幂等性常用的方法

  • A. 生成全局唯一id(uuid),借助redis存储
  • B. 乐观锁机制(cas)
  • C. 悲观锁机制(for update)?
  • D. Token机制(类全局id)
  • E. 防重表(支付订单号,唯一索引)
  • F. 异步处理

以上是关于分布式锁的主要内容,如果未能解决你的问题,请参考以下文章

分布式锁三种解决方案

MySQL系列:kafka停止命令

硬核!管理mysql数据库的工具

java开发的项目案例,大厂内部资料

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

Java进阶之光!2021必看-Java高级面试题总结