Spring Boot + Redis + Redisson 分布式锁深度实战:高并发抢单与库存防超卖全方案(6000字终极指南)
一、分布式锁核心原理深度解析
1.1 分布式锁的本质需求
1.2 Redis分布式锁实现原理
SET lock_key unique_value NX PX 30000
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
1.3 Redisson分布式锁优势
| 特性 |
原生Redis实现 |
Redisson实现 |
优势说明 |
| 锁续期 |
手动实现 |
自动看门狗 |
避免业务未完成锁过期 |
| 可重入 |
不支持 |
支持 |
同一线程可多次加锁 |
| 公平锁 |
不支持 |
支持 |
按请求顺序获取锁 |
| 红锁 |
复杂实现 |
内置支持 |
多节点容错 |
| 锁状态 |
需额外实现 |
完善API |
监控更方便 |
1.4 锁类型选择矩阵
| 场景 |
推荐锁类型 |
原因 |
| 抢购活动 |
非公平锁 |
性能优先 |
| 订单支付 |
公平锁 |
防止资源抢占 |
| 库存扣减 |
可重入锁 |
支持嵌套调用 |
| 金融交易 |
红锁 |
最高安全性 |
| 数据迁移 |
读写锁 |
读写分离 |
二、环境搭建与深度配置
2.1 完整依赖配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.24.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
2.2 高级Redisson配置
spring:
redis:
host: redis-cluster.example.com
port: 6379
password: securePassword123!
database: 0
lettuce:
pool:
max-active: 100
max-idle: 50
min-idle: 10
max-wait: 3000
redisson:
config: |
clusterServersConfig:
nodeAddresses:
- "redis://redis-node1:6379"
- "redis://redis-node2:6379"
- "redis://redis-node3:6379"
scanInterval: 2000 # 集群状态扫描间隔
slaveConnectionMinimumIdleSize: 24
slaveConnectionPoolSize: 64
masterConnectionMinimumIdleSize: 24
masterConnectionPoolSize: 64
readMode: "SLAVE" # 读写分离
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
threads: 16
nettyThreads: 32
transportMode: "EPOLL" # Linux高性能模式
lockWatchdogTimeout: 30000 # 看门狗超时时间
useScriptCache: true # 启用脚本缓存
2.3 多环境配置策略
@Configuration
public class RedissonConfig {
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(
@Value("${spring.redis.host}") String host,
@Value("${spring.redis.port}") int port,
@Value("${spring.redis.password}") String password,
@Value("${spring.profiles.active}") String profile) {
Config config = new Config();
if ("prod".equals(profile)) {
config.useClusterServers()
.addNodeAddress("redis://" + host + ":" + port)
.setPassword(password)
.setPingConnectionInterval(1000);
} else {
config.useSingleServer()
.setAddress("redis://" + host + ":" + port)
.setPassword(password)
.setConnectionPoolSize(64);
}
return Redisson.create(config);
}
}
三、分布式锁工具类深度封装
3.1 高级锁工具类
@Component
@Slf4j
public class DistributedLockUtil {
private final RedissonClient redissonClient;
private final MeterRegistry meterRegistry;
public DistributedLockUtil(RedissonClient redissonClient, MeterRegistry meterRegistry) {
this.redissonClient = redissonClient;
this.meterRegistry = meterRegistry;
}
public <T> T executeWithLock(String lockKey, int waitTime, int leaseTime,
TimeUnit unit, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
boolean locked = false;
Timer.Sample timer = Timer.start(meterRegistry);
try {
locked = lock.tryLock(waitTime, leaseTime, unit);
if (locked) {
meterRegistry.timer("distributed.lock.wait")
.record(System.nanoTime() - timer.startTime(), TimeUnit.NANOSECONDS);
return supplier.get();
} else {
meterRegistry.counter("distributed.lock.fail", "lockKey", lockKey).increment();
throw new LockAcquisitionException("获取锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new LockAcquisitionException("锁获取被中断", e);
} finally {
if (locked && lock.isHeldByCurrentThread()) {
try {
lock.unlock();
meterRegistry.counter("distributed.lock.success").increment();
} catch (IllegalMonitorStateException e) {
log.warn("锁状态异常,可能已自动释放", e);
}
}
}
}
public <T> T executeWithReentrantLock(String lockKey, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
try {
return supplier.get();
} finally {
if (lock.isHeldByCurrentThread() && lock.getHoldCount() > 0) {
lock.unlock();
}
}
}
public <T> T executeWithFairLock(String lockKey, int waitTime, Supplier<T> supplier) {
RLock lock = redissonClient.getFairLock(lockKey);
try {
if (lock.tryLock(waitTime, -1, TimeUnit.SECONDS)) {
return supplier.get();
}
throw new LockAcquisitionException("获取公平锁失败");
} catch (InterruptedException e) {
throw new LockAcquisitionException("锁获取被中断", e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
public <T> T executeWithReadLock(String lockKey, Supplier<T> supplier) {
RReadWriteLock rwLock = redissonClient.getReadWriteLock(lockKey);
RLock lock = rwLock.readLock();
lock.lock();
try {
return supplier.get();
} finally {
lock.unlock();
}
}
public void executeWithWriteLock(String lockKey, Runnable runnable) {
RReadWriteLock rwLock = redissonClient.getReadWriteLock(lockKey);
RLock lock = rwLock.writeLock();
lock.lock();
try {
runnable.run();
} finally {
lock.unlock();
}
}
public <T> T executeWithRedLock(String lockKey, int waitTime, Supplier<T> supplier) {
RLock lock1 = redissonClient.getLock(lockKey + "_node1");
RLock lock2 = redissonClient.getLock(lockKey + "_node2");
RLock lock3 = redissonClient.getLock(lockKey + "_node3");
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
try {
if (redLock.tryLock(waitTime, -1, TimeUnit.SECONDS)) {
return supplier.get();
}
throw new LockAcquisitionException("获取红锁失败");
} catch (InterruptedException e) {
throw new LockAcquisitionException("锁获取被中断", e);
} finally {
redLock.unlock();
}
}
}
3.2 自定义锁异常体系
public class LockAcquisitionException extends RuntimeException {
public LockAcquisitionException(String message) {
super(message);
}
public LockAcquisitionException(String message, Throwable cause) {
super(message, cause);
}
}
public class LockOperationException extends RuntimeException {
public LockOperationException(String message) {
super(message);
}
}
四、库存防超卖深度实现
4.1 库存服务接口设计
public interface InventoryService {
boolean reduceInventory(Long productId, int quantity);
int getInventory(Long productId);
String reserveInventory(Long productId, int quantity, long expireSeconds);
boolean confirmReserve(String reserveToken);
void cancelReserve(String reserveToken);
}
4.2 Redis库存服务实现
@Service
@Slf4j
public class RedisInventoryServiceImpl implements InventoryService {
private final RedisTemplate<String, Integer> redisTemplate;
private final DistributedLockUtil lockUtil;
private final RedissonClient redissonClient;
private final InventoryRepository inventoryRepository;
private static final String INVENTORY_KEY = "inventory:";
private static final String RESERVE_KEY = "inventory_reserve:";
private static final String RESERVE_TOKEN_KEY = "reserve_token:";
@Override
public boolean reduceInventory(Long productId, int quantity) {
String lockKey = "lock:inventory:" + productId;
return lockUtil.executeWithLock(lockKey, 3, 30, TimeUnit.SECONDS, () -> {
String key = INVENTORY_KEY + productId;
Integer current = redisTemplate.opsForValue().get(key);
if (current == null) {
current = loadInventoryFromDB(productId);
redisTemplate.opsForValue().set(key, current);
}
if (current < quantity) {
log.warn("库存不足: productId={}, current={}, required={}", productId, current, quantity);
return false;
}
redisTemplate.opsForValue().decrement(key, quantity);
CompletableFuture.runAsync(() ->
inventoryRepository.reduceInventory(productId, quantity));
return true;
});
}
@Override
public String reserveInventory(Long productId, int quantity, long expireSeconds) {
String lockKey = "lock:inventory_reserve:" + productId;
String reserveToken = UUID.randomUUID().toString();
boolean success = lockUtil.executeWithLock(lockKey, 3, 30, TimeUnit.SECONDS, () -> {
String key = INVENTORY_KEY + productId;
Integer current = redisTemplate.opsForValue().get(key);
if (current == null) {
current = loadInventoryFromDB(productId);
redisTemplate.opsForValue().set(key, current);
}
if (current < quantity) {
return false;
}
redisTemplate.opsForValue().decrement(key, quantity);
String reserveKey = RESERVE_KEY + reserveToken;
Map<String, Object> reserveInfo = new HashMap<>();
reserveInfo.put("productId", productId);
reserveInfo.put("quantity", quantity);
reserveInfo.put("expireAt", System.currentTimeMillis() + expireSeconds * 1000);
redisTemplate.opsForHash().putAll(reserveKey, reserveInfo);
redisTemplate.expire(reserveKey, expireSeconds + 60, TimeUnit.SECONDS);
redisTemplate.opsForValue().set(RESERVE_TOKEN_KEY + reserveToken, reserveKey,
expireSeconds + 60, TimeUnit.SECONDS);
return true;
});
return success ? reserveToken : null;
}
@Override
public boolean confirmReserve(String reserveToken) {
String tokenKey = RESERVE_TOKEN_KEY + reserveToken;
String reserveKey = (String) redisTemplate.opsForValue().get(tokenKey);
if (reserveKey == null) {
throw new InventoryException("预占记录不存在或已过期");
}
Map<Object, Object> reserveInfo = redisTemplate.opsForHash().entries(reserveKey);
if (reserveInfo.isEmpty()) {
throw new InventoryException("预占记录不存在");
}
Long productId = Long.parseLong(reserveInfo.get("productId").toString());
int quantity = Integer.parseInt(reserveInfo.get("quantity").toString());
redisTemplate.delete(reserveKey);
redisTemplate.delete(tokenKey);
CompletableFuture.runAsync(() ->
orderService.createOrderFromReserve(productId, quantity, reserveToken));
return true;
}
@Override
public void cancelReserve(String reserveToken) {
String tokenKey = RESERVE_TOKEN_KEY + reserveToken;
String reserveKey = (String) redisTemplate.opsForValue().get(tokenKey);
if (reserveKey == null) {
log.warn("预占记录不存在: token={}", reserveToken);
return;
}
Map<Object, Object> reserveInfo = redisTemplate.opsForHash().entries(reserveKey);
if (reserveInfo.isEmpty()) {
log.warn("预占记录已失效: token={}", reserveToken);
return;
}
Long productId = Long.parseLong(reserveInfo.get("productId").toString());
int quantity = Integer.parseInt(reserveInfo.get("quantity").toString());
String inventoryKey = INVENTORY_KEY + productId;
redisTemplate.opsForValue().increment(inventoryKey, quantity);
redisTemplate.delete(reserveKey);
redisTemplate.delete(tokenKey);
}
@Scheduled(fixedRate = 60000)
public void cleanExpiredReserves() {
Set<String> keys = redisTemplate.keys(RESERVE_KEY + "*");
long now = System.currentTimeMillis();
for (String key : keys) {
Long expireAt = (Long) redisTemplate.opsForHash().get(key, "expireAt");
if (expireAt != null && expireAt < now) {
String token = key.substring(RESERVE_KEY.length());
cancelReserve(token);
}
}
}
}
4.3 库存防超卖策略对比
| 策略 |
实现复杂度 |
性能 |
适用场景 |
缺点 |
| 悲观锁 |
低 |
中 |
低并发场景 |
高并发下性能差 |
| 乐观锁 |
中 |
高 |
冲突较少场景 |
重试逻辑复杂 |
| 分布式锁 |
高 |
高 |
高并发场景 |
实现复杂 |
| 预占库存 |
高 |
极高 |
秒杀场景 |
状态管理复杂 |
| 队列削峰 |
中 |
极高 |
极端高并发 |
延迟较高 |
五、抢单业务深度实现
5.1 抢单服务核心逻辑
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
private final InventoryService inventoryService;
private final DistributedLockUtil lockUtil;
private final OrderRepository orderRepository;
private final IdGenerator idGenerator;
private final RateLimiter rateLimiter;
@Override
public Order createOrder(Long userId, Long productId, int quantity) {
if (!rateLimiter.tryAcquire()) {
throw new RateLimitException("系统繁忙,请稍后再试");
}
String lockKey = "order:create:" + userId + ":" + productId;
return lockUtil.executeWithLock(lockKey, 2, 10, TimeUnit.SECONDS, () -> {
if (orderRepository.existsByUserIdAndProductId(userId, productId)) {
throw new OrderException("请勿重复下单");
}
if (!inventoryService.reduceInventory(productId, quantity)) {
throw new InventoryException("库存不足");
}
Order order = new Order();
order.setId(idGenerator.nextId());
order.setUserId(userId);
order.setProductId(productId);
order.setQuantity(quantity);
order.setStatus(OrderStatus.CREATED);
orderRepository.save(order);
eventPublisher.publishEvent(new OrderCreatedEvent(order));
return order;
});
}
@Override
public Order fastCreateOrder(Long userId, Long productId, int quantity) {
if (!rateLimiter.tryAcquire()) {
throw new RateLimitException("系统繁忙,请稍后再试");
}
String reserveToken = inventoryService.reserveInventory(productId, quantity, 900);
if (reserveToken == null) {
throw new InventoryException("库存不足");
}
try {
Order order = new Order();
order.setId(idGenerator.nextId());
order.setUserId(userId);
order.setProductId(productId);
order.setQuantity(quantity);
order.setStatus(OrderStatus.PENDING);
order.setReserveToken(reserveToken);
orderRepository.save(order);
CompletableFuture.runAsync(() ->
inventoryService.confirmReserve(reserveToken));
return order;
} catch (Exception e) {
inventoryService.cancelReserve(reserveToken);
throw e;
}
}
@Override
@Transactional
public void confirmOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new OrderException("订单不存在"));
if (order.getStatus() != OrderStatus.PENDING) {
throw new OrderException("订单状态异常");
}
if (order.getReserveToken() != null) {
inventoryService.confirmReserve(order.getReserveToken());
}
order.setStatus(OrderStatus.COMPLETED);
orderRepository.save(order);
eventPublisher.publishEvent(new OrderCompletedEvent(order));
}
}
5.2 幂等性处理设计
@Aspect
@Component
@Slf4j
public class IdempotentAspect {
private final RedissonClient redissonClient;
private final RedisTemplate<String, String> redisTemplate;
@Around("@annotation(idempotent)")
public Object around(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {
String idempotentKey = generateIdempotentKey(joinPoint, idempotent);
RLock lock = redissonClient.getLock("lock:idempotent:" + idempotentKey);
lock.lock();
try {
if (redisTemplate.hasKey(idempotentKey)) {
throw new IdempotentException("重复请求");
}
Object result = joinPoint.proceed();
redisTemplate.opsForValue().set(
idempotentKey,
"processed",
idempotent.expireTime(),
TimeUnit.SECONDS
);
return result;
} finally {
lock.unlock();
}
}
private String generateIdempotentKey(ProceedingJoinPoint joinPoint, Idempotent idempotent) {
}
}
@PostMapping("/create")
@Idempotent(key = "#userId + ':' + #productId", expireTime = 3600)
public Order createOrder(@RequestParam Long userId, @RequestParam Long productId) {
}
六、Redisson高级特性深度应用
6.1 看门狗机制原理
6.2 红锁(RedLock)算法实现
public boolean tryRedLock(String lockKey, int waitTime, int leaseTime) {
RLock lock1 = redissonClient.getLock(lockKey + "_node1");
RLock lock2 = redissonClient.getLock(lockKey + "_node2");
RLock lock3 = redissonClient.getLock(lockKey + "_node3");
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
try {
boolean acquired = redLock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
if (acquired) {
int acquiredNodes = 0;
if (lock1.isHeldByCurrentThread()) acquiredNodes++;
if (lock2.isHeldByCurrentThread()) acquiredNodes++;
if (lock3.isHeldByCurrentThread()) acquiredNodes++;
return acquiredNodes >= 2;
}
return false;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
6.3 联锁(MultiLock)应用场景
public void transferInventory(Long fromProductId, Long toProductId, int quantity) {
RLock lock1 = redissonClient.getLock("inventory:" + fromProductId);
RLock lock2 = redissonClient.getLock("inventory:" + toProductId);
RLock multiLock = redissonClient.getMultiLock(lock1, lock2);
multiLock.lock();
try {
inventoryService.reduceInventory(fromProductId, quantity);
inventoryService.increaseInventory(toProductId, quantity);
} finally {
multiLock.unlock();
}
}
七、性能优化与防死锁深度策略
7.1 锁粒度优化方案
RLock globalLock = redissonClient.getLock("global_inventory_lock");
RLock productLock = redissonClient.getLock("inventory_lock:" + productId);
public boolean reduceInventorySegment(Long productId, int quantity) {
int segment = (int) (productId % 32);
String lockKey = "inventory_segment_lock:" + segment;
return lockUtil.executeWithLock(lockKey, 3, 10, TimeUnit.SECONDS, () -> {
});
}
7.2 死锁检测与预防
@Scheduled(fixedRate = 60000)
public void detectDeadLocks() {
Set<String> lockKeys = redissonClient.getKeys().getKeysByPattern("lock:*");
for (String lockKey : lockKeys) {
RLock lock = redissonClient.getLock(lockKey);
long holdTime = lock.remainTimeToLive();
if (holdTime == -1) {
long heldTime = System.currentTimeMillis() - lock.getLockHoldTime();
if (heldTime > 300000) {
log.warn("锁持有时间过长: {}, heldTime={}ms", lockKey, heldTime);
alertService.sendLockAlert(lockKey, heldTime);
}
} else if (holdTime > 60000) {
log.warn("锁可能未被释放: {}, remainTime={}ms", lockKey, holdTime);
}
}
}
public <T> T executeWithTimeoutLock(String lockKey, int waitTime, int maxHoldTime, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
boolean locked = false;
try {
locked = lock.tryLock(waitTime, maxHoldTime, TimeUnit.MILLISECONDS);
if (locked) {
return supplier.get();
}
throw new LockAcquisitionException("获取锁失败");
} catch (InterruptedException e) {
throw new LockAcquisitionException("锁获取被中断", e);
} finally {
if (locked && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
7.3 锁竞争监控指标
@Bean
public MeterRegistryCustomizer<MeterRegistry> lockMetrics(RedissonClient redissonClient) {
return registry -> {
Gauge.builder("redisson.lock.waiting_threads", () -> {
int total = 0;
Set<String> keys = redissonClient.getKeys().getKeysByPattern("lock:*");
for (String key : keys) {
RLock lock = redissonClient.getLock(key);
total += lock.getQueueSize();
}
return total;
})
.description("等待锁的线程总数")
.register(registry);
Gauge.builder("redisson.lock.held_time.max", () -> {
long max = 0;
Set<String> keys = redissonClient.getKeys().getKeysByPattern("lock:*");
for (String key : keys) {
RLock lock = redissonClient.getLock(key);
if (lock.isLocked()) {
long heldTime = System.currentTimeMillis() - lock.getLockHoldTime();
if (heldTime > max) max = heldTime;
}
}
return max;
})
.description("最长锁持有时间")
.register(registry);
};
}
八、压测对比与性能数据深度分析
8.1 JMeter压测配置
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="高并发抢单测试">
<intProp name="ThreadGroup.num_threads">1000</intProp>
<intProp name="ThreadGroup.ramp_time">60</intProp>
<longProp name="ThreadGroup.duration">600</longProp>
</ThreadGroup>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="创建订单请求">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="userId" elementType="HTTPArgument">
<stringProp name="Argument.value">${__Random(1,10000)}</stringProp>
</elementProp>
<elementProp name="productId" elementType="HTTPArgument">
<stringProp name="Argument.value">1001</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain">api.example.com</stringProp>
<stringProp name="HTTPSampler.port">443</stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.path">/order/create</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>
8.2 压测结果对比分析
| 指标 |
无锁方案 |
简单锁 |
分段锁 |
预占模式 |
| QPS |
12,500 |
8,200 |
18,300 |
23,500 |
| 平均响应时间 |
45ms |
68ms |
32ms |
25ms |
| P99响应时间 |
210ms |
350ms |
150ms |
95ms |
| 库存准确性 |
严重超卖 |
100% |
100% |
100% |
| CPU使用率 |
95% |
85% |
75% |
65% |
| Redis负载 |
12% |
45% |
68% |
82% |
8.3 性能瓶颈分析
瓶颈点分析:
- Redis集群成为性能瓶颈(82%负载)
- 分布式锁竞争导致线程阻塞
- 网络延迟影响锁获取速度
优化方案:
- Redis集群横向扩展(增加分片)
- 采用分段锁减少竞争
- 使用本地缓存减少Redis访问
- 升级网络基础设施
九、生产环境最佳实践
9.1 锁命名规范
String lockKey = "order:inventory:product:" + productId;
9.2 异常处理模板
public void executeBusinessWithLock(String lockKey, Runnable businessLogic) {
RLock lock = redissonClient.getLock(lockKey);
boolean locked = false;
try {
locked = lock.tryLock(3, 30, TimeUnit.SECONDS);
if (locked) {
businessLogic.run();
} else {
handleLockAcquisitionFailure(lockKey);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
handleInterruptedException(e);
} catch (Exception e) {
handleBusinessException(e);
} finally {
if (locked) {
try {
if (lock.isHeldByCurrentThread() && lock.isLocked()) {
lock.unlock();
}
} catch (IllegalMonitorStateException e) {
log.error("锁释放异常: {}", lockKey, e);
}
}
}
}
9.3 监控告警配置
groups:
- name: lock_alerts
rules:
- alert: HighLockContention
expr: redisson_lock_waiting_threads > 50
for: 5m
labels:
severity: warning
annotations:
summary: "高锁竞争警告"
description: "系统锁竞争激烈,当前等待线程数: {{ $value }}"
- alert: LongHoldingLock
expr: redisson_lock_held_time_max > 300000
for: 2m
labels:
severity: critical
annotations:
summary: "锁持有时间过长"
description: "锁 {{ $labels.lock_name }} 持有时间超过5分钟"
- alert: LockAcquisitionFailure
expr: increase(distributed_lock_fail_total[5m]) > 100
labels:
severity: warning
annotations:
summary: "锁获取频繁失败"
description: "5分钟内锁获取失败次数: {{ $value }}"
十、常见问题深度解决方案
10.1 锁超时问题解决方案
lock.tryLock(3, -1, TimeUnit.SECONDS);
long estimatedTime = estimateBusinessTime();
lock.tryLock(3, estimatedTime * 2, TimeUnit.MILLISECONDS);
private void startLockRenewal(RLock lock, long leaseTime) {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
if (lock.isHeldByCurrentThread()) {
lock.expire(leaseTime, TimeUnit.MILLISECONDS);
}
}, leaseTime / 3, leaseTime / 3, TimeUnit.MILLISECONDS);
}
10.2 锁释放问题解决方案
finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
lock.lock();
lock.lockAsync().thenAccept(locked -> {
try {
} finally {
lock.unlockAsync();
}
});
public <T> T executeWithAutoRelease(RLock lock, Supplier<T> supplier) {
lock.lock();
try {
return supplier.get();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
10.3 锁竞争优化方案
public class SegmentLock {
private final RLock[] segments;
public SegmentLock(int segmentCount, RedissonClient redissonClient) {
segments = new RLock[segmentCount];
for (int i = 0; i < segmentCount; i++) {
segments[i] = redissonClient.getLock("segment_lock_" + i);
}
}
public void execute(String key, Runnable action) {
int segment = Math.abs(key.hashCode()) % segments.length;
segments[segment].lock();
try {
action.run();
} finally {
segments[segment].unlock();
}
}
}
public class CompositeLock {
private final RLock lock1;
private final RLock lock2;
public CompositeLock(RedissonClient redissonClient, String key1, String key2) {
lock1 = redissonClient.getLock(key1);
lock2 = redissonClient.getLock(key2);
}
public void execute(Runnable action) {
boolean locked1 = false;
boolean locked2 = false;
try {
locked1 = lock1.tryLock(3, TimeUnit.SECONDS);
locked2 = lock2.tryLock(3, TimeUnit.SECONDS);
if (locked1 && locked2) {
action.run();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (locked1) lock1.unlock();
if (locked2) lock2.unlock();
}
}
}
10.4 Redis集群故障处理
config.useClusterServers()
.setScanInterval(2000)
.setSlaveConnectionMinimumIdleSize(24)
.setSlaveConnectionPoolSize(48)
.setMasterConnectionMinimumIdleSize(24)
.setMasterConnectionPoolSize(48)
.setFailedSlaveReconnectionInterval(30000)
.setFailedSlaveCheckInterval(60000);
redissonClient.getClusterNodesGroup().addConnectionListener(new ConnectionListener() {
@Override
public void onConnect(InetSocketAddress addr) {
log.info("节点连接成功: {}", addr);
}
@Override
public void onDisconnect(InetSocketAddress addr) {
log.warn("节点断开连接: {}", addr);
alertService.sendNodeDownAlert(addr);
}
});
总结与最佳实践
11.1 技术选型建议
| 场景 |
推荐方案 |
理由 |
| 普通电商 |
分布式锁+缓存 |
平衡性能与准确性 |
| 秒杀系统 |
预占库存+队列 |
极致性能 |
| 金融交易 |
红锁+数据库锁 |
最高安全性 |
| 数据迁移 |
读写锁 |
读写分离 |
| 定时任务 |
全局锁 |
简单可靠 |
11.2 性能优化金字塔
11.3 上线检查清单
所有评论(0)