返回

Redis集群中的分布式锁实践

后端

分布式锁在 Redis 集群中的实践探索

分布式系统中,资源访问冲突时,分布式锁 扮演着同步机制的角色,确保数据的 一致性和完整性 。Redis 集群以其可靠性成为实现分布式锁的不二之选。

分布式锁的基本概念

分布式锁是一种同步机制,保证 互斥访问 共享资源,主要需求如下:

  • 排他性: 同一时刻,只有一个进程/线程能持有锁。
  • 可重入性: 同一进程/线程可多次获取同一锁。
  • 可用性: 锁可被获取和释放。
  • 可靠性: 进程/线程崩溃时,锁可释放。
  • 性能: 锁操作高效。

Redis 集群中的分布式锁实践

SETNX 实现简单锁

最常见的是使用 SETNX 命令:

SETNX my_lock 1

如果 my_lock 键不存在,则设置值为 1 并返回 1;否则返回 0。进程/线程尝试获取锁时,执行 SETNX。成功获取返回 1,否则等待锁释放。

为了 防止死锁 ,需要设置超时:

EXPIRE my_lock 30

超时后,锁自动释放。

Redlock 算法增强健壮性

Redlock 算法使用 多个 Redis 实例 提高健壮性。

  1. 客户端随机选择多个 Redis 实例。
  2. 向每个实例发送 SETNX 命令尝试获取锁。
  3. 超过半数实例获取锁后,视为成功。
  4. 设置锁超时时间。
  5. 释放锁时,向每个实例发送 DEL 命令。

即使一个或多个实例宕机,锁仍然有效。

代码示例

使用 Python redis-py 库实现 Redlock 锁:

import redis
import random

# 创建 Redis 集群连接池
redis_cluster = redis.StrictRedisCluster(...)

# Redlock 锁参数
num_instances = 5  # Redis 实例数量
quorum = num_instances // 2 + 1  # 超过半数实例

# 获取锁
def acquire_lock(key, ttl):
    clients = random.sample(redis_cluster.nodes, num_instances)
    locks = {}
    for client in clients:
        lock_name = f'{key}-{client.host}-{client.port}'
        if client.setnx(lock_name, 1):
            locks[lock_name] = client.ttl(lock_name)  # 锁超时时间
            if len(locks) >= quorum:
                return True
    # 释放已获取锁
    for lock_name, ttl in locks.items():
        client.delete(lock_name)
    return False

# 释放锁
def release_lock(key):
    for client in redis_cluster.nodes:
        lock_name = f'{key}-{client.host}-{client.port}'
        client.delete(lock_name)

常见问题解答

  1. 为什么需要分布式锁?
    为了防止分布式系统中资源访问冲突,确保数据一致性。

  2. 为什么使用 Redis 集群?
    提供可靠性、高可用性和可扩展性。

  3. Redlock 算法的优点是什么?
    提高健壮性,即使一个或多个 Redis 实例宕机也能保证锁的有效性。

  4. 如何防止死锁?
    设置锁超时时间,以在进程/线程崩溃时自动释放锁。

  5. 如何选择锁的超时时间?
    考虑业务场景,超时时间应足够长以完成操作,但又足够短以防止锁长时间占用。