分布式锁定义

  • 分布式环境下,锁定全局唯一资源

    • 请求处理串行化
    • 实现表现互斥锁

      分布式锁目的

  • 交易订单锁定

    • 防止重复下单
    • 解决业务层幂等问题
  • MQ消息消费幂等性

    • 发送消息重复
    • 消息消费去重

      高可用分布式锁设计目标

  • 强一致性

  • 服务高可用,系统稳健
  • 锁必须是可重入的(避免死锁)
  • 锁字段续约及其自动释放
  • 可视化管理后台,监控及管理

应用场景

  • 保证数据库可靠性(转账)
  • 分布式缓存更新问题
  • 分布式中任务领取问题

分布式锁方案比较

分布式锁介绍 - 图1

基于Redis分布式锁方案

  • 唯一线程串行处理
  • 实现方式

    • 锁的获取使用set命令实现,需要使用一条命令实现生成和设置过期时间来保证原子性。

      1. private static final String SET_IF_NOT_EXIST = "NX";
      2. private static final String SET_WITH_EXPIRE_TIME = "PX";
      3. //@param jedis Redis客户端
      4. //@param lockKey 锁
      5. //@param requestId 请求标识
      6. //@param expireTime 超期时间
      7. jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
    • 锁的释放:需要一条命令完成保证原子性,但是需要先判断是否是当前线程持有的锁,然后才能执行删除。

      • 使用lua脚本来完成
  1. //lua脚本
  2. String script="if redis.call('get', KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
  3. Object result=jedis.eval(script, Collections.singletonList(lockKey),
  4. Collections.singletonList(requestId));
  • 存在问题:
    • 锁时间不可控
      • 无法续租期
    • 单点问题
      • 单实例存在进程一旦死掉,会彻底阻塞业务流程
      • 主从方式,主从数据异步,会存在同步数据时候锁失效的问题
    • 官方建议
      • Redis本身建议使用Redlock算法来保证,但是问题是需要至少三个Redis主从实例来完成,维护成本相对较高。Redlock等同于自己实现简单的一致性协议,细节繁琐,容易出错

基于ETCD分布式锁方案

为什么选择ETCD:

  • 简单kv强一致性
  • 高可用,无单点
  • 数据高可靠
    • 持久化

分布式锁介绍 - 图2
分布式锁介绍 - 图3
分布式锁介绍 - 图4