1. 数据一致性概述:到底什么是数据一致性?
大家好,我是你们的老朋友。今天咱们开始聊微服务里最让人头疼的问题——数据一致性。
说实话,我做了十几年分布式系统,踩过的坑里,有一半以上跟数据一致性有关。你想想看,一个单体应用拆成几十个微服务,数据散落在各个数据库里,怎么保证它们能对得上?
嗯,咱们先从最基础的说起。
1.1 什么是数据一致性?
数据一致性,说白了就是:同一份数据,在不同地方看到的应该是一样的。
举个最简单的例子。你去银行转账,从A账户扣了100块,B账户就得加上100块。如果扣款成功了,但B账户没到账,这就叫不一致。
在单体应用里,这事好办。一个事务就搞定了。但在微服务里,数据分散在不同的服务里,每个服务有自己的数据库。这时候要保持一致,就没那么简单了。
核心定义:数据一致性是指分布式系统中,多个副本或分片之间的数据在逻辑上保持等价的状态。
我个人习惯把一致性分成几个维度来看:
- 强一致性:写完就能读到最新数据,延迟最低
- 弱一致性:写完不一定马上读到,但最终会读到
- 最终一致性:给系统一点时间,数据最终会一致
我在项目中遇到过很多团队,一上来就追求强一致性。结果呢?系统性能上不去,还经常死锁。后来我学乖了,先问业务场景,再选一致性模型。
1.2 为什么微服务中会出现不一致?
这个问题我问过很多学员。答案五花八门,但核心原因其实就几个。
原因一:分布式事务的天然缺陷
微服务里,一个业务操作往往要跨多个服务。比如下单:
- 订单服务创建订单
- 库存服务扣减库存
- 支付服务扣款
- 物流服务创建配送单
这四个操作,如果任何一个失败,其他三个怎么办?回滚?怎么回滚?
在单体应用里,一个数据库事务就能搞定。但在微服务里,每个服务有自己的数据库,没法用传统的事务机制。
原因二:网络不可靠
这个我深有体会。有一次线上故障,就是因为网络抖动,一个服务调用超时了。调用方以为失败了,其实被调用方已经处理成功了。结果数据就对不上了。
你想想看,网络延迟、丢包、重传,这些都是家常便饭。微服务之间的调用,本质上就是远程调用,天然不可靠。
原因三:服务实例的动态变化
微服务经常要扩缩容。今天10个实例,明天20个。每个实例都有自己的状态。如果某个实例挂了,它处理到一半的数据怎么办?
我曾经遇到过一个场景:一个服务在处理订单时挂了,重启后它不知道之前处理到哪一步了。结果订单状态和库存数据对不上了。嗯,这就是典型的「状态丢失」问题。
| 不一致原因 | 典型场景 | 影响范围 |
|---|---|---|
| 分布式事务 | 跨服务操作失败 | 多个服务数据不一致 |
| 网络不可靠 | 超时、重试、丢包 | 单次调用结果不确定 |
| 服务动态变化 | 扩缩容、宕机 | 状态丢失或重复处理 |
| 并发冲突 | 多个请求同时修改 | 数据覆盖或丢失 |
避坑指南:我曾经在一个项目中,因为没处理好网络超时,导致用户重复下单。后来我加了个幂等性校验,才彻底解决。记住:微服务里,任何一次调用都可能失败,一定要做好容错。
1.3 CAP理论与BASE理论
聊数据一致性,绕不开CAP理论。这个理论是分布式系统的基石。
CAP理论说:一个分布式系统,最多只能同时满足以下三个特性中的两个:
- C(一致性):所有节点在同一时刻看到的数据是一样的
- A(可用性):每个请求都能得到响应,不管成功还是失败
- P(分区容错性):系统允许网络分区,即使部分节点失联,系统仍能工作
说白了,就是鱼和熊掌不可兼得。你选了CP,就得牺牲A;选了AP,就得牺牲C。
我刚开始做分布式时,总想着三者都要。后来发现,网络分区是必然的,所以P必须选。剩下的就是在C和A之间做取舍。
那BASE理论呢?
BASE理论是对CAP的补充。它说:既然强一致性做不到,那咱们就追求「基本可用」和「最终一致」。
BASE三个要素:
- BA(基本可用):系统允许部分功能降级,但核心功能必须可用
- S(软状态):允许数据在一段时间内不一致
- E(最终一致性):经过一段时间后,数据最终会一致
你想想看,很多互联网业务其实不需要强一致性。比如微博的点赞数,你点个赞,别人晚几秒看到也没关系。这就是典型的最终一致性场景。
我的经验:选CAP还是BASE,取决于业务。金融交易必须强一致,那就选CP。社交、电商可以接受最终一致,那就选AP+BASE。别盲目追求强一致,那会拖垮你的系统。
举个例子:
// 强一致性场景:银行转账
// 必须保证扣款和入账同时成功或同时失败
// 选CP,牺牲可用性
// 最终一致性场景:用户头像更新
// 用户改了头像,别人晚几秒看到也没关系
// 选AP,牺牲一致性
嗯,这里要注意:BASE理论不是让你放弃一致性,而是让你接受「最终一致」。这个「最终」可能是几毫秒,也可能是几秒。关键看你怎么设计补偿机制。
我在项目中常用的做法是:核心链路用强一致,非核心链路用最终一致。比如下单时,库存扣减必须强一致;但用户积分更新,可以异步处理,最终一致就行。
好了,这一章就聊到这。下一章咱们深入聊聊分布式事务的具体实现方案。