分布式系统面试总结:3、分布式锁(和本地锁的区别、特点、常见实现方案)

仅供自学回顾使用,请支持javaGuide原版书籍。

本篇文章涉及到的分布式锁,在本人其他文章中也有涉及。

《JUC:三、两阶段终止模式、死锁的jconsole检测、乐观锁(版本号机制+CAS实现)+悲观锁》:https://blog.csdn.net/zhiaidaidai/article/details/142862002

《redis:四、双写一致性的原理和解决方案(延时双删、分布式锁)》:https://blog.csdn.net/zhiaidaidai/article/details/135030539

必看⭐⭐⭐:《redis:六、setnx获取锁、Lua脚本释放锁、基于redisson的分布式锁(看门狗机制、主从一致性、红锁)》:https://blog.csdn.net/zhiaidaidai/article/details/135064906

1.本地锁和分布式锁

对于单机多线程来说,在 Java 中,我们通常使用 synchronized 关键字这类 JDK 自带的 本地锁 来控制一个 JVM 进程内的多个线程对本地共享资源的访问,如下:

在这里插入图片描述
分布式系统下,不同的服务/客户端通常运行在独立的 JVM 进程上。如果多个 JVM 进程共享同一份资源的话,使用本地锁就没办法实现资源的互斥访问了。于是,分布式锁 就诞生了。
在这里插入图片描述

2.分布式锁的特点

一个最基本的分布式锁需要满足:

  • 互斥:任意一个时刻,锁只能被一个线程持有。
  • 高可用:锁服务是高可用的,当一个锁服务出现问题,能够自动切换到另外一个锁服务。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。这一般是通过超时机制实现的。
  • 可重入:一个节点获取了锁之后,还可以再次获取锁

除了上面这三个基本条件之外,一个好的分布式锁还需要满足下面这些条件:

  • 高性能:获取和释放锁的操作应该快速完成,并且不应该对整个系统的性能造成过大影响。
  • 非阻塞:如果获取不到锁,不能无限期等待,避免对系统正常运行造成影响。

3.常见分布式锁实现方案

常见分布式锁实现方案如下:

  • 基于关系型数据库比如 MySQL 实现分布式锁。
    • 一般是通过唯一索引或者排他锁实现。
    • 一般不会使用这种方式,问题太多比如性能太差、不具备锁失效机制。
  • 基于分布式协调服务 ZooKeeper 实现分布式锁。
  • 基于分布式键值存储系统比如 Redis 、Etcd 实现分布式锁。

关系型数据库的方式基于 ZooKeeper 或者 Redis 实现分布式锁这两种实现方式要用的更多一些。