我们知道,在多线程情况下访问一些共享资源需要加锁,不然就会出现数据被写乱的问题。在分布式系统下,这样的问题也是一样的。只不过,我们需要一个分布式的锁服务。对于分布式的锁服务,一般可以用数据库 DB、Redis 和 ZooKeeper 等实现。不管怎么样,分布式的锁服务需要有以下几个特点。
安全性(Safety):在任意时刻,只有一个客户端可以获得锁(排他性)。
避免死锁:客户端最终一定可以获得锁,即使锁住某个资源的客户端在释放锁之前崩溃或者网络不可达。
容错性:只要锁服务集群中的大部分节点存活,Client 就可以进行加锁解锁操作。
Redis 的分布式锁服务
我们通过以下命令对资源加锁。
SET resource_name my_random_value NX PX 30000
解释一下:
SET NX 命令只会在 key 不存在的时候给 key 赋值,PX 命令通知 Redis 保存这个 key 30000ms。
my_random_value 必须是全局唯一的值。这个随机数在释放锁时保证释放锁操作的安全性。
PX 操作后面的参数代表的是这个 key 的存活时间,称作锁过期时间。
当资源被锁定超过这个时间时,锁将自动释放。
获得锁的客户端如果没有在这个时间窗口内完成操作,就可能会有其他客户端获得锁,引起争用问题。
这里的原理是,只有在某个 key 不存在的情况下才能设置(set)成功该 key。于是,这就可以让多个进程并发去设置同一个 key,只有一个进程能设置成功。而其它的进程因为之前有人把 key 设置成功了,而导致失败(也就是获得锁失败)。