目录

分布式锁

分布式锁用于解决分布式系统的资源竞争问题。例如避免多台服务器同时修改一个数据导致数据出错。

一个比较简单的场景是基于 crontab 的定时任务。当系统采用单机时,可以直接把定时任务放到 crontab 触发。但是如果要为系统部署一台热备,就得在主机故障后让备机自动代替主机触发定时任务的功能。

有两种可选项:

  1. 备机 crontab 不加入定时任务,当主机故障后,通过某种方式为备机加入 crontab
  2. 主备机的 crontab 保持一致,但阻止他们同时执行

第一种方式需要获取服务器列表及其健康信息。在发现主机故障后,选择一台服务器登录并修改 crontab。比较麻烦。

如果选择第二种方式,则需要考虑多台机器同时启动一个任务时,如果仅让其中一台服务器去执行。这就需要分布式锁。

每台服务器在启动任务的时候,都去尝试获取这个任务的锁。如果获取到,就执行;获取不到就放弃执行,退出任务。

分布式锁的实现方式

分布式锁的支撑组件有两个要求:

  1. 本身支持锁住数据,或者所有请求按照顺序逐个执行
  2. 支持集群。即本身是高可用的。

这些组件可以是 MySQL 等关系型数据库、Redis、Zookeeper。以下主要介绍这三者的实现方式。

MySQL 实现分布式锁

字段作用
lock_id用于唯一标识某个任务的 ID,设置 unique 索引
owner锁的持有者,可以主动释放锁
expire_at锁的过期时间

分为两步:

  1. 查看锁是否存在,如果不存在就创建。创建成功则表示获取到锁。
  2. 锁存在的情况下,尝试更新。更新成功则表示获取到锁。

第一步用 SELECT key FROM lock WHERE key = ? FOR UPDATE,将 key 锁住。

第二步在更新的时候,需要满足以下两个条件中的一个:

  1. owner 为空。即持有者主动释放锁。
  2. expire_at 小于当前时间。表示锁过期。

Redis

https://www.jianshu.com/p/7e47a4503b87

Zookeeper