🧑 博主简介:CSDN博客专家、全栈领域优质创作者、高级开发工程师、高级信息系统项目管理师、系统架构师,10年以上多种混合语言开发经验,从事PACS医学影像开发领域多年,熟悉DICOM协议及其应用开发技术。我的技能涵盖了多种编程语言和技术框架:作为高级C/C++与C#开发工程师,我擅长Windows系统下的.NET及C++开发技术,尤其精通MFC、DLL动态链接库、WinForm、WPF、Windows服务、WebAPI及.NET Core跨平台等技术的开发工作。此外,由于项目需要,也熟悉Java开发,并利用业余时间学习了JavaScript、Vue等前端技术,同时自学了QT开发工具,对Python也有一定的了解。这使我具备了使用多种混合语言进行开发的能力。我一直坚持撰写博客文章,记录个人的学习历程,分享编程开发相关的知识与经验,旨在为编程爱好者提供帮助和支持。通过这样的方式,我希望可以与志同道合的朋友交流探讨,共同进步,在技术的世界里不断学习和成长。如果您也热衷于技术探索,愿意一起讨论最新技术趋势或解决遇到的技术难题,欢迎随时联系。让我们携手共进,在追求卓越技术的道路上越走越远。欢迎关注、学习及合作,可提供解决方案和技术支持!
技术合作请加本人wx(注明来自csdn):xt20160813

