MST

星途 面试题库

面试题:Redis 命令并发控制之锁机制相关

在 Redis 中,如何使用 SETNX 命令实现简单的分布式锁?如果在使用分布式锁过程中出现锁长时间未释放,你会如何处理?
25.2万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

使用 SETNX 命令实现简单的分布式锁

  1. 加锁: 在 Redis 中,可以使用 SETNX key value 命令来实现加锁操作。SETNXSET if Not eXists 的缩写,即只有当指定的键不存在时,才会设置键的值。 示例代码(以 Python 和 redis - py 库为例):
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
lock_key = "my_distributed_lock"
lock_value = "unique_value"

if r.setnx(lock_key, lock_value):
    print("获取锁成功")
else:
    print("获取锁失败")

在这个示例中,setnx 方法尝试设置 lock_key 的值为 lock_value。如果设置成功(返回 True),说明获取锁成功;否则,说明锁已被其他进程持有。

  1. 解锁: 当任务完成后,需要释放锁,即删除对应的键。 示例代码:
if r.delete(lock_key):
    print("释放锁成功")
else:
    print("释放锁失败")

处理锁长时间未释放的情况

  1. 设置锁的过期时间: 为了防止锁长时间未释放,可以在加锁时给锁设置一个过期时间。在 Redis 2.6.12 版本之后,可以使用 SET key value NX EX seconds 命令,它等价于 SETNX 加上 EXPIRE 命令。 示例代码(Python):
if r.set(lock_key, lock_value, nx = True, ex = 10):
    print("获取锁成功,设置过期时间为10秒")
else:
    print("获取锁失败")

这里通过 ex 参数设置了锁的过期时间为 10 秒。如果在 10 秒内任务没有完成,锁会自动释放,其他进程可以获取锁。

  1. 使用看门狗机制: 对于一些长时间运行的任务,可以使用看门狗机制。即当获取锁成功后,启动一个后台线程,定期检查任务是否完成,如果任务还在运行,就延长锁的过期时间。 示例代码(以 Python 为例,使用 threading 模块实现简单的看门狗):
import threading
import time


def watchdog(redis_client, lock_key, lock_value, expire_time):
    while True:
        if redis_client.get(lock_key) == lock_value.encode('utf - 8'):
            redis_client.expire(lock_key, expire_time)
        time.sleep(expire_time // 3)


if r.set(lock_key, lock_value, nx = True, ex = 10):
    print("获取锁成功")
    # 启动看门狗线程
    watch_dog_thread = threading.Thread(target = watchdog, args = (r, lock_key, lock_value, 10))
    watch_dog_thread.daemon = True
    watch_dog_thread.start()
else:
    print("获取锁失败")

这个看门狗线程会每隔 expire_time // 3 秒检查一次锁是否还被当前进程持有,如果是,则延长锁的过期时间。