跳到主要内容

分布式锁实现

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向 yudao-cloud 的分布式锁实现,系统性阐述 Redis 分布式锁与数据库锁(通过 Lock4j + Redisson)两种技术路径的差异与适用场景;详解 Lock4j 框架的使用方法与 @DistributedLock 注解的参数配置及锁粒度控制;给出分布式锁在事务处理中的应用策略(乐观锁与悲观锁选择);并提供性能优化方案(锁超时、死锁检测、自动续期)与异常处理、锁释放策略,以保障数据一致性与操作可靠性。

项目结构

围绕分布式锁能力,yudao-cloud 在以下模块中提供了关键实现与配置:

  • Redis 工具层:提供基于 Redis 的原生分布式锁工具类,支持加锁、解锁与可重试获取。
  • Lock4j 保护层:集成开源 Lock4j 与 Redisson,提供注解式分布式锁能力,并自定义失败策略。
  • 示例与使用:规则模块的 Kafka 消费者展示了本地队列+锁的组合使用模式。

Mermaid Diagram Code:

graph TB
subgraph "框架层"
REDIS["Redis 工具<br/>RedisDistributionLockUtils"]
LOCK4J_CFG["Lock4j 配置<br/>YudaoLock4jConfiguration"]
LOCK4J_FAIL["失败策略<br/>DefaultLockFailureStrategy"]
LOCK4J_KEYS["Redis Key 常量<br/>Lock4jRedisKeyConstants"]
end
subgraph "业务层"
RULE_CONSUMER["规则业务消费者<br/>RuleBusinessLimitConsumer"]
end
RULE_CONSUMER --> REDIS
RULE_CONSUMER --> LOCK4J_CFG
LOCK4J_CFG --> LOCK4J_FAIL
LOCK4J_CFG --> LOCK4J_KEYS

图示来源

章节来源

核心组件

  • Redis 分布式锁工具类:提供基于 Redis 的 setNx + 过期时间的原子加锁,以及基于当前值匹配的安全解锁;支持带等待时间的可重试获取。
  • Lock4j 集成:通过配置类注册自定义失败策略,统一在锁获取失败时抛出业务异常;Redis Key 常量定义了锁键命名规范。
  • 业务使用示例:规则模块消费者在 Kafka 消费失败时,采用本地队列兜底+重试+锁的组合策略,提升可靠性。

章节来源

架构总览

下图展示 Redis 原生锁与 Lock4j(基于 Redisson)两种实现的交互关系与职责边界:

Mermaid Diagram Code:

graph TB
CLIENT["业务服务/控制器"] --> API["业务接口"]
API --> LOCK4J_ANN["@DistributedLock 注解<br/>Lock4j"]
API --> REDIS_UTIL["Redis 工具<br/>RedisDistributionLockUtils"]
LOCK4J_ANN --> REDIS_KEY["Redis Key 常量<br/>LOCK4J"]
LOCK4J_ANN --> FAIL_STRATEGY["失败策略<br/>DefaultLockFailureStrategy"]
REDIS_UTIL --> STRING_RT["StringRedisTemplate"]

图示来源

详细组件分析

组件一:Redis 分布式锁工具类

  • 加锁:基于 Redis 的 setIfAbsent(key, value, expire) 实现原子加锁;若成功返回 true,否则 false。
  • 解锁:先读取当前值,仅当与期望值相等时才删除 key,避免误删他人持有的锁。
  • 可重试获取:在指定等待时间内循环尝试加锁,每次间隔固定时间,提升获取成功率。

Mermaid Diagram Code:

flowchart TD
START(["进入 tryLock"]) --> CALC["计算结束时间"]
CALC --> LOOP{"是否到达结束时间?"}
LOOP --> |否| TRY_LOCK["尝试加锁"]
TRY_LOCK --> SUCCESS{"加锁成功?"}
SUCCESS --> |是| RETURN_TRUE["返回 true"]
SUCCESS --> |否| SLEEP["休眠固定时长"] --> LOOP
LOOP --> |是| RETURN_FALSE["返回 false"]

图示来源

章节来源

组件二:Lock4j 注解与配置

  • 注解使用:通过 @DistributedLock(由 Lock4j 提供)在方法上声明分布式锁,结合 Key 构建策略实现细粒度控制。
  • 失败策略:自定义 DefaultLockFailureStrategy,在锁获取失败时统一抛出业务异常,便于上层统一处理。
  • 配置加载:YudaoLock4jConfiguration 在 LockAutoConfiguration 前置加载,确保失败策略生效。
  • Redis Key 规范:Lock4jRedisKeyConstants 定义了统一的键前缀与命名格式,便于运维与排障。

Mermaid Diagram Code:

sequenceDiagram
participant Caller as "调用方"
participant Service as "业务方法"
participant Lock4j as "@DistributedLock"
participant Strategy as "DefaultLockFailureStrategy"
participant Redis as "Redis"
Caller->>Service : 调用被锁保护的方法
Service->>Lock4j : 进入注解切面
Lock4j->>Redis : 尝试获取分布式锁
alt 获取成功
Redis-->>Lock4j : 成功
Lock4j-->>Service : 执行业务逻辑
Service-->>Caller : 返回结果
else 获取失败
Redis-->>Lock4j : 失败
Lock4j->>Strategy : 触发失败策略
Strategy-->>Caller : 抛出业务异常
end

图示来源

章节来源

