MST

星途 面试题库

面试题:如何在高并发且复杂业务场景下设计并优化Redis分布式锁以保证性能与可靠性

假设存在一个高并发且业务逻辑复杂的系统,需要使用Redis分布式锁保证数据一致性和业务流程的正确性。请设计一套完整的Redis分布式锁方案,并详细说明如何进行性能优化和可靠性保障,同时要考虑到锁的可重入性、锁超时等问题。
23.3万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

Redis分布式锁方案设计

  1. 加锁
    • 使用 SETNX(SET if Not eXists)命令,示例如下:
    import redis
    
    r = redis.Redis(host='localhost', port=6379, db = 0)
    lock_key = "your_lock_key"
    lock_value = "unique_value_for_lock"
    lock_acquired = r.setnx(lock_key, lock_value)
    if lock_acquired:
        # 加锁成功,执行业务逻辑
        pass
    else:
        # 加锁失败,处理等待或重试逻辑
        pass
    
    • 为了保证锁的可重入性,当一个线程再次获取它已经持有的锁时,不应该被视为新的锁获取。可以在 lock_value 中加入线程标识等信息,每次获取锁时检查是否是自己已经持有锁,如果是则增加持有计数。例如:
    if lock_acquired:
        r.hset(lock_key, "holder_thread", threading.current_thread().ident)
        r.hset(lock_key, "hold_count", 1)
    else:
        current_holder = r.hget(lock_key, "holder_thread")
        if current_holder == threading.current_thread().ident:
            current_count = r.hget(lock_key, "hold_count")
            r.hset(lock_key, "hold_count", int(current_count) + 1)
            lock_acquired = True
    
  2. 解锁
    • 对于普通解锁,使用 DEL 命令删除锁键。但在可重入锁场景下,需要先检查持有计数。
    if lock_acquired:
        hold_count = r.hget(lock_key, "hold_count")
        if int(hold_count) == 1:
            r.delete(lock_key)
        else:
            r.hset(lock_key, "hold_count", int(hold_count) - 1)
    

性能优化

  1. 减少网络开销
    • 批量操作:尽量将多个 Redis 操作合并为一个批量操作,例如使用 pipeline。在Python中:
    pipe = r.pipeline()
    pipe.setnx(lock_key, lock_value)
    pipe.hset(lock_key, "holder_thread", threading.current_thread().ident)
    pipe.hset(lock_key, "hold_count", 1)
    results = pipe.execute()
    
    • 长连接:使用连接池来复用 Redis 连接,减少连接创建和销毁的开销。在Python中,redis - py 库默认使用连接池。
  2. 优化锁的粒度
    • 细分锁:根据业务逻辑,将大的锁细分为多个小的锁,减少锁的竞争。例如,在一个电商系统中,如果有商品库存扣减和订单创建两个操作,可以为商品库存扣减设置一个锁,为订单创建设置另一个锁。

可靠性保障

  1. 锁超时
    • 设置合理的超时时间:在加锁时使用 SET key value ex seconds 形式,既设置锁的值又设置超时时间,防止死锁。例如:
    lock_acquired = r.set(lock_key, lock_value, ex = 10)
    
    • 自动续期:对于业务执行时间可能较长的情况,可以使用 Redisson 等框架,它提供了锁自动续期功能。在业务执行过程中,当锁快过期时,框架会自动延长锁的有效期。
  2. 故障处理
    • 主从复制:部署 Redis 主从集群,当主节点发生故障时,从节点可以晋升为主节点继续提供服务。但要注意主从复制可能存在数据同步延迟问题,可能导致短暂的锁一致性问题。
    • Redlock 算法:使用 Redlock 算法,通过向多个独立的 Redis 实例获取锁,当大多数实例都获取到锁时,才认为锁获取成功。这样即使某个 Redis 实例发生故障,也能保证锁的可靠性。在Python中,可以使用 redlock - py 库实现 Redlock。例如:
    from redlock import Redlock
    
    # 创建 Redlock 实例
    redlock = Redlock(
        resource="your_resource_name",
        connection_details=[
            {"host": "localhost", "port": 6379, "db": 0},
            {"host": "localhost", "port": 6380, "db": 0},
            {"host": "localhost", "port": 6381, "db": 0}
        ]
    )
    # 获取锁
    lock_acquired = redlock.lock()
    if lock_acquired:
        try:
            # 执行业务逻辑
            pass
        finally:
            redlock.unlock()