当前位置: 首页 > news >正文

云计算与大数据进阶 | 26、解锁云架构核心:深度解析可扩展数据库的5大策略与挑战(下)


在数据库的世界里,面对数据如潮水般的增长难题,聪明的工程师早已准备了五大扩展方案来应对,它们就像五把钥匙,以破解着不同场景下的性能困局。

上回书云计算与大数据进阶 | 26、解锁云架构核心:深度解析可扩展数据库的5大策略与挑战(上)-CSDN博客我们初探了纵向扩展、主仆读代理与主–主模式的奥秘,今天就让我们深入后两把钥匙,揭开分区模式与分布式共识模式的神秘面纱,看看它们如何在数据的迷宫中进行开锁。

(4)分区模式:让数据“各就其位”

如何让数据存储与查询更高效??

你有没有想过,当数据库里的数据像滚雪球一样越堆越多时,怎么才能让它既“存的下”又“跑的快”呢?这就是数据库分区的秘密所在。

数据库分区通常有两种模式:水平分区和垂直分区。

数据库分区就像整理书架,有两种常见思路:按 “行” 分(水平分区)和按 “列” 分(垂直分区)。咱们一个个看:

1) 水平分区:把“大表格”拆分成“小抽屉”

水平分区常被称作分表,是谷歌公司的工程师最早在BigTable项目中使用的技术,专门用来应对超大规模数据的存储和查询难题。

比如你有一张 “用户表”,里面存了 1 亿条数据。水平分区就像把这张大表按行 “切成” 很多小表,比如按用户 ID 的奇偶性分成两张表,或者按注册时间分成 “2023 年用户表”“2024 年用户表” 等。

每个小表放在不同的服务器(物理节点)上。比如用户 ID 为奇数的表放在服务器 A,偶数的放在服务器 B。

好处就是:

· I/O 速度飙升:原来查 1 亿条数据要扫描整个表,现在只需查其中一个小表,读写速度自然快很多。


· 负载均衡:不同的小表可以分担查询压力,就像多个收银员同时结账,避免排队。

2)垂直分区:给“胖表格”减肥

垂直分区则是按照列来切分一张表,分区后的每张表通常列数较少。就是说如果一张表有 100 列(比如用户表包含姓名、地址、购物记录、浏览历史等),垂直分区就像把它按列 “拆成” 几张 “瘦表”。比如把常用的 “姓名、地址” 放在一张表,不常用的 “浏览历史” 放在另一张表。

值得指出的是,垂直分区有些类似于数据库正则化操作,但不同的是,正则化是为了减少数据冗余(比如把 “地址” 单独存到一张表),而垂直分区更 “灵活”—— 即使已经正则化的表,还能继续按列拆分,比如把 “用户表” 的 “基础信息” 和 “交易记录” 分成两张表,分别放在不同服务器上。

好处就是:

· 按需加载数据:查询 “用户基础信息” 时,只需访问包含姓名、地址的 “瘦表”,不用加载所有列,节省内存和查询时间。


· 横向扩展更轻松:不同的 “瘦表” 可以独立扩展硬件资源,比如给存储交易记录的表增加硬盘,而不影响基础信息表。

数据库分区是优化数据存储与查询性能的关键技术,通过合理切分数据,可大幅提升系统的并发处理能力。以下是四种常见的分区逻辑规则,结合实际场景带你轻松理解:

①范围分区

范围分区比较容易理解。例如电商数据库中按照商品的销售价格范围来分区:0~<10元,10~<25元,25~<50元,50~<100元,100~<250元,250~<500元,500~<1000元,1000元以上。原表可以以商品价格为key被分成8张表。

②列表分区

列表分区非常简便。例如在微信数据库后台,如果按照注册用户所在省或直辖市信息(该数据既可以通过注册信息来提取,也可以通过对注册IP地址的自动分析来获取)分表,可以分成北京、上海、广东等几十张表。

③哈希分区

