分布式锁的可用性与切换效率探讨
不可否认在多核时代多线程并发是常态 分布式锁服务通过持续心跳来保证锁的健壮性让用户不用投入很多精力关注丢锁但也有可能异常的用户进程持续占据锁。我们也曾经遇到过该类场景因为机器 load 高硬件问题等原因设备上的进程假死但其中仍存在部分线程在工作比如锁的心跳维护线程依然正常运行这样锁节点仍然是被假死进程占据着且无法被其他进程抢占。针对该场景为了保证锁最终可以被调度提供了可以安全释放锁的会话加黑机制。当用户需要将发生假死的进程持有的锁释放时可以通过查询会话信息并将会话加黑此后心跳将不能正常维护最终导致会话过期锁节点被安全释放。这里我们不是强制删除锁而是选用禁用心跳的原因如下:a. 删除锁操作本身不安全如果锁已经被其他人正常抢占此时删锁请求会产生误删除。b. 删除锁后持有锁的人会话依然正常它仍然认为自己持有锁会打破锁的互斥性原则。切换效率当进程持有的锁需要被重新调度时持有者可以主动删除锁节点但当持有者发生异常(如进程重启机器宕机等)新的进程要重新抢占就需要等待原先的会话过期后才有机会抢占成功。默认情况下分布式锁使用的会话生命期为 50 秒当持有锁的进程意外退出后(未主动释放锁)最长需要经过 50 秒锁节点才可以被再次抢占。要提升切换精度本质上要压缩会话生命周期同时也意味着更快的心跳频率对后端更大的访问压力。我们通过对后端进行优化使得会话周期可以进一步压缩提升锁的切换效率。例如目前给 TableStore 提供 30 秒的分布式锁同时也通过提供 Restful 接入方式让用户可以自定义会话时长及控制心跳发送同时我们会将锁的精度进一步提高到 20 秒之内 。结合具体的业务场景例如守护进程发现锁持有进程挂掉的场景提供锁的 CAS 释放操作使得进程可以零等待进行抢锁。比如利用在锁节点中存放进程的唯一标识强制释放已经不再使用的锁并重新争抢该方式可以彻底避免进程升级或意外重启后抢锁需要的等待时间。