《分布式并发控制实战手册:从Redis锁到ZK选主的架构之道》
一、为什么需要分布式锁?------单机锁的局限性
1.1 传统锁的困境
java
// 单机环境下使用ReentrantLock
public class InventoryService {
private final Lock lock = new ReentrantLock();
private int stock = 100;
public void deduct() {
lock.lock();
try {
if (stock > 0) {
stock--;
}
} finally {
lock.unlock();
}
}
}
// 问题:当服务部署多个节点时,单机锁失效!
// 节点A和节点B会同时修改库存,导致超卖
1.2 CAP理论启示
无法同时满足 无法同时满足 无法同时满足 一致性Consistency 可用性Availability 分区容错性Partition
架构选择:
- Redis:偏向AP(高可用)
- ZooKeeper:偏向CP(强一致)
二、Redis分布式锁深度剖析
2.1 基础实现方案
java
// 使用SETNX命令(存在缺陷)
public class RedisLock {
private Jedis jedis;
public boolean tryLock(String key, String value, int expire) {
String result = jedis.set(key, value, "NX", "EX", expire);
return "OK".equals(result);
}
public void unlock(String key) {
jedis.del(key);
}
}
// 问题清单:
// 1. 非原子操作风险
// 2. 锁误删(需验证value)
// 3. 无自动续期
2.2 生产级解决方案(Redisson)
java
// Redisson客户端配置
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
RedissonClient client = Redisson.create(config);
// 加锁示例
RLock lock = client.getLock("order_lock");
try {
// 尝试加锁,最多等待100秒,锁自动释放时间30秒
boolean res = lock.tryLock(100, 30, TimeUnit.SECONDS);
if (res) {
// 执行业务逻辑
processOrder();
}
} finally {
lock.unlock();
}
// 核心功能:
// 1. WatchDog自动续期(默认30秒检测)
// 2. 可重入锁机制
// 3. 锁释放校验(Lua脚本保证原子性)
2.3 Redlock算法实现
java
// 多Redis节点配置
Config config1 = new Config();
config1.useClusterServers()
.addNodeAddress("redis://node1:6379");
Config config2 = new Config();
config2.useClusterServers()
.addNodeAddress("redis://node2:6379");
RedissonClient client1 = Redisson.create(config1);
RedissonClient client2 = Redisson.create(config2);
RLock lock1 = client1.getLock("resource");
RLock lock2 = client2.getLock("resource");
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2);
try {
// 超过半数节点加锁成功视为成功
if (redLock.tryLock()) {
// 访问共享资源
}
} finally {
redLock.unlock();
}
三、ZooKeeper分布式锁实现方案
3.1 临时顺序节点原理
lock lock-00000001 lock-00000002 lock-00000003
执行流程:
- 每个客户端创建临时顺序节点
- 监听前序节点的删除事件
- 最小序号节点获得锁
3.2 Curator框架实现
java
// 连接配置
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory
.newClient("zk1:2181,zk2:2181", retryPolicy);
client.start();
// 创建分布式锁
InterProcessMutex lock = new InterProcessMutex(client, "/locks/order");
try {
// 获取锁(支持超时设置)
if (lock.acquire(10, TimeUnit.SECONDS)) {
// 业务处理
updateOrderStatus();
}
} finally {
lock.release();
}
// 核心特性:
// 1. 自动创建/删除临时节点
// 2. 连接断开自动释放锁
// 3. 顺序公平锁机制
四、ZooKeeper选主机制
4.1 选主流程设计
java
// 选主实现代码
public class LeaderElection {
private final String PATH = "/election/leader";
private CuratorFramework client;
private String nodePath;
public void start() throws Exception {
// 创建临时顺序节点
nodePath = client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(PATH + "/node_");
// 检查当前最小序号节点
checkLeadership();
}
private void checkLeadership() throws Exception {
List<String> nodes = client.getChildren().forPath(PATH);
Collections.sort(nodes);
if (nodePath.endsWith(nodes.get(0))) {
System.out.println("成为Leader节点");
// 执行Leader任务
startLeaderJob();
} else {
// 监听前一个节点的删除事件
String previousNode = PATH + "/" + nodes.get(
Collections.binarySearch(nodes, nodePath.substring(nodePath.lastIndexOf("/") + 1)) - 1
);
watchPreviousNode(previousNode);
}
}
private void watchPreviousNode(String path) {
// 设置Watcher监听节点删除事件
}
}
4.2 选主场景应用
NodeA NodeB ZK 创建临时节点/node_00000001 创建临时节点/node_00000002 返回节点列表,NodeA为Leader 执行定时任务 监听/node_00000001 节点断开连接 触发节点删除事件 升级为Leader NodeA NodeB ZK
五、分布式方案对比决策树
是 否 是 否 是 否 分布式并发需求 是否要求强一致性? ZooKeeper方案 是否高频短时锁? Redis方案 是否需要公平锁?
方案对比表:
特性 | Redis分布式锁 | ZooKeeper分布式锁 |
---|---|---|
一致性 | 最终一致 | 强一致 |
性能 | 10万+ QPS | 1万+ QPS |
可靠性 | 依赖持久化策略 | 基于Zab协议 |
锁类型 | 非公平锁 | 公平锁 |
适用场景 | 高频短时操作 | 低频长事务 |
六、电商库存扣减实战
6.1 Redis锁实现
java
public class RedisInventoryService {
private RedissonClient redisson;
private Jedis jedis;
public boolean deductStock(String productId, int count) {
RLock lock = redisson.getLock("stock_lock:" + productId);
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
int stock = Integer.parseInt(jedis.get("stock:" + productId));
if (stock >= count) {
jedis.decrBy("stock:" + productId, count);
return true;
}
return false;
}
} finally {
lock.unlock();
}
return false;
}
}
6.2 ZooKeeper选主调度
java
public class SchedulerMaster {
private InterProcessMutex lock;
public void start() {
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
try {
if (lock.acquire(0, TimeUnit.SECONDS)) {
// 只有Leader节点执行
generateReport();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 0, 60*1000);
}
}
七、生产环境注意事项
7.1 Redis锁的三大陷阱
-
时钟漂移问题:多节点时间不同步导致锁过期
java// 解决方案:使用Redisson的WatchDog机制 config.setLockWatchdogTimeout(30_000);
-
网络分区风险:脑裂导致锁失效
bash# Redis配置(至少3个节点) min-replicas-to-write 2 min-replicas-max-lag 10
-
锁误用场景:不适用长时间事务
java// 错误示例:获取锁后执行耗时操作 lock.lock(); try { processBatchData(); // 可能执行10分钟 } finally { lock.unlock(); }
7.2 ZooKeeper的容错设计
-
会话管理:设置合理超时时间
javaCuratorFrameworkFactory.builder() .sessionTimeoutMs(60000) .connectionTimeoutMs(15000)
-
重试策略:指数退避算法
javanew RetryNTimes(3, 1000)
-
节点清理:添加监听处理
javaPathChildrenCache cache = new PathChildrenCache(client, "/locks", true); cache.getListenable().addListener(new PathChildrenCacheListener() { public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) { // 处理节点变化事件 } });
总结与进阶指南
学习路线建议:
- 掌握分布式系统理论基础(Paxos/Raft算法)
- 研究Redis源码(Redlock实现细节)
- 分析ZooKeeper的Zab协议
- 学习其他协调服务(etcd/Consul)
性能优化方向:
- Redis锁碎片化(按业务拆分锁粒度)
- ZooKeeper节点预创建(减少实时创建开销)
- 本地缓存+分布式锁的混合方案
推荐监控指标:
- 锁等待时间(redis_lock_wait_time)
- 锁持有时间(zk_lock_hold_duration)
- 选主切换频率(leader_switch_count)
掌握这些知识后,您已经能够设计出满足1000+TPS的分布式并发控制系统。建议在实际项目中从简单场景入手(如秒杀活动),逐步扩展到复杂业务(金融交易系统),同时持续关注分布式领域的最新发展(如Google Chubby的设计理念)。