哈希分区通常对某个表中的主键进行哈希(或取余)运算后再对表进行分区,参考图1展示的3张表——用户、群聊信息与照片相册都采用了哈希运算,被水平分为n张表。图1展示的第4张表事件则采用的是典型的范围分区方式。

④组合分区

组合分区是以上3种方法组合而成的复合分表方法。图1展示了垂直分区与水平分区如何协同工作。应用服务器访问的数据库Single先被垂直分区,每个表形成了一个独立的数据库逻辑节点,每个节点之上又可以通过水平分区继续形成多个细分逻辑节点。这样二层(甚至更多层)分区可以对数据库层系统实现充分的水平扩展,以获取更高的系统并发性能。

图1:组合分区

分区之后,数据库系统的物理与逻辑构造会因高度分布性而变得复杂,但是从SQL及编程访问API的角度来看,并没有(也不应该)发生任何变化,这就保证了系统在内核经过分区操作后的向后兼容性。

在实现方法上,应用服务层所看到的数据库依然可以是一个完整的数据库及表,但是这只是逻辑上的完整,数据库系统内核要负责实现对分区节点的并发访问。

分区的实现方法较之前的主—仆模式或主—主模式具有一个明显的优势,那就是不同层之间交互的复杂度大大降低。在主—仆/主—主模式中,应用服务层通常需要有明确的逻辑判断来确保写与读面向哪个节点,而分区实现方法则对应用服务层逻辑可以完全透明。

分区规则的选择策略:

场景需求推荐分区规则示例
按区间查询(如时间、价格)范围分区电商订单按年份、价格分表
按固定标签分类(如地域)列表分区社交用户按省份分表
数据均匀分布、随机查询哈希分区高频访问的用户表、交易表
超大规模系统多层扩展组合分区(垂直 + 水平)大型互联网平台的数据库架构

小结:分区是门 “让数据听话” 的艺术
数据库分区就像给数据设计一个 “智能仓库”:
水平分区让数据按 “行” 住不同房间,提高存储和查询效率;
垂直分区让数据按 “列” 精简行李,轻装上阵跑得快;
合理的分区规则,能让数据库在面对海量数据时依然 “从容不迫”。
下次当你听说某个系统能秒级查询千万条数据时,说不定背后就有数据库分区的功劳哦!

(5)分布式共识:如何让多节点达成“数据默契”?

在分布式系统的中,数据就像四散的星,而节点如同独立运行的行星。即便在看似简单的主备架构中,“异步性” 也如同隐藏的暗物质,时刻挑战着数据一致性的根基。今天,我们就来聊聊分布式系统的 “异步诅咒” 与 “共识解药”,看看工程师如何在混乱中搭建秩序。

我们在前文中提到了即便在最简单的主备系统架构中也可能会出现系统内无法保证一致性的问题,这是因为任何分布式系统在本质上都是由“异步分布式”造成的。所有的操作(如网络传输、数据处理、发送回执、信息同步、程序启动或重启等)都需要时间来完成,因此,任何交易、任何事物处理,即便在一个实例内都是异步的,而多实例之间的这种异步性会被放大很多倍。分布式系统设计中非常重要的一个原则就是:与异步性共存,不要追求完美的一致性,但是,可以假设整个系统在大部分的时间内是可以正常工作的,即便部分进程或网络出现问题,整个系统依然可以对外提供服务。

so,异步的本质就是时间差引发的混乱,因为在分布式系统中,每个操作都自带‘延迟buff’:

· 网络传输需要时间(如北京节点到深圳节点的数据包往返约 50ms);


· 数据处理需要时间(如复杂查询可能耗时数百毫秒);


· 节点故障需要时间(如服务器重启可能需要数分钟)。


这些 “时间差” 导致多节点之间的状态永远处于 “不完全同步” 的动态过程中。就像四个人同时编辑同一篇文档,若没有实时协作工具,各自修改后必然出现版本冲突。

异步的放大效应:从单机到集群的蝴蝶效应:

· 单实例内:异步是 “可控的混乱”。例如数据库事务中,写操作先记录日志再修改数据,中间存在短暂不一致,但通过锁机制可控制。


