记得去年参与一个电商秒杀系统开发时,我用RedisTemplate手写了一套分布式锁。上线当天凌晨,运营同事突然打电话说出现了超卖现象。排查发现有个服务节点崩溃后,锁没能正确释放,导致其他节点同时处理了同一批订单。那次事故让我深刻认识到:手工实现分布式锁就像用瑞士军刀修车——看似能用,实则隐患重重。
手工实现Redis锁的典型问题包括:
实测对比显示,基于Redisson的方案比手工实现可靠性提升显著:
| 指标 | 手工实现 | Redisson |
|---|---|---|
| 锁续期 | 需自行实现 | 自动看门狗机制 |
| 可重入 | 不支持 | 原生支持 |
| 释放安全性 | 易误删 | 客户端ID绑定 |
| 集群支持 | 无 | 哨兵/集群模式 |
java复制// 初始化配置
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient client = Redisson.create(config);
// 获取锁实例
RLock lock = client.getLock("orderLock");
try {
// 支持重入的加锁操作
lock.lock();
// 业务处理...
processOrder();
} finally {
// 确保释放锁
lock.unlock();
}
这个看似简单的代码背后,Redisson帮我们处理了:
在票务系统中,我们曾用公平锁解决了黄机器刷票问题:
java复制RLock fairLock = client.getFairLock("ticketLock");
// 后续使用与普通锁相同
公平锁特点:
内容管理系统中的典型应用:
java复制RReadWriteLock rwLock = client.getReadWriteLock("articleLock");
// 读操作
rwLock.readLock().lock();
try {
// 多个线程可并发读取
showArticle();
} finally {
rwLock.readLock().unlock();
}
// 写操作
rwLock.writeLock().lock();
try {
// 独占式写入
updateArticle();
} finally {
rwLock.writeLock().unlock();
}
实测某资讯平台采用读写锁后,QPS从1200提升到3800+。
生产环境推荐配置(3哨兵+1主2从):
java复制Config config = new Config();
config.useSentinelServers()
.setMasterName("mymaster")
.addSentinelAddress("redis://sentinel1:26379")
.addSentinelAddress("redis://sentinel2:26379")
.addSentinelAddress("redis://sentinel3:26379")
.setDatabase(0);
关键参数说明:
masterName:主节点名称(需与sentinel.conf一致)sentinelAddresses:至少配置3个哨兵地址failMaxAttempts:故障转移重试次数(默认3)6节点集群配置示例(3主3从):
java复制Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://node1:7000")
.addNodeAddress("redis://node2:7001")
//...其他节点
.setScanInterval(2000); // 集群状态扫描间隔
避坑指南:
retryAttempts(默认3次)和retryInterval(默认1500ms)在金融支付系统中,我们总结出这些经验:
业务域:操作类型:资源ID格式(如payment:create:order123)某银行系统接入Redisson后的性能变化:
遇到锁问题时,可以这样排查:
redis-cli查看锁键状态redisson.getLock("lockName").isLocked()验证锁状态forceUnlock()紧急释放(慎用)