在学习数据库的时候,我们经常会接触到两个概念:
-
关系型数据库强调 ACID
-
NoSQL / 分布式数据库经常强调 BASE
很多人第一次看到 BASE 时,会产生一个疑问:
如果 NoSQL 不保证强一致性,而只是保证"最终一致性",那数据岂不是可能不一致?这样的数据库还能用吗?
答案当然是:能用,而且很多互联网系统恰恰非常依赖这种设计。
关键在于,BASE 并不是"不要一致性",而是在分布式、高并发场景下,对一致性、可用性和性能进行权衡。
一、先简单回顾一下 ACID
传统关系型数据库中的事务,一般强调 ACID:
-
Atomicity(原子性)
-
Consistency(一致性)
-
Isolation(隔离性)
-
Durability(持久性)
例如用户进行一次银行转账:
A 账户扣除 100 元
B 账户增加 100 元
这两步应该作为一个整体执行。
要么全部成功:
A:1000 → 900
B:500 → 600
要么全部失败。
不能出现:
A:1000 → 900
B:仍然是 500
否则钱就"消失"了。
因此,在银行余额、支付、账务等场景中,强一致性通常非常重要。
二、为什么分布式系统不能一直追求强一致性?
假设我们的系统只有一台数据库服务器:
用户
↓
数据库
所有数据都在一个地方,一致性相对容易保证。
但随着业务规模越来越大,单机数据库撑不住之后,系统可能变成:
┌── Node A
用户 ──────┼── Node B
└── Node C
数据会分布在多个节点上。
这时问题就出现了。
假设 Node A 更新了一条数据:
库存:100 → 99
然后需要同步给 Node B 和 Node C。
但是网络通信是有延迟的。
于是短时间内可能出现:
Node A:99
Node B:100
Node C:100
如果我们要求:
所有节点必须在同一时刻看到完全一样的数据
那么系统就必须等待所有节点完成同步以后,才能返回请求。
这样虽然一致性很强,但会带来几个问题:
-
请求延迟增加
-
某个节点故障可能拖慢整个系统
-
网络抖动时系统可用性下降
-
高并发场景吞吐量下降
因此很多分布式系统会选择:
允许短时间不一致,但保证最终会一致。
这就是 BASE 思想产生的背景。
三、什么是 BASE?
BASE 主要包含三个部分:
Basically Available
Soft State
Eventually Consistent
也就是:
1. Basically Available:基本可用
意思是:
即使系统发生部分故障,也尽可能继续提供服务。
比如一个电商系统有 10 台数据库节点,其中 1 台发生故障。
系统不应该因为这一台服务器挂掉,就导致整个网站无法访问。
可以通过:
节点 A ❌
节点 B ✅
节点 C ✅
节点 D ✅
让其他节点继续处理请求。
因此 BASE 更强调:
系统先活着。
四、Soft State:软状态
Soft State 可以理解成:
系统允许数据暂时处于一个中间状态。
例如商品库存原本是:
库存 = 100
用户购买一件商品之后,Node A 已经更新为:
Node A:99
但 Node B 还没同步:
Node B:100
那么此时系统暂时存在:
Node A:99
Node B:100
这就是一种"软状态"。
数据暂时不完全一致。
但这种状态只存在于数据同步的过程中。
五、Eventually Consistent:最终一致性
最终一致性是 BASE 最重要的一个概念。
意思是:
系统允许短时间不一致,但经过一段时间以后,所有节点最终会达到一致状态。
例如:
T1 时刻
Node A:99
Node B:100
Node C:100
经过数据同步:
T2 时刻
Node A:99
Node B:99
Node C:99
最终三个节点的数据一致。
这就是:
短时间不一致
↓
数据传播 / 同步
↓
最终一致
六、那 NoSQL 数据库岂不是"不可靠"?
这里很容易产生一个误区:
最终一致性 = 数据不可靠
实际上并不是。
最终一致性只是说:
数据不一定"瞬间一致"。
而不是说:
数据最终会错。
比如微博点赞。
某篇文章真实点赞数是:
10001
由于不同节点同步存在几十毫秒的延迟:
用户 A 可能看到:
10000
用户 B 可能看到:
10001
这个问题严重吗?
通常并不严重。
几十毫秒之后:
用户 A:10001
用户 B:10001
最终所有人看到的数据都会一致。
但如果为了让点赞数绝对实时一致,要求所有点赞请求必须同步多个节点以后才能返回:
用户点赞
↓
Node A 写入
↓
等待 Node B
↓
等待 Node C
↓
全部完成
↓
返回成功
那么点赞这种高并发操作的性能会大幅下降。
这显然不划算。
七、哪些业务适合 BASE?
很多互联网业务其实并不要求强一致性。
例如:
点赞数
1000 → 1001
稍微晚一点同步影响不大。
浏览量
文章浏览量:
PV = 100000
变成:
PV = 100001
晚几十毫秒甚至几秒更新通常也没有问题。
Feed 流
比如微博、朋友圈、社区推荐:
用户 A 发了一条动态
用户 B 晚 1 秒看到,一般可以接受。
搜索索引
例如商品更新:
价格:100 → 90
数据库已经更新,但 Elasticsearch 可能晚几百毫秒同步。
很多系统也能接受这种短暂的不一致。
缓存
经典结构:
Redis
↓
MySQL
Redis 和 MySQL 在某个极短时间窗口内,也可能存在数据不一致。
通常通过:
-
缓存删除
-
延迟双删
-
TTL
-
MQ 同步
-
重试机制
等方式保证最终一致性。
八、哪些业务不能轻易使用最终一致性?
有些业务对数据一致性非常敏感。
例如银行转账:
A → B 转账 100 元
不能允许:
A 已经扣款
B 很久以后才到账
更不能出现账务永久错误。
类似场景还有:
-
银行账户余额
-
支付系统
-
清结算系统
-
核心账务
-
某些严格库存系统
这些场景通常需要更强的事务和一致性保证。
因此实际系统中经常会:
核心数据 → 强一致
非核心数据 → 最终一致
而不是所有业务都使用同一种一致性策略。
九、BASE 和 CAP 有什么关系?
BASE 经常和 CAP 一起出现。
CAP 指的是分布式系统中的三个性质:
C:Consistency 一致性
A:Availability 可用性
P:Partition Tolerance 分区容错
在发生网络分区的情况下,系统通常无法同时完美保证:
Consistency
+
Availability
因为分布式系统基本无法避免网络问题,所以 P 通常必须保证。
系统就需要在:
CP
或者
AP
之间进行权衡。
很多强调 BASE 的系统,会更倾向于:
AP
也就是:
在发生网络问题时,优先保证系统还能提供服务,然后通过异步同步让数据最终一致。
这也是 BASE 的核心思想之一。
十、NoSQL 一定只能提供最终一致性吗?
并不是。
这是一个很常见的误区:
SQL = ACID
NoSQL = BASE
实际上现代数据库并没有这么绝对。
很多 NoSQL 数据库都允许用户在:
一致性
性能
可用性
之间进行调整。
例如 Cassandra 可以通过配置:
ONE
QUORUM
ALL
决定一个请求需要多少副本确认。
MongoDB 也可以通过:
Read Concern
Write Concern
调整读写的一致性级别。
Redis 也可以通过:
-
主从复制
-
WAIT
-
Sentinel
-
Cluster
等机制提高数据可靠性。
因此更准确的说法应该是:
NoSQL 通常更强调可扩展性和高可用性,在某些场景下愿意使用最终一致性换取性能。
而不是:
NoSQL 不保证数据正确。
十一、一个实际的电商例子
假设一个秒杀系统:
用户下单
↓
扣库存
↓
创建订单
↓
写数据库
如果每一步都要求跨数据库强事务:
库存数据库
↕
分布式事务
↕
订单数据库
可能需要使用:
-
2PC
-
TCC
-
XA
这些方案虽然能够提供较强的一致性,但实现复杂,而且高并发下性能压力较大。
另一种方案是:
用户请求
↓
Redis 原子扣库存
↓
Redis Stream / MQ
↓
立即返回
↓
消费者异步创建订单
↓
失败重试
↓
补偿
这种设计允许:
某个短暂时刻:
Redis:库存已经减少
MySQL:订单还没落库
也就是说:
暂时不一致
但是消费者最终会处理消息:
Redis
↓
Stream / MQ
↓
订单数据库
最终变成:
库存正确
订单正确
这就是一个非常典型的 BASE / 最终一致性思想。
十二、总结
ACID 和 BASE 并不是谁先进、谁落后。
它们解决的是不同场景下的问题。
可以简单理解成:
ACID:
我要数据现在就一致
即使性能低一些也可以
BASE:
我要系统高可用、高吞吐
允许数据短时间不一致
但最终必须一致
因此:
| 场景 | 更适合的思想 |
|---|---|
| 银行转账 | ACID / 强一致 |
| 支付账务 | ACID / 强一致 |
| 点赞 | BASE / 最终一致 |
| 浏览量 | BASE / 最终一致 |
| Feed 流 | BASE / 最终一致 |
| 搜索索引 | BASE / 最终一致 |
| 秒杀异步落库 | BASE / 最终一致 |
所以对于:
"NoSQL 使用 BASE,那 NoSQL 还能用吗?"
答案是:
当然可以。
BASE 并不是放弃一致性,而是接受:
在大型分布式系统中,没有必要让所有数据在任何时刻都保持绝对强一致。
对于大量互联网业务而言,使用"短暂不一致 + 最终一致"的方案,反而可以获得更好的:
-
可用性
-
扩展性
-
性能
-
容错能力
这也是 NoSQL 和分布式数据库能够支撑大规模互联网业务的重要原因。