· 多实例间:异步是 “失控的混沌”。主备节点间数据同步存在延迟,若此时主节点故障,备节点可能缺失部分数据,导致 “不一致性窗口” 扩大。


· 典型场景:电商秒杀时,多台服务器同时扣减库存,若异步同步不及时,可能出现超卖(库存为负)或用户看到不一致库存状态。

分布式共识系统中最核心的部分是分布式共识算法,它就如同“数据裁判”一样,被用来保证即使在分布式系统中出现了各种各样的问题,整体服务也依然可以保持在线。其核心目标可概括为三点:合法有效、达成一致、快速终止。

1、合法有效:只对合理数据达成共识(如投票必须基于有效候选人)。
例:金融交易中,只处理金额为正数且账户存在的转账请求。


2、达成一致:所有正常节点最终认同同一结果(如选举只能有一个获胜者)。
反例:“两军通信问题” 中,由于信使可能丢失消息,两支军队无法绝对保证进攻时间一致,象征分布式系统中绝对一致的不可达性。


3、快速终止:避免无限循环投票(如会议必须在有限时间内选出方案)。
例:Raft 算法通过任期(Term)机制,确保 Leader 选举在有限轮次内完成。

 
1) 共识过程的 “人类隐喻”:从聚餐决策看算法逻辑

图2:多任务间形成共识的过程

想象一下,有四人打算去聚餐并决策去哪吃(图2场景)的场景,在图2中,展示了多任务间形成共识的过程,这一过程与我们日常生活中的行为并无本质上的不同。

A、B、C、D这4个人在一起讨论晚上去哪里,一开始A提议去看电影,得到了B的认同,但是C很快提出了去吃饭,D赞同C的提议,随后B改口赞同C的提议,最终A也改为同意C的提议。此时,这4人达成了晚上去吃饭的共识。这就是多任务形成共识最简单的样子。实际的分布式算法中还会引入例如角色、阶段、如何终止共识等问题,老夫会在后文中逐一介绍。

提议阶段:A 提议看电影,B 赞同(初步共识);
冲突阶段:C 提议吃饭,D 赞同,B 改主意(新提议推翻旧共识);
终止阶段:A 最终同意吃饭,全员达成一致(共识终止)。

分布式算法将这一过程抽象为:
角色分工:提议者(Proposer)、接受者(Acceptor)、学习者(Learner);
阶段划分:预投票阶段(确定提议优先级)、正式投票阶段(达成最终共识);
终止条件:多数节点接受同一提议,或超时后重新选举。

形成共识的过程需要有明确的终止算法,否则就会出现悬而不决、无限等待的问题。例如当某个实例(进程)下线后,剩余进程如果无限等待其重新上线,抑或是图2中的4个人层出不穷地提出新方案,那么会导致各方永远无法达成共识。共识算法需要考虑这些因素,并规避其发生。本质上,无论是用何种跨进程的集群内通信方式,算法需要尽可能简洁,让共识的达成(进而终止)代价越低越好。

那么,分布式共识系统应该采用何种通信手段呢?

2)共识算法的通信哲学:从 “泛洪广播” 到 “精准控制”

在前文中,老夫就提到过网络系统的3种通信方式(中心化=广播式去中心化=分层区域广播或多播式,以及点对点分布式)​,对于小型分布式系统而言,最简单和最直接的方式是广播式,但是这其中存在很多细节,因为广播发起者与信息接收者之间的互动逻辑决定了这个交互过程是属于“尽人事听天命”类型的单向一次性传送模式,还是更为可靠的交互模式。要理解这个过程,就需要我们考虑一种可能发生的情况,即如果提议者A在给B、C发出请求后下线,并没有向D发送请求,那么广播算法中就需要考虑加上B、C可以分别向D继续广播的逻辑。

(1) 通信模式的进化之路

