Java之分布式系统与一致性!

举报
喵手 发表于 2025/09/24 21:48:28 2025/09/24
【摘要】 开篇语哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是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 !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。