张柏芝b大毛又多又长

核心内容摘要

污污网:重塑你的网络娱乐体验,探索无限可能
《真人40分钟刺激战场》:当虚拟战场化为现实,一场极致生存挑战即将引爆!

“妈妈,帮我戴避孕套”

为什么需要分布式锁在单体应用中我们使用Java的synchronized或ReentrantLock就能解决并发问题。

但在微服务架构下多个实例同时运行单机的锁机制就失效了。

这时就需要分布式锁来保证跨JVM的互斥访问。

分布式锁的核心需求互斥性同一时刻只能有一个客户端持有锁防止死锁客户端崩溃后能自动释放锁容错性Redis节点故障时仍能正常工作可重入性同一个线程可以多次获取同一个锁

Redis实现分布式锁的基础方案

1 最简单的实现SET NX最早期的实现方式是使用SET命令的NX选项SET key value NX PX 30000NX只在key不存在时设置PX设置过期时间毫秒这种方式的缺点无法实现可重入锁无法获取锁的持有人信息无法实现锁的自动续期

2 完整实现方案一个相对完善的Redis分布式锁实现需要包含以下逻辑Redis分布式锁基础架构加锁SET key value NX PX timeout解锁Lua脚本保证原子性看门狗定时续期防止业务执行时间超过锁过期时间

Redisson分布式锁Redisson是Redis的Java客户端它提供了完善的分布式锁实现解决了原生Redis锁的各种问题。

1 核心特性可重入锁同一个线程可多次获取锁公平锁按请求顺序获取锁读写锁允许多个读操作或单个写操作红锁跨多个Redis节点的分布式锁自动续期看门狗机制自动延长锁时间锁释放Lua脚本保证原子性操作

2 基本使用// 获取锁对象 RLock lock redisson.getLock(myLock); try { // 加锁支持等待时间和自动续期 boolean locked lock.tryLock(100, 30000, TimeUnit.MILLISECONDS); if (locked) { // 执行业务逻辑 doBusiness(); } } finally { // 释放锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); } }

Redis实现 vs Redisson对比Redis实现 vs Redisson对比特性Redis原生实现Redisson实现复杂度高需要处理多种边界情况低开箱即用可重入锁需要自己实现原生支持自动续期需要后台线程续期看门狗自动续期公平锁难以实现开箱即用读写锁难以实现开箱即用红锁需要自己协调开箱即用异常处理需要仔细处理完善的异常体系结论生产环境推荐使用Redisson它已经处理了各种边界情况和异常场景。

Redisson核心原理解析