1.1广播式(小型系统)
实现:提议者向所有节点发送请求,如 A 向 B、C、D 广播 “去看电影”。
问题:
单向传送可能丢失(如 A 未向 D 发送请求);
冗余通信导致复杂度 O (N²)(N 个节点需 N×(N-1) 次交互)。
改进:可靠广播(Reliable Broadcast),允许节点接力转发(如 B、C 收到请求后主动向 D 广播),确保消息送达。
1.2分层多播(中型系统)
实现:将节点分组,组内广播 + 组间中继。如电商系统按地域分为 “华北组”“华南组”,组内广播同步库存,组间通过少数节点中继同步。
优势:复杂度降至 O (N log N),兼顾效率与可靠性。
1.3点对点(大型系统)
实现:基于 Gossip 协议,节点随机向邻居发送消息,如区块链节点间的交易同步。
特点:去中心化、容错性强,但达成共识时间较长(适合最终一致性场景)。

(2)通信复杂度的 “不可能三角”

模式一致性通信成本适用规模
广播式O(N²)小型(<10 节点)
分层多播O(N log N)中型(10-100 节点)
点对点 Gossip低(最终一致)O(N)大型(>1000 节点)

工程选择

  • 金融交易选广播式(牺牲成本保一致);
  • 社交动态同步选 Gossip(低成本换最终一致)。

在分布式系统中,消息如同往来的信使,若无法保证有序性,就会像混乱的驿站导致政令不通。如何让多节点间的消息传递既 “原子不可分割” 又 “严格按序执行”?今天我们通过 ZAB 和 Raft 算法,揭开分布式共识中的 “秩序密码”。

3)消息有序性的两大核心诉求

(1)事务性(原子性与不可分割性)
原子性:消息要么全成功,要么全失败。如银行转账中,扣款和到账必须同时完成,否则回滚。
不可分割性:消息内容不可被篡改或部分接收。类似古代密信需完整送达,中途篡改或截断则视为无效。

(2)序列性保持
消息需按发送顺序处理。如电商订单系统中,先 “下单” 后 “付款” 的顺序不可颠倒,否则会导致库存与资金状态混乱。

4)ZAB 协议:ZooKeeper 的 “领导 - 跟随” 秩序法则

作为 Apache ZooKeeper 的核心协议,ZAB 通过角色分工 + 阶段式通信实现消息有序性,其逻辑可概括为 “四阶段状态机”:

(1)角色定义
领导者(Leader):唯一写入口,负责生成事务编号(ZXID)、广播消息;
跟随者(Follower):接收并执行 Leader 的指令,参与选举。


(2)四阶段通信流程


① 启动选举阶段:找 “唯一指挥官”
节点启动或 Leader 故障时进入选举状态,通过投票选出拥有最新事务日志的节点为 Leader(假设 ID 大的节点日志更全)。
核心逻辑:每个节点广播选票(包含自身 ID 和日志版本),收到多数派(≥半数)支持后成为 Leader。


② 发现阶段:对齐 “历史账本”
新 Leader(意向领导)与 Follower 通信,确认彼此的事务日志差异。
Follower 向 Leader 发送自身最后一条事务的 ZXID,Leader 根据差异生成同步方案(如补发缺失日志)。


③ 同步阶段:统一 “数据副本”
Leader 向 Follower 发送日志同步请求,Follower 接收后执行并返回确认。
当 Leader 收到多数派确认时,正式成为 “确认领导”,确保所有节点日志一致。


④ 广播阶段:有序 “分发指令”
Leader 接收客户端请求,生成新事务(ZXID 递增),以异步广播方式发送给 Follower。
Follower 收到后先写入本地日志,再向 Leader 返回 ACK;Leader 收到多数派 ACK 后,commit 事务并通知 Follower 执行。


(3)故障检测:心跳机制守护秩序
Leader 定期向 Follower 发送心跳(默认 200ms),若 Follower 超时未收到心跳,触发重新选举。
优势:通过 “任期(Epoch)” 隔离不同选举周期,避免旧 Leader 干扰新集群。

5) Raft 算法:更简单的 “任期 + 日志” 秩序哲学

相较于 ZAB,Raft 以 “模块化设计” 降低复杂度,通过任期(Term)+ 日志复制实现消息有序性,核心组件如下:


(1)角色定义
领导者(Leader):每个 Term 内唯一,负责接收客户端请求、复制日志;
跟随者(Follower):被动接收日志,超时未收到心跳则转为候选者(Candidate);
候选者:发起选举,竞争成为新 Leader。

(2)三大阶段流程


① 选举阶段:用 “任期” 隔离冲突
初始时所有节点为 Follower,超时后(如 150-300ms)转为 Candidate,向其他节点发送选举请求。
收到多数派投票的 Candidate 成为 Leader,任期号递增(如 Term 1→Term 2),旧 Term 的请求自动失效。


② 心跳阶段:维持 “领导权威”
Leader 通过定时心跳(如 100ms)告知 Follower “我还在任”,Follower 重置超时计时器。
若 Follower 超时未收到心跳,重新进入选举阶段,避免 “孤儿 Leader” 问题。


③ 日志复制阶段:按 “任期 + 索引” 保证顺序
客户端请求→Leader 生成日志条目(包含 Term 和索引),按顺序复制到 Follower。
Follower 收到日志后,先校验 Term(必须等于当前 Leader 的 Term),再写入本地日志。
Leader 收到多数派 Follower 的 ACK 后,commit 日志并通知客户端,确保日志顺序与 Leader 完全一致。

图3中展示了在一个有3个节点的RAFT集群中客户端与服务器集群的互动。整个流程围绕着领导角色进程展开,可被分解为10步,而这只是覆盖了上面提到的RAFT算法的广播及日志传播阶段。

图3:RAFT集群中客户端与服务器集群的互动


如上图所示,3种角色及其所负责的任务内容如下:

①跟随者,不会主动发起任何通信,只被动接收远程过程调用(Remote Procedure Call,RPC)。

②候选者,会发起新的选举,对选举任期进行增量控制,发出选票,或重启以上任务。在该过程中,只有含有全部已提交命令的候选者会成为领导者,并会通过RPC调用的方式通知其他候选者选举结果,并避免出现平票的问题[插图]。另外,每个进程都维护了自己的一套日志,这在原生的RAFT算法实现中被称为LogCabin。

③领导者,会定期向所有跟随者发送心跳RPC,以防止因为过长的空闲时间而导致过期(和重新选举)​。领导者通常最先面向客户端进程请求,对日志进程添加处理以及发起复制、提交并更改自身的状态机,并向所有跟随者同步。RAFT共识算法集群进程间的角色转换关系如图4所示。

图4:RAFT共识算法集群进程间的角色转换关系

RAFT描述的是一种通用的算法逻辑,它的具体实现有很多种,并且有很大调整和调优的空间。例如,原始的RAFT算法和一主多备份的架构类似,任何时候只有一个实例在服务客户端请求。如果我们结合图数据库可能的查询请求场景,完全可以分阶段地改造为(难度从低到高)以下几种情况。

①多实例同时接收读请求负载:写入依然通过领导者节点实现,读负载全部在在线节点间均衡。

②多实例同时接收先读再写类请求负载:典型的如需回写类的图算法,全部节点都可以承载图算法,在回写部分先进行本地回写,再异步同步给其他节点。

③多实例同时接收更新请求负载并转发:写入请求可以发送给任意集群内节点,但是跟随者会转发给领导者节点处理。

④多实例同时处理更新请求:这是最复杂的一种情况,取决于隔离层级的需求。如果多个请求同时在多个实例上更改同一段数据,并且有不同的赋值,将会造成数据的不一致性。在这种情况下,实现一致性的最可靠途径就是对关键区域采用序列化访问。这也是我们在本章中反复提到的,任何分布式系统在最底层、最细节、最关键的部分,一定要考虑到有需要串行处理的情形。

目前我们已知的RAFT算法具体实现可能远超100种,例如ETCD、HazelCast、Hashicorp、TiKV、CockrochDB、Neo4j、Ultipa Graph等,并且采用各种编程语言,如C、C++、Java、Rust、Python、Erlang、Golang、C#、Scala、Ruby等。这足以体现分布式共识算法及系统的生命力。

