分布式锁
目录
分布式锁用于解决分布式系统的资源竞争问题。例如避免多台服务器同时修改一个数据导致数据出错。
一个比较简单的场景是基于 crontab 的定时任务。当系统采用单机时,可以直接把定时任务放到 crontab 触发。但是如果要为系统部署一台热备,就得在主机故障后让备机自动代替主机触发定时任务的功能。
有两种可选项:
- 备机 crontab 不加入定时任务,当主机故障后,通过某种方式为备机加入 crontab
- 主备机的 crontab 保持一致,但阻止他们同时执行
第一种方式需要获取服务器列表及其健康信息。在发现主机故障后,选择一台服务器登录并修改 crontab。比较麻烦。
如果选择第二种方式,则需要考虑多台机器同时启动一个任务时,如果仅让其中一台服务器去执行。这就需要分布式锁。
每台服务器在启动任务的时候,都去尝试获取这个任务的锁。如果获取到,就执行;获取不到就放弃执行,退出任务。
分布式锁的实现方式
分布式锁的支撑组件有两个要求:
- 本身支持锁住数据,或者所有请求按照顺序逐个执行
- 支持集群。即本身是高可用的。
这些组件可以是 MySQL 等关系型数据库、Redis、Zookeeper。以下主要介绍这三者的实现方式。
MySQL 实现分布式锁
字段 | 作用 |
---|---|
lock_id | 用于唯一标识某个任务的 ID,设置 unique 索引 |
owner | 锁的持有者,可以主动释放锁 |
expire_at | 锁的过期时间 |
分为两步:
- 查看锁是否存在,如果不存在就创建。创建成功则表示获取到锁。
- 锁存在的情况下,尝试更新。更新成功则表示获取到锁。
第一步用 SELECT key FROM lock WHERE key = ? FOR UPDATE
,将 key 锁住。
第二步在更新的时候,需要满足以下两个条件中的一个:
- owner 为空。即持有者主动释放锁。
- expire_at 小于当前时间。表示锁过期。
Redis
https://www.jianshu.com/p/7e47a4503b87