漫画分布式锁
"分布式系统中,锁不再是线程间的约定,而是服务间的契约。"
🎭 人物介绍
- 分布式大师:精通分布式系统架构的技术专家
- Java小子:对分布式锁充满好奇的开发者
- Redis老兄:缓存数据库的化身,擅长高性能存储
- ZK智者:ZooKeeper的化身,专注一致性保证
- 数据库老爷:传统数据库的代表,稳重可靠
本节导言
Java小子:(困惑地)在单机环境下,我们可以用synchronized或ReentrantLock来保证线程安全,但在分布式环境下该怎么办呢?
分布式大师:(微笑)这就是分布式锁要解决的问题!在分布式系统中,不同服务器上的进程需要协调访问共享资源,传统的JVM内锁就无能为力了。
Redis老兄:(跳出来)我可以帮忙!用我的原子操作,可以实现高性能的分布式锁!
ZK智者:(沉稳地)稳重起见,我的强一致性保证更适合关键业务场景。
数据库老爷:(慢条斯理)别忘了我,数据库锁虽然性能一般,但胜在简单可靠。
1. 分布式锁基础概念
1.1 什么是分布式锁
分布式大师:分布式锁是在分布式环境下,控制分布式系统不同进程共同访问共享资源的一种锁实现。
1.2 分布式锁的特性要求
分布式大师:一个好的分布式锁应该具备以下特性:
- 互斥性:同一时刻只有一个客户端能获取锁
- 防死锁:即使持有锁的客户端崩溃,锁最终也能被释放
- 容错性:只要大部分节点正常,客户端就能获取和释放锁
- 一致性:加锁和解锁必须是同一个客户端
2. Redis分布式锁实现
2.1 基础实现
Redis老兄:我的SET命令支持原子性操作,是实现分布式锁的利器!
java
@Component
public class RedisDistributedLock {
@Autowired
private StringRedisTemplate redisTemplate;
private static final String LOCK_PREFIX = "distributed_lock:";
private static final String UNLOCK_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
public boolean tryLock(String key, String value, long expireTime) {
String lockKey = LOCK_PREFIX + key;
Boolean result = redisTemplate.opsForValue()
.setIfAbsent(lockKey, value, Duration.ofSeconds(expireTime));
return Boolean.TRUE.equals(result);
}
public boolean unlock(String key, String value) {
String lockKey = LOCK_PREFIX + key;
DefaultRedisScript<Long> script = new DefaultRedisScript<>();
script.setScriptText(UNLOCK_SCRIPT);
script.setResultType(Long.class);
Long result = redisTemplate.execute(script,
Collections.singletonList(lockKey), value);
return Long.valueOf(1).equals(result);
}
}
2.2 Redisson实现
java
@Service
public class RedissonLockService {
@Autowired
private RedissonClient redissonClient;
public void simpleLock() {
RLock lock = redissonClient.getLock("myLock");
try {
boolean acquired = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (acquired) {
System.out.println("获取锁成功,执行业务逻辑");
Thread.sleep(5000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
3. ZooKeeper分布式锁实现
3.1 Curator框架实现
ZK智者:Apache Curator提供了更简单的API!
java
@Service
public class CuratorLockService {
private CuratorFramework client;
@PostConstruct
public void init() {
client = CuratorFrameworkFactory.newClient(
"localhost:2181",
new ExponentialBackoffRetry(1000, 3)
);
client.start();
}
public void mutexLock() throws Exception {
InterProcessMutex lock = new InterProcessMutex(client, "/locks/mutex");
try {
if (lock.acquire(10, TimeUnit.SECONDS)) {
System.out.println("获取锁成功");
Thread.sleep(5000);
}
} finally {
lock.release();
}
}
}
4. 数据库分布式锁实现
数据库老爷:虽然性能不如Redis和ZooKeeper,但我的ACID特性保证了绝对的可靠性!
sql
CREATE TABLE distributed_lock (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
lock_name VARCHAR(100) NOT NULL,
lock_value VARCHAR(100) NOT NULL,
expire_time TIMESTAMP NOT NULL,
UNIQUE KEY uk_lock_name (lock_name)
);
java
@Repository
public class DatabaseDistributedLock {
@Autowired
private JdbcTemplate jdbcTemplate;
public boolean tryLock(String lockName, String lockValue, long expireSeconds) {
String sql = "INSERT INTO distributed_lock (lock_name, lock_value, expire_time) " +
"VALUES (?, ?, DATE_ADD(NOW(), INTERVAL ? SECOND))";
try {
int result = jdbcTemplate.update(sql, lockName, lockValue, expireSeconds);
return result > 0;
} catch (DuplicateKeyException e) {
return false;
}
}
public boolean unlock(String lockName, String lockValue) {
String sql = "DELETE FROM distributed_lock WHERE lock_name = ? AND lock_value = ?";
int result = jdbcTemplate.update(sql, lockName, lockValue);
return result > 0;
}
}
5. 分布式锁对比分析
方案 | 性能 | 可靠性 | 复杂度 | 适用场景 |
---|---|---|---|---|
Redis | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | 高并发场景 |
ZooKeeper | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 强一致性要求 |
数据库 | ⭐⭐ | ⭐⭐⭐⭐ | ⭐ | 简单业务场景 |
6. 实战案例:秒杀系统
java
@Service
public class SeckillService {
@Autowired
private RedissonClient redissonClient;
public SeckillResult seckill(Long productId, Long userId) {
String lockKey = "seckill:lock:" + productId;
RLock lock = redissonClient.getLock(lockKey);
try {
boolean acquired = lock.tryLock(3, 10, TimeUnit.SECONDS);
if (!acquired) {
return SeckillResult.fail("系统繁忙,请稍后重试");
}
// 检查库存
if (!hasStock(productId)) {
return SeckillResult.fail("商品已售罄");
}
// 扣减库存
decreaseStock(productId);
// 创建订单
SeckillOrder order = createOrder(productId, userId);
return SeckillResult.success("秒杀成功", order);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return SeckillResult.fail("系统异常");
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
记忆口诀
分布式锁三大将,Redis、ZK、数据库;
Redis性能最为强,QPS可达十万量;
ZK一致性保障好,强一致性是特长;
数据库锁最简单,ACID特性有保障;
互斥防死要做好,超时机制不能忘。
总结
分布式大师:选择合适的分布式锁方案需要考虑:
- 性能要求:高并发选Redis,一致性要求高选ZooKeeper
- 业务场景:简单场景可以用数据库锁
- 技术栈:结合现有技术栈选择
- 维护成本:考虑团队技术水平
记住:没有最好的方案,只有最合适的方案!
分布式锁,让分布式系统更加协调有序! 🔐
📌 行动指南
- 点赞 → 让更多Java开发者掌握JVM技术
- 评论 → 留言"JVM技术"领取[JVM调优实战手册]
- 关注 → 追踪更新《更多Java技术精彩内容》(已写完待发布)
- 赞赏 → 解锁完整源码+专属技术咨询
🚀 下期预告
《更多Java技术精彩内容》关注可抢先看
📚 相关推荐:
让我们一起在Java的世界里探索更多精彩内容! 🚀