在基于共识算法的高可用分布式系统架构中,我们做了一个比较重要的假设,那就是在大多数的时候,系统的每个实例上都存有全量的数据。注意,我们限定的是“大多数时候”​,言下之意是在某个时间点或切片下,多个实例间可能存在数据或状态的不一致,因此需要在分布式系统内通过共识算法来实现数据的同步,以形成最终的数据一致。我们不应该在存在网络通信时延或系统进程处理时耗的条件下,假设任何需要多进程并发操作的系统中的数据可以保持100%的强一致性。

维度ZABRaft
核心逻辑基于事务 ID(ZXID)的状态机复制基于任期(Term)的日志顺序复制
选举策略优先选日志最新的节点(假设 ID 大 = 日志新)任期内随机选举,超时后重新竞争
通信复杂度四阶段状态机,流程较复杂三阶段模块化设计,逻辑更清晰
时钟依赖依赖集群内 ID 顺序,对时钟同步要求低依赖任期隔离,需节点时钟基本同步
适用场景强一致性场景(如分布式锁、配置中心)通用分布式系统(如数据库主从同步)

从以上内容我们可以看出,从早期复杂的 ZAB 到简洁的 Raft,算法的演进史就是一部 “用规则对抗混沌” 的奋斗史。下一篇,我们将具体聊聊可扩展存储系统的那些事儿! 敬请期待!

最后,将本篇的上下部分以表的形式做个总结:

名称核心招式适用场景效果
纵向扩展升级单机硬件(CPU / 内存)数据量小、增长缓慢简单直接,成本随硬件线性增长
主仆读代理主节点写 + 仆节点读读多写少(如新闻、电商浏览)读写分离,读性能提升显著
主–主模式多主并行写 + 异步同步异地多活(如跨国企业)双活容灾,写延迟略高
分区模式数据拆分到多节点海量数据存储与高并发查询存储 + 计算双重扩展,复杂度高
分布式共识多节点算法达成一致强一致写(如金融、事务系统)数据零丢失,牺牲部分性能

(文/Ricky - HPC高性能计算与存储专家、大数据专家、数据库专家及学者) 

相关文章:

  • mariadb 升级 (通过yum)
  • Profinet转Ethernet IP主站网关:点燃氢醌生产线的智慧之光!
  • 践行“科学智能”!和鲸打造 AI for Science 专属应用
  • 关于能管-虚拟电厂的概述
  • 爬虫攻防战:从入门到放弃的完整对抗史与实战解决方案
  • NFT市场开发技术全解析:从架构设计到实现
  • verify_ssl 与 Token 验证的区别详解
  • [Java][Leetcode middle] 151. 反转字符串中的单词
  • 研读论文《Attention Is All You Need》(7)
  • Axure难点解决分享:垂直菜单展开与收回(4大核心问题与专家级解决方案)
  • LeetCode 35 搜索插入位置题解
  • 力扣HOT100之二叉树:230. 二叉搜索树中第 K 小的元素
  • python-leetcode 67.寻找两个正序数组中的中位数
  • MySQL数据库基础 -- SQL 语句的分类,存储引擎
  • Django框架的前端部分使用Ajax请求一
  • 【数根】2022-1-24
  • Vue 中 v-model 的三种使用方式对比与实践
  • C++23 std::mdspan:多维数组处理新利器
  • 【第二届帕鲁杯】第二届帕鲁杯 主环境 基本完整wp
  • linux安装conda环境-ubuntu
  • 学生靠老干妈下饭、职工餐肉类又多又好?纪委出手整治
  • “大国重器”、新型反隐身雷达……世界雷达展全面展示尖端装备
  • 上昆“学馆制”10年,完成300出折子戏和20台大戏传承
  • 意德首脑会谈,梅洛尼警告欧盟绿色政策面临“工业荒漠化”
  • 陶石不语,玉见文明:临平玉架山考古博物馆明日开馆
  • 朝鲜称将在各领域采取反制措施,应对美国敌对挑衅