Java之分布式系统与一致性!
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
如果你刚写完一个单体应用,正沾沾自喜地部署到服务器,结果产品拍了拍你:“能不能支持10万并发?”
你的内心可能是这样的⬇️
“啊?这不是写几个接口就完了吗?为啥还要考虑一致性、分布式锁、CAP… 我是来写业务的,不是来造火箭的啊兄弟!”
别急。今天就让我们来拨开分布式系统的迷雾,看看它到底是“性能优化的钥匙”,还是“复杂性的潘多拉魔盒”。
一、CAP定理 & BASE理论:鱼和熊掌不可兼得
在进入实战之前,必须得搞明白一个灵魂拷问:“我到底是要强一致性,还是要高可用?”
✳️ CAP 定理是什么?
CAP 定理,全名是:Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性)
它告诉你:分布式系统最多只能同时满足其中两个,三者不可兼得。
组合 | 特点说明 |
---|---|
CP | 强一致性 + 分区容错,但可用性低(如:Zookeeper) |
AP | 高可用 + 分区容错,但牺牲一致性(如:DNS、Cassandra) |
CA | 只能存在于理想世界,分区容忍性不可能缺席 |
👉 举个栗子:
Zookeeper 选择的是 CP,如果主节点挂了,它会停止对外提供服务来保持一致性;
Cassandra 选择的是 AP,即使有节点挂了也能读写,但可能读到“旧数据”。
✳️ BASE 理论呢?
如果说 CAP 是硬规则,那 BASE 就是权衡后的实用主义哲学。
BASE = Basically Available + Soft State + Eventually Consistent
翻译成人话就是:
“别追求每次都对,能接受最终对就行。”
你点外卖,骑手迟到 2 分钟还能接受;但你付完钱订单没了,系统崩盘——那就不能接受。
二、分布式事务:本地事务已死,谁来背锅?
在单体架构里,你可以用 @Transactional
一把梭,提交失败就回滚,潇洒得很。
可分布式系统里,数据库一堆、服务一堆、消息一堆……一个接口跨三个系统,哪里来的事务一致性?
🚨 典型痛点:
- 用户下单成功了 → 账户没扣钱 → 库存没减 → 财务找上门:“你到底卖了没卖?”
分布式事务解决方案(常见的三种):
1. 两阶段提交(2PC)
- 第一阶段:各节点“预提交”
- 第二阶段:协调者通知“提交”或“回滚”
🧨 缺点:协调者一挂,系统直接僵尸化。
2. TCC(Try Confirm Cancel)
- Try:预留资源
- Confirm:正式提交
- Cancel:回滚资源
适用于业务可以拆成三个阶段的(比如:账户冻结 → 确认扣款 → 解冻)。
// Try
accountService.tryFreeze(userId, amount);
// Confirm
accountService.confirm(userId);
// Cancel
accountService.cancel(userId);
优点是灵活,缺点是业务入侵严重,每个系统都得支持三套逻辑。
3. 消息最终一致性(基于 MQ)
- 下单 → 发送 MQ 消息 → 异步扣库存/扣款 → 成功或失败后回调更新状态
是 BASE 理论的最佳落地方式,“先做再对齐”。
三、分布式锁:防止“多人抢麦”的场景神器
如果你遇到“同一商品被两个人秒杀成功”、“同一用户支付两次”这种情况,恭喜你踩了并发坑的第一个雷——缺少分布式锁。
🧱 为什么不能用 synchronized
?
因为在分布式系统中,多个服务实例运行在多个 JVM 中,synchronized
只能锁住本地线程!
根本没用!
🐵 分布式锁方案:
1. Redis 锁(最常见)
Boolean success = redisTemplate.opsForValue()
.setIfAbsent("lock:product:1001", "UUID", 10, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(success)) {
try {
// 执行业务逻辑
} finally {
redisTemplate.delete("lock:product:1001");
}
}
但注意:
- 要防止锁过期业务未完成(可以用 Redisson)
- 要防止误删锁(加唯一标识)
2. Zookeeper 分布式锁(CP风格)
Zookeeper 使用临时顺序节点实现锁竞争。
优点:
- 强一致性
- 有“排队”机制,不会饥饿
缺点:
- 性能不如 Redis,适合少量高价值的锁
四、分库分表 & 读写分离:性能优化,还是一致性灾难?
你的系统一旦数据量上来了,老板盯着 QPS 和响应时间,DBA 拍着桌子说:“必须分库分表!”
你以为只是多了几张表?结果你发现自己进入了分页排序分页失效、ID碰撞、事务混乱的地狱循环。
🎯 分库分表的典型方式:
- 垂直拆分:按业务拆(用户表放A库,订单表放B库)
- 水平分表:按数据行拆(订单_0 表、订单_1 表)
常见组件:
- ShardingSphere
- MyCat
- 自研中间件(最稳定也最累)
🚦 读写分离带来的挑战:
- 主从延迟 → 写完读不到
- 查询一致性问题 → 业务逻辑出错
- 强一致需求要“强制走主库”
// 读写分离伪代码
if (isWriteRequest) {
routeTo(masterDB);
} else {
routeTo(slaveDB);
}
你以为是优化,其实是“新坑入口”,必须引入全链路追踪、慢 SQL 警报等手段兜底。
结语:分布式系统的美,是建立在代价之上的
很多人把“分布式”当成“高级架构”的代名词,但真相是:
每多一个节点,就多一个出错点;每多一份数据,就多一份一致性代价。
CAP 定理不是传说,分布式事务不是理想,分库分表也不只是写个路由规则那么简单。
那么问题来了:
💣你写的系统,是靠“锁与补偿”维持运行,还是已经成为“分布式灾难现场”?
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!
- 点赞
- 收藏
- 关注作者
评论(0)