分布式锁

分布式锁
  • 单体应用,所有请求都会分配到当前服务器的JVM内部,然后映射为操作系统的线程进行处理,这个共享变量只是这个JVM内部的一快空间。
  • 单机环境可java自带的apiReentrantLock或Synchronize进行互斥控制。
  • 集群要部署到多个服务器,变量在多个JVM的内存区域,不具备可见性。需要跨JVM的互斥操作。

    分布式锁条件
  • 分布式环境下,一个方法同一时间只能被一个机器的一个线程执行。

  • 高可用。
  • 高性能。
  • 可重入。
  • 锁失效机制,防止死锁。
  • 非阻塞即没获取到锁直接返回失败。

    三种实现方式
  • 分布式C一致性A可用性P分区容错性理论,只能满足两项。

  • 基于数据库的排他锁。
    • 新建表,插入唯一性约束
    • 新建表,更改字段
    • 缺:数据库单点,没有失效时间,非阻塞,非可重入。
  • 基于缓存(Redis)实现。
    • Boolean lock = setIfAbsent(lockKey,LOCK);//获取锁
    • expire(lockKey,1,TimeUnit.MINUTES);//过期时间
    • 缺:主从下,master获取锁,master宕机,slaver晋升master,安全失效。
  • ZK实现。
    • ZK数据存储结构类似树,由节点组成,
      • 持久节点:默认,节点客户端与zk断开后,依旧存在。
      • 持久顺序节点:创建时,根据时间给节点进行编号。
      • 临时节点:和持久节点相反,断开后消失。
      • 临时顺序节点:结合临时和顺序节点的特点。
    • zk分布式锁原理:用到了临时顺序节点。
      • 获取锁:创建持久节点ParentLock,第一个客户端想要获取锁,需要在ParentLock节点下创建一个临时顺序节点Lock1,之后客户端查找临时顺序节点并排序,若式第一个节点就获取锁。客户端2获取同理,若排序不是第一个,客户端2向前面节点注册Watcher监听,这是意味着客户端2枪锁失败,进入等待。
      • 释放锁
        • 情景1,任务完成,客户端调用删除节点指令。
        • 情景2,客户端崩溃,断开与zk的连接,根据临时节点特性自动删除。若有watcher,接到通知。
    • 缺点:性能没有缓存高,并发问题,由于网络抖动导致的session中断,zk会以为客户端挂了让其他获取锁,导致问题(这个问题不常见因心跳重试机制)。

分布式锁(zk应用)

来源:com/zking/dp/sales/core/management/util/RedisLock.java:146

  • 思路
  • 获得lock
    • 用了setnx命令,缓存锁。
    • redis缓存的key是锁的key,共享,value是到期时间(注意:这里把过期时间放在value了,没有时间上设置其超时时间)
  • 执行过程
    • 通过setnx尝试设置某key的值,成功(当前没有这个锁)则返回,获取到锁。
    • 锁已经存在则获取锁的到期时间,和当前时间比较,超时的话,则设置新的值。

缓存
  • 订单信息

    幂等校验
  • 报价的时候不允许核保