分布式的核心 – BASE理论
CAP定理告诉我们,在网络分区发生时,一致性和可用性无法兼得。对于许多互联网业务来说:
短暂的数据不一致(如看到别人几秒前发的评论、商品库存显示略有延迟)是可以接受的。服务完全不可用(如页面打不开、无法下单)是难以接受的。
因此,BASE理论应运而生,为这类场景提供了设计指导:放弃实时强一致,换取高可用和系统弹性。
BASE的核心思想是 “基本可用,柔性状态,最终一致” 。其名称本身就是一个巧妙的双关语:
1.Basically Available(基本可用)
系统在出现部分故障(如节点宕机、网络分区)时,保证核心功能的可用性,而不是完全不可用。
这通常通过“降级”来实现,例如:
1. 返回降级数据(如旧的缓存数据、默认值)。
2. 使用简化版服务流程。
3. 将用户流量引导到其他正常的数据中心。
2.Soft State(软状态/柔性状态)
系统的状态(数据)不需要在所有时刻都保持强一致,允许存在中间状态,并且这个状态可能随时间变化而不同。这个“软状态”源于系统各副本之间可能存在异步的数据同步。
3.Eventually Consistent(最终一致性)
这是BASE理论的最终目标。系统保证,在没有新的数据更新操作后,经过一段不确定的时间(可能是几毫秒,也可能是几分钟),所有数据副本最终会达到一致的状态。它不保证“何时”一致,但承诺“最终”会一致。这是与ACID的强一致性最根本的区别。
与乐观ACID区别
ACID的承诺(包括乐观事务):我向你保证,无论我内部用什么方法(悲观锁还是乐观锁),你看到的数据永远是强一致的。如果做不到,我就让操作失败,也绝不会让你看到脏数据。
BASE的承诺:我向你保证,系统会一直可用,你能一直读写。但你读到的数据可能是旧版本的,不过你放心,只要没人再改,过一会儿所有副本都会同步成最新的。
简单了解分布式数据库
1.常见分布式数据库结构
在分布式数据库中,主节点通常是一个单点(或者通过多主复制,但这里我们先考虑单主)。主从节点的数据都是一致的。对于主节点本身,必须保证ACID,主节点是写操作的唯一入口,必须确保事务的原子性、一致性、隔离性和持久性。否则,整个系统的数据正确性无法保证。从节点可以承担读的任务,1个主节点 + 3个从节点,读吞吐量是单机的4倍,可以承受的并发用户数大幅提升,这对于读多写少的应用(如新闻网站、社交平台)效果极佳。
[读请求]
↗ ↑ ↖
[从节点1] [从节点2] [从节点3]
↖ ↑ ↗
[主节点] ← [写请求]
2.核心优势:高可用
分布式数据库系统确保最终一致性,通过一套精心设计的机制来管理数据副本之间的异步同步。这些机制的核心是:允许数据在短时间内不一致,但保证在没有新写入的情况下,所有副本最终会收敛到相同的状态。
高可用性是分布式系统的核心价值,因为一致性的保障,若主节点发生故障,可以迅速切换到从节点来继续提供服务。
从单次请求的微观视角看,主从分布式付出了更多延迟和复杂度。但从宏观的系统工程视角看,它换来了:
1. 高可用性:系统几乎不停机
2. 数据安全:数据几乎不丢失
3. 读扩展性:读性能可以线性提升
4. 运维便利:可以零停机维护升级
这就是典型的“用性能换可靠性,用复杂度换可用性”的工程权衡。 对于大多数互联网公司来说,业务的连续性比单次请求快几毫秒重要得多。用户无法忍受“网站挂了”,但可以忍受“这个操作慢了0.1秒”。
分布式系统不是为了让单个请求更快,而是为了让整个系统在规模增长时依然可靠可用。
数据一致性保障 – Raft算法
Raft 共识算法。它被称为“可理解的一致性算法”,其目标就是提供一个比Paxos更易理解、更易实现的方案,用于管理复制日志(Replicated Log),这正是分布式数据库保证数据一致性的核心。
Raft的目标是:让这些节点对一系列操作指令(即日志)的顺序达成完全一致。即使部分节点发生故障,整个系统也能继续工作,且不会出现数据分歧。
Raft通过分解问题来实现这一目标,它将共识过程分解为三个相对独立的子问题:
1. Leader选举:系统必须有且只有一个Leader来管理所有决策。
2. 日志复制:Leader接收客户端命令,并将其安全地复制到所有节点。
3. 安全性:确保在任何情况下(如Leader崩溃),已提交的日志条目都不会被覆盖或丢失。
1.基础概念
节点状态:每个节点在任何时刻都处于以下三种状态之一:
Leader:处理所有客户端请求,管理日志复制。一个集群同一时刻最多只有一个有效的Leader。
Follower:完全被动,只响应来自Leader和Candidate的请求(同步日志或投票)。
Candidate:竞选Leader时的临时状态。
任期:Raft将时间划分为任意长度的任期,用连续的整数编号。每个任期都以一次选举开始。一个任期内最多只有一个Leader。任期是逻辑时钟,用于识别过时的信息。
RPC:节点间通过两种RPC进行通信:
RequestVote RPC:由Candidate在选举期间发起,用于拉票。
AppendEntries RPC:由Leader发起,用于复制日志条目和发送心跳(不含日志条目的AppendEntries)以维持权威。
2.Leader选举
这是Raft最直观的部分,就像“班级选班长”。
触发选举:
所有节点启动时都是Follower。
每个Follower都设置一个随机化的选举超时(例如150-300ms)。
只要Follower能定期收到Leader的心跳(AppendEntries RPC),它就保持Follower状态并重置计时器。
如果一个Follower在超时时间内没有收到任何心跳,它就认为Leader可能挂了,于是自增当前任期号,转变为Candidate,发起一轮新的选举。
选举过程:
Candidate首先给自己投一票。
然后向集群中所有其他节点并行发送 RequestVote RPC。
每个节点在一个任期内最多只能投出一票(先到先得),并且只会投票给日志至少和自己一样新的Candidate(这是安全性的关键)。
Candidate可能获得三种结果:
1. 赢得多数票:成为新Leader,立即开始向所有节点发送心跳以确立权威,阻止新的选举。
2. 收到来自更高任期的RPC:认识到已有更新的Leader或Candidate,立即降级为Follower。
3. 选举超时:未赢得选举也未发现更高任期(选票被瓜分),则自增任期,发起新一轮选举。随机化超时大大降低了再次平票的概率。
3.日志复制
这是数据一致性的核心。Leader被选举出来后,就开始为客户端请求服务。
日志结构
每个节点的日志都是一系列条目的有序集合。每个条目包含:
1. 客户端要执行的命令。
2. 该条目被创建时的任期号(Term)。
一个整数索引(Index),表示它在日志中的位置。
复制流程
- 接收命令:客户端向Leader发送一个操作命令。
- 本地追加:Leader将命令作为一个新条目追加到自己的本地日志中。
- 并行复制:Leader通过 AppendEntries RPC,并行地将该条目发送给所有Follower。
- Follower回应:Follower收到RPC后,会进行严格的一致性检查(前一个条目的索引和任期是否匹配),检查通过才将条目追加到本地日志,并回复成功。
- Leader提交:当Leader收到超过半数的Follower的成功回复后,就认为该条目是已提交的。Leader在本地应用该条目到状态机(即执行命令,如更新数据库),并将结果返回给客户端。Leader在后续的AppendEntries RPC(包括心跳)中,会携带最新的提交索引。
- Follower提交:Follower得知某个条目已被提交后,也按顺序将其应用到自己的状态机。
强一致性保证
Raft的一个关键特性是,它保证所有已提交的条目都是持久化的,并且最终会被所有可用的状态机以相同的顺序执行。这就是分布式数据库实现强一致性或线性一致性的基础。
4. 安全性
这是Raft算法的基石,确保在最恶劣的情况下(如网络分区、多Leader脑裂、节点频繁崩溃)都不会出错。核心安全规则包括:
选举限制:如上所述,一个Candidate必须拥有足够新的日志才能赢得选举。这确保了新Leader一定包含所有已提交的条目,从而防止已提交的日志被覆盖。
提交规则:Leader只能提交当前任期内的日志条目(通过计数方式),而不能直接提交之前任期的条目。这条巧妙的规则避免了“已提交条目被覆盖”的极端角落案例。