分布式锁是一个在分布式环境中重要的原语,它表明不同进程间采用互斥的方式操作共享资源 。本文将谈谈分布式相关的内容 。
1
分布式锁概述
从进程锁到分布式锁
在单进程环境中,为了防止多线程同时对共享资源进行读写操作,我们通常使用内核或者类库实现线程间的互斥 。当扩展到分布式系统下,我们需要提供相同功能的分布式锁服务,不同的主机通过该服务获取一把锁,而获取该锁的机器就可以排他性的访问共享资源 。
在单机环境下,操作系统知道自己进程的状态,当进程挂掉的时候该进程会释放自己持有的锁资源,但在分布式环境下,存在宕机、网络分区、时延等各种异常状态,因此需要给分布式锁提供新的特性:可用性 。
分布式锁的系统分类
基于锁资源的安全性,可以将分布式锁分为以下两部分:
- 基于异步复制的分布式系统,例如:redis、mysql
- 基于paxos协议的分布式一致性系统,例如:etcd、zookeeper
基于paxos协议的分布式系统,通过一致性协议保证数据的多副本,数据的安全性高,通常使用lease机制承担粗粒度的锁服务,适用于对安全性很敏感,希望长期持有锁,不希望发生丢锁现象的服务 。
2
基于 redis 的分布式锁
通常可以使用setnx(set if not exists)实现排他的获取锁操作,但是由于分布式系统中进程可能随时宕机,因此获取锁时,需要添加TTL保证锁不会因为进程挂掉之后变成死锁状态,但是此时又出现了第二个问题,那就是setnx和expire操作必须是原子操作,因为setnx之后,如果进程挂掉,expire有可能没有机会执行,这同样会导致死锁 。正确的操作如下:
SET lock_name value NX EX lock_time
- EX second:设置 key 的过期时间,单位是秒
- NX:当 key 不存在的时候进行设置,等同于 SETNX 操作
DEL lock_name
需要注意的是,这里有可能出现错误删除锁的问题 。场景如下:- 进程A加锁成功,锁超时时间20秒 。由于进程A业务逻辑执行过长,20秒之后,锁过期自动释放 。
- 此时进程B接着加锁,加锁成功后,执行业务逻辑 。这期间,进程A结束执行,使用DEL释放锁 。
SET lock_name uuid NX EX lock_time
释放锁时,需要先获取锁的UUID,如果是自己分配的,则释放锁 。但是这里的比较和释放操作必须是原子操作,否则会出现获获取锁比对的时候正确,此时正好TTL过期,另一个进程加锁成功,这样的话还是会出现错误释放锁的操作 。可以使用Lua脚本实现判断与删除的原子操作 。3
基于 etcd/zookeeper 的分布式锁
排他锁(exclusive locks)
排他锁(写锁、独占锁)表现如下:
进程p1对数据d1加上排他锁,那么在整个加锁期间,只允许进程p1对数据d1进行读取和更新操作,其他任何进程都不能再对整个数据进行任何类型的操作 。直到p1释放排他锁 。
通过在zk/etcd上的数据节点来表示一个锁
推荐阅读
- 分布式存储技术:数据分布与数据复制
- 存储的未来:分布式存储、原子存储、DNA存储
- 浅谈分布式存储架构:IPFS和HDFS
- 分布式存储:边缘计算应用落地的催化剂
- 浅谈两种方法教你如何把QQ好友导入微信,如何qq号好友导入微信好友吗
- 中控锁失灵车门锁不住
- 妹锁,捐献50万元奖金资助贫困学生
- 网络解锁助手下载,安卓4g解锁破解
- 手机2021年新款,指纹解锁2k屏全网通手机
- Play市场解锁小教程,日版谷歌市场解锁