分布式锁实现及常见问题

分布式锁介绍

对于平台系统,由于系统是集群模式,每个节点都是无状态模式,提供统一的功能,所以无法使用JVM的锁,需要使用分布式锁保证所有机器只有一个在执行

由于分布式锁一般是通过其他机器或进程(redis,zk,mysql等)来记录状态所以需要有的特性

  • 并发获取锁时只能一个服务获取一个锁
  • 业务服务挂掉后,锁最终也可以被释放
  • 业务需要避免提前释放锁的问题
  • 锁记录的服务节点挂掉后可以保证锁的一致性
  • 锁释放后其他服务可以获取锁
  • 锁释放时不会错误释放

分布式锁实现方式

redis实现

加锁

  • 通过redis的命令jedis.set(key, value, nxxx, expx, time)来实现加锁(value为当前机器和线程的信息)
  • redis的key为锁的信息,value为当前机器和线程的信息,如:主机IP+线程ID(172.16.1.1:100)
  • redis的超时根据业务来订(如果有锁的续租,需要有统一的最小时间)
  • 获取琐时不断的重试,知道超出等待时间
  • 获取琐时判断value值是否和当前线程的一致,来实现可重入

解锁

  • 通过lua脚本进行解锁
  • lua脚本中应该包含两条指令,判断value值是否和当前线程的值一至,将锁删除

zk实现

加锁

  • 在/xxxLock下创建临时的且有序的子节点
  • 客户端获取/xxxLock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通知后重复此步骤直至获得锁

解锁

  • 完成业务流程后,删除对应的子节点释放锁

对比

Redis为AP模式,可能存在获取到多把锁,比如在主从切换时,Zk为CP架构,不会存在获取到多把锁,因为在创建节点时会同步给半数节点。redis分布式锁相对更快

常见问题

redis锁的问题

获取锁后节点宕机

设置锁的超时时间,宕机后只会影响一定的时间

可重入

获取锁时判断设置的值是否和当前线程的信息一样

锁到期后还没执行完

使用watchDog进行续租

主从节点切换

  • 强制同步从节点,会有性能问题
  • 红锁解决(也会有性能问题)

ZK锁的问题

极端情况下,节点1获取到了锁,发送修改了值的请求,请求已经发送出去,但是还没有发送到资源服务器,此时节点1断开了ZK连接,节点2拿到了锁,也发送了修改值的命令,资源服务器先收到节点2的请求,之后又收到了节点1的请求就会出错

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容