实现分布式锁

分布式锁需要解决的问题

  • 互斥性
    • 任一时刻,只能有一个客户端获取锁
  • 安全性
    • 锁只能由持有的客户端删除
  • 死锁
    • 避免某些客户端因宕机等原因未能释放锁,而其他客户端再也无法获取该锁
  • 容错
    • 当部分节点宕机后客户端应仍然能够获取锁和释放锁

如何通过Redis实现分布式锁

方案一(不推荐)

SETNX key value :如果key不存在,创建并赋值

  • 时间复杂度O(1)
  • 返回值:key不存在,设置成功,返回1,key存在则失败返回0

因为setnx是原子的又有以上特性,初期被用来实现分布式锁

执行某段代码时先尝试使用SETNX对某个key设值,如果设置成功,则证明没有别的线程在执行该段代码。

如何解决SETNX长期有效的问题?

EXPIRE key secons

  • 设置key的生存时间,当key过期时会被自动删除

此方法的问题

如果一个线程设置了key还没来得及设置过期时间就宕机了,就会发生死锁

主要原因就是原子性不能得到满足

方案二

SETNXEXPIRE放在一块执行

SET key value [EX seconds] [PX milliseconds] [NX|XX]

  • EX seconds:设置键值对过期时间为seconds秒

  • PX milliseconds:设置键值对过期时间为milliseconds毫秒

  • NX:只在键不存在时才对键进行设置操作,效果等同SETNX

  • XX:只在键已在时才对键进行设置操作,与SETNX相反

  • SET操作完成时返回OK,否则返回nil

这样可以保证操作的原子性

大量key同时过期的注意事项

集中过期,由于清楚大量的key很耗时,会出现短暂卡顿现象

  • 解决方法:在设置key的过期时间时,给每个key加一个随机值