组件三:业务使用示例(规则模块)

  • 场景:Kafka 消费到规则业务限流事件,优先尝试加锁并处理;若失败则放入本地队列,由后台线程轮询重试。
  • 目的:在高并发下降低对共享资源的竞争,同时通过本地队列兜底保证最终一致性。

Mermaid Diagram Code:

sequenceDiagram
participant Kafka as "Kafka 消费者"
participant LocalQ as "本地队列"
participant Worker as "本地队列消费者线程"
Kafka->>Kafka : 消费事件
Kafka->>Kafka : 尝试加锁
alt 加锁成功
Kafka->>Kafka : 处理业务
else 加锁失败
Kafka->>LocalQ : 放入本地队列
Worker->>LocalQ : 轮询取出
Worker->>Worker : 再次尝试加锁
alt 成功
Worker->>Worker : 处理业务
else 失败
Worker->>LocalQ : 重新入队或丢弃
end
end

图示来源

章节来源

依赖关系分析

  • Lock4j 配置类依赖 LockAutoConfiguration,确保在 Lock4j 自动装配之前注册自定义失败策略。
  • 失败策略依赖全局业务异常常量,统一错误码与语义。
  • Redis 工具类依赖 Spring 上下文中的 StringRedisTemplate,用于与 Redis 通信。
  • 业务消费者同时依赖 Redis 工具类与 Lock4j 注解能力,形成“原生锁 + 注解锁”的双通道。

Mermaid Diagram Code:

graph LR
YUDAO_CFG["YudaoLock4jConfiguration"] --> FAIL_STRAT["DefaultLockFailureStrategy"]
FAIL_STRAT --> GLOBAL_ERR["GlobalErrorCodeConstants"]
REDIS_UTIL["RedisDistributionLockUtils"] --> STRING_RT["StringRedisTemplate"]
RULE_CONSUMER["RuleBusinessLimitConsumer"] --> REDIS_UTIL
RULE_CONSUMER --> YUDAO_CFG

图示来源

章节来源

性能考虑

  • 锁超时与租约:Redis 原生锁通过过期时间避免死锁;建议根据业务最长执行时间设置合理租约,避免过短导致频繁重试、过长导致资源占用。
  • 可重试策略:在 tryLock 中设置合理的等待时长与休眠间隔,平衡吞吐与延迟。
  • 自动续期:Lock4j 基于 Redisson 的看门狗机制可实现自动续期,避免业务未完成但锁已过期的情况。
  • 锁粒度控制:通过 @DistributedLock 的 key 构建策略,将锁粒度细化到业务实体维度,减少不必要的串行化。
  • 并发与抖动:在高并发场景下,建议引入退避重试与限流,避免热点竞争导致的抖动。

[本节为通用性能指导,无需列出具体文件来源]

故障排查指南

  • 锁获取失败:检查失败策略是否触发,确认异常栈中的错误码与上下文信息;核对锁键命名与租约时间。
  • 误删锁:确认解锁时的当前值匹配逻辑,避免不同实例间的误删。
  • 死锁与长时间占用:启用自动续期与合理租约时间;对超时任务进行告警与熔断。
  • 业务异常处理:结合幂等注解(Idempotent)与分布式锁,确保异常时的清理与补偿。

章节来源

结论

yudao-cloud 提供了两条分布式锁路径:Redis 原生工具类适合轻量、明确的加解锁场景;Lock4j 注解式能力适合复杂业务的统一治理与失败策略标准化。结合自动续期、合理的锁粒度与超时策略,可在高并发下兼顾性能与可靠性;配合异常处理与幂等设计,进一步保障数据一致性与系统稳定性。

[本节为总结性内容,无需列出具体文件来源]

附录

A. Redis 分布式锁与数据库锁的技术差异与适用场景

  • Redis 分布式锁
    • 优点:实现简单、性能高、支持自动续期;适合高并发、低延迟场景。
    • 注意:需关注网络分区、时钟漂移与误删风险,建议使用带值匹配的解锁与合理租约。
  • 数据库锁(Lock4j + Redisson)
    • 优点:具备成熟的分布式锁能力与自动续期;注解式使用降低侵入性。
    • 注意:依赖 Redis 与 Redisson,需评估集群可用性与网络开销。

[本节为概念性对比,无需列出具体文件来源]

B. @DistributedLock 注解参数与锁粒度控制

  • 关键参数(示意)
    • key:锁键表达式,建议唯一标识业务实体。
    • leaseTime:锁租约时间,应覆盖业务最长执行时间。
    • waitTime:最大等待时间,决定可重试窗口。
    • unit:时间单位。
  • 锁粒度控制
    • 将 key 构建为“业务域:业务ID”形式,避免跨业务干扰。
    • 对热点资源采用分段锁或随机后缀,降低争用。

[本节为使用指导,无需列出具体文件来源]

C. 事务处理中的锁策略:乐观锁与悲观锁

  • 乐观锁:适用于冲突概率较低的读多写少场景,通过版本号或时间戳判断冲突。
  • 悲观锁:适用于强一致性与高冲突场景,通过数据库行级锁或分布式锁阻塞并发。
  • 在 yudao-cloud 中,可结合 Redis 原生锁与 Lock4j 注解,按业务特性灵活选择。

[本节为通用策略说明,无需列出具体文件来源]

用户文档
AI 助手
Agent 列表
请选择一个 Agent 开始对话
AI 问答