1 加锁机制Redisson使用Lua脚本保证加锁的原子性Redisson加解锁流程-- 检查key是否存在 if redis.call(exists, KEYS[1]) 0 then -- 不存在则设置使用hash结构存储 redis.call(hset, KEYS[1], ARGV[2],

redis.call(pexpire, KEYS[1], ARGV[1]) return nil end -- key已存在检查是否是当前线程 if redis.call(hexists, KEYS[1], ARGV[2]) 1 then -- 是当前线程增加重入次数 redis.call(hincrby, KEYS[1], ARGV[2],

redis.call(pexpire, KEYS[1], ARGV[1]) return nil end return redis.call(pttl, KEYS[1])锁的数据结构使用Hash类型Key锁名称Field线程标识UUID:threadIdValue重入次数

2 看门狗机制看门狗Watchdog是Redisson的核心特性用于解决锁超时问题Watchdog机制业务获得锁时启动后台定时任务每隔lockWatchdogTimeout/3时间检查锁是否还持有如果还持有则重置过期时间业务释放锁时停止看门狗默认情况下看门狗每10秒续期一次锁的过期时间为30秒。

3 解锁机制解锁同样使用Lua脚本保证原子性-- 检查锁是否是当前线程持有 if redis.call(hexists, KEYS[1], ARGV[2]) 0 then return nil end -- 减少重入次数 local counter redis.call(hincrby, KEYS[1], ARGV[2], -

-- 如果重入次数大于0重置过期时间 if counter 0 then redis.call(pexpire, KEYS[1], ARGV[1]) return 0 end -- 重入次数为0删除锁 redis.call(del, KEYS[1]) -- 发布解锁消息 redis.call(publish, KEYS[2], ARGV[3]) return 1

生产环境实战案例生产环境实战案例

1 库存扣减Service public class InventoryService { Autowired private RedissonClient redisson; public boolean deductStock(String productId, int quantity) { RLock lock redisson.getLock(stock: productId); try { // 等待5秒锁过期30秒 if (lock.tryLock(5, 30, TimeUnit.SECONDS)) { // 查询库存 int stock getStock(productId); if (stock quantity) { // 扣减库存 updateStock(productId, stock - quantity); return true; } return false; } throw new BusinessException(系统繁忙请稍后重试); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }

2 订单幂等性控制Service public class OrderService { Autowired private RedissonClient redisson; public Order createOrder(OrderRequest request) { String lockKey order:create: request.getUserId(); RLock lock redisson.getLock(lockKey); try { if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { // 检查是否已有未完成订单 Order existOrder getUnfinishedOrder(request.getUserId()); if (existOrder ! null) { return existOrder; } // 创建新订单 Order order buildOrder(request); saveOrder(order); return order; } throw new BusinessException(操作频繁请稍后重试); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }

3 定时任务防止重复执行Component public class DataSyncJob { Autowired private RedissonClient redisson; Scheduled(cron 0 */5 * * * *) public void syncData() { String lockKey job:data:sync; RLock lock redisson.getLock(lockKey); try { // 尝试获取锁不等待 if (lock.tryLock(0, TimeUnit.SECONDS)) { // 执行数据同步 doSync(); } else { log.info(上次同步任务尚未完成跳过本次执行); } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }

高级特性读写锁在读多写少的场景下使用读写锁可以大幅提升并发性能读写锁原理Service public class ConfigService { Autowired private RedissonClient redisson; public String getConfig(String key) { RReadWriteLock rwLock redisson.getReadWriteLock(config: key); RLock readLock rwLock.readLock(); try { readLock.lock(); // 多个线程可以同时读取 return queryFromDB(key); } finally { readLock.unlock(); } } public void updateConfig(String key, String value) { RReadWriteLock rwLock redisson.getReadWriteLock(config: key); RLock writeLock rwLock.writeLock(); try { // 写操作独占锁 writeLock.lock(); updateDB(key, value); // 清除缓存 clearCache(key); } finally { writeLock.unlock(); } } }

最佳实践

1 锁的粒度选择粗粒度锁整个表或模块简单但并发度低细粒度锁单个记录并发度高但实现复杂推荐根据业务场景选择合适的粒度库存扣减用商品维度订单创建用用户维度。

2 锁的过期时间设置不要设置过短避免业务未执行完就释放不要设置过长避免故障时长时间阻塞Redisson的看门狗会自动续期但要设置合理的初始时间推荐根据业务执行时间的P99值设置预留50%余量。

3 异常处理捕获中断异常确保锁能被释放使用tryLock而不是lock避免无限等待检查锁的持有状态避免误释放

九、

常见问题Q1Redisson锁会丢失吗不会。

Redisson使用看门狗机制即使业务执行时间超过锁的过期时间也会自动续期直到业务主动释放锁。

Q2Redis主从切换会影响锁吗会。

单节点Redis在主从切换时可能丢失锁。

需要使用Redisson的红锁RedLock或Redis Cluster。

Q3如何实现公平锁Redisson提供了公平锁实现RLock fairLock redisson.getFairLock(myFairLock); fairLock.lock();Q4性能如何Redisson的分布式锁性能很好单机QPS可达5万足以应对大多数场景。

如有更高性能需求可以考虑分段锁或本地锁分布式锁的组合方案。

十、

总结Redisson分布式锁是Java领域最成熟的Redis分布式锁解决方案使用简单API友好学习成本低功能完善支持多种锁类型和场景稳定可靠经过大量生产环境验证性能优异看门狗机制和Lua脚本保证性能在实际项目中建议优先使用Redisson它已经帮你处理了各种复杂的边界情况让你专注于业务逻辑的实现。

9.1成长小视频-9.1成长小视频应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123