常见分布式系统的架构模型分析
在日常开发过程中,经常遇到很多分布式系统或组件,他们的架构、部署方式、读写方式、集群实现方式各不相同,为什么会出现这种情况,就需要结合产生的背景、适用场景来综合分析,本文希望就常见的分布式系统的架构、存储、读写模型,设计的分布式系统包括:HBase、Redis、Memcached、ElasticSearch、ClickHouse、ZooKeeper、Kafka。
分布式系统都需要解决高性能和高可用两大痛点。高性能分为存储高性能和计算高性能,高可用分为存储高可用、计算高可用和业务高可用(开源分布式系统一般不会考虑业务高可用,本文不会讨论)
一句话总结
| 系统 | 产生背景 | 存储高性能 | 计算高性能 | 存储高可用 | 计算高可用 |
|---|---|---|---|---|---|
| HBase | Google三驾马车之一Bigtable的开源实现,目的是解决海量数据的随机读写问题(2009年) | 靠 LSM-Tree、顺序写、缓存、Bloom Filter | 靠分布式并行、Coprocessor 下推、数据局部性 | 靠 HDFS 副本、WAL、Master/RegionServer HA | 靠 Region 自动迁移、客户端 Failover、计算下推冗余、结合大数据框架容错 |
| Redis | 为了解决关系数据库查询太慢以及Memcached太简单的问题(2009年) | 内存存储 + 高效数据结构 + 单线程模型 + 顺序写持久化 | 单线程原子操作 + 内存操作 + Lua 脚本下推 | 主从复制 + RDB/AOF 持久化 + Sentinel 自动故障转移 + Cluster 分片 | Cluster 分片并行 + Master/Slave 切换 + 客户端容错 + 服务端 Lua 脚本 |
| Memcached | 为了解决关系数据库查询太慢(2003年) | 内存存储 + Slab Allocation 避免碎片 + 哈希表 O(1) 访问 + 多线程 + libevent | 只支持简单原子操作(INCR/DECR),无复杂计算逻辑,极简设计保证极高性能 | 无持久化、无复制;高可用依赖客户端一致性哈希 + 外部数据库重建缓存 | 客户端路由和重试机制;某节点宕机后,客户端自动跳过并请求其他节点 |
| ElasticSearch | 为了解决互联网数据爆炸式增长带来的全文搜索问题,而传统Lucene单机处理能力有限(2010年) | Lucene 倒排索引 + 列存 DocValues;写入走 translog + 内存 buffer;segment 顺序写 + 合并优化;分片并行写入 | 分布式分片并行搜索;倒排索引加速查询;列存支持聚合/排序;Query/FieldData Cache;近实时搜索 | 主从分片机制(primary/replica);Translog 保证写入可靠;Master 负责分片调度;自动数据均衡 | 分片并行执行;Replica 分片容错和分担读;客户端透明容错;Master 协调路由;可结合大数据引擎 HA |
| ClickHouse | Yandex需要实时分析TB/PB级日志和用户数据,需要大量聚合、统计类查询(2016年) | 列式存储;高效压缩;分区 + 稀疏索引;MergeTree 批量写入;异步合并优化 | 向量化执行(SIMD);多线程并行;分布式执行计划;分区裁剪 + 索引跳过;内存计算 | ReplicatedMergeTree;ZooKeeper 协调一致性;副本恢复;分布式 shard 容错 | 分布式查询容错;副本分担查询;失败重试;无中心化调度避免单点故障 |
| ZooKeeper | 分布式应用越来越多,配置管理、状态同步等共性需求越来越多,受Google发布Chubby论文启发造的一个轮子(2008年) | 内存存储为主;顺序写日志;轻量数据量设计 | 读写分离;Watcher 机制减少轮询;轻量计算逻辑 | ZAB 协议复制;WAL + 快照;过半确认机制 | Leader-Follower 架构;过半原则;Leader 选举;客户端透明容错 |
| Kafka | LinkedIn大规模日志和事件数据激增,内部大量服务间异步通信,传统消息队列能力有限(2011年) | 顺序写磁盘;分段存储;零拷贝;页缓存;批量写入 | 分区并行;消费者组;Kafka Streams / ksqlDB 流处理;压缩传输 | 多副本机制;Leader-Follower 架构;ISR 保证;acks=all 持久化策略 | Leader 自动切换;Consumer Rebalance;事务与幂等;流处理状态快照和恢复 |
HBase
HBase 是一个 构建在 HDFS 之上的分布式 NoSQL 数据库,核心目标是:高吞吐写入、大规模数据存储、强一致性。
存储高性能:
-
HBase 构建在 HDFS 之上,数据按照 Region(区域) 切分,每个 Region 存储一部分表的数据,分布在集群不同节点,天然支持水平扩展。
-
先写 WAL(顺序写磁盘),保证数据持久性,再写 MemStore(内存)。MemStore 达到阈值后 flush 成 HFile(顺序写入 HDFS),避免了随机写磁盘。
-
HFile 是顺序写、分块存储的文件,便于顺序读写;
-
基于 LSM-Tree(Log-Structured Merge Tree)的存储结构
与传统 B+Tree 不同,LSM-Tree 通过批量写、顺序写和延迟合并提升性能。 -
Region 自动分裂(Region Split):当 Region 数据过大时,HBase 自动拆分 Region,并分配到不同 RegionServer,避免单点热点问题。
-
负载均衡(Load Balancing):HMaster 定期把 Region 迁移,保证 RegionServer 的负载均衡,提高整体稳定性和可用性。
计算高性能:
- 数据按 RowKey + ColumnFamily + Timestamp 三维结构存储,RowKey 有序存放,使得按行范围查询和前缀匹配非常高效。
- RegionServer 并行处理,客户端的请求会被分散到多个 RegionServer,充分利用集群的计算和存储能力。
- 多次写入操作合并为大块顺序写,极大降低磁盘寻道开销。
- MemStore:最新数据在内存,读请求可直接返回;BlockCache:将热点数据缓存到内存,减少 HDFS 访问;Bloom Filter:快速判断某个 RowKey 是否存在,避免无效的磁盘 I/O;时间戳版本管理:支持按时间检索数据。
- 通过 Minor/Major Compaction 合并小文件,减少查询时的随机访问,提高读性能。
- 计算下推(Server-Side Execution):HBase 支持 Coprocessor(协处理器),类似数据库里的触发器和存储过程。通过 Coprocessor,可以在 RegionServer 本地执行部分计算逻辑,而不是把所有数据拉回客户端再计算。比如:计数(RowCount)、聚合(Sum、Avg)、过滤(Filter)等操作都可以直接在 RegionServer 内部完成。
存储高可用:
-
HBase 的底层数据都存储在 HDFS,所以它继承了 HDFS 的高可用特性:
-
数据副本机制:每个 HFile(存储在 HDFS 上的文件)会有 3 副本(默认),分布在不同的 DataNode 上;某个 DataNode 挂了,副本还能保证数据可用;即使丢了副本,HDFS 也会自动补齐。
-
NameNode HA:HDFS 早期的单点问题(单 NameNode)现在已经通过 Active/Standby NameNode 架构解决;通过 Zookeeper 或 JournalNode 来实现 NameNode 高可用,避免单点故障。
计算高可用:
-
HMaster 高可用:HBase 集群有一个 Active Master 和多个 Standby Master;借助 Zookeeper 进行 Master 的选举;Active Master 宕机时,Standby Master 会快速接管,保证元数据管理不中断。
-
RegionServer 高可用:数据分布在多个 RegionServer 上,每个 RegionServer 负责一部分 Region;如果某个 RegionServer 宕机:Zookeeper 会感知到失联;HMaster 会把它负责的 Region 重新分配到其他存活的 RegionServer 上;因为数据在 HDFS 上有副本,所以新的 RegionServer 依然能读写。
-
WAL(预写日志)保证数据不丢失:每次写操作先写 WAL(存在 HDFS,带副本);RegionServer 宕机时,可以用 WAL 进行 数据恢复(replay);保证即使节点挂掉,数据也不会丢。
-
ZooKeeper 协调高可用:管理集群元数据、Region 分配、Master 选举;负责监控 RegionServer 的心跳,发现故障时触发 failover。
Redis
存储高性能
内存存储
Redis 把数据放在内存里(而不是磁盘),访问速度接近纳秒级。
高效数据结构
String(SDS)、Hash(ziplist/hashtable)、List(quicklist)、Set(dict/intset)、Sorted Set(skiplist + dict);
针对不同场景选择最优结构,避免额外开销。
单线程事件循环
使用 I/O 多路复用(epoll/kqueue),避免多线程加锁竞争,保证操作有序高效。
持久化顺序写
RDB(快照)和 AOF(追加日志)持久化都是顺序写磁盘,减少磁盘随机 I/O。
👉 结果:读写速度通常在 10 万 ~ 百万 QPS 级别。
计算高性能
单线程模型
避免多线程上下文切换和锁开销,所有命令原子执行,计算逻辑简单。
内存操作
大部分计算(计数、排序、聚合等)直接在内存数据结构上完成,不需要磁盘参与。
原子操作
INCR、HINCRBY、LPUSH 等命令本身是原子操作,避免复杂事务开销。
Lua 脚本下推
把逻辑计算放在服务端用 Lua 执行,减少网络往返(类似 HBase 的 Coprocessor)。
👉 结果:Redis 既能存储,也能在数据侧快速完成轻量计算。
存储高可用
主从复制(Replication)
一个 Master 可以有多个 Slave;
Slave 异步复制 Master 数据,Master 宕机时可以提升 Slave。
持久化
RDB:周期性快照,适合快速恢复;
AOF:写命令日志,支持更高持久性。
哨兵(Sentinel)机制
监控 Master/Slave 节点健康;
Master 宕机时自动选举新 Master,保障服务可用。
Redis Cluster
分片存储(Hash Slot 16384 槽),节点间自动迁移数据;
部分节点宕机时,其他节点接管槽位;
水平扩展存储容量和高可用。
👉 结果:Redis 可以做到节点故障自动切换,数据依然可用。
计算高可用
分片计算
在 Redis Cluster 模式下,数据按槽位分布在不同节点;
计算(比如聚合、统计)分布到各个节点并行执行。
哨兵 + 自动故障转移
节点计算能力随主从切换而迁移,任务不中断。
客户端容错
Redis 客户端支持自动感知槽位迁移,失败重试;
业务层几乎感知不到节点的切换。
Lua 脚本 + Pipeline
保证计算逻辑在服务端执行,减少对网络和单点的依赖;
即使节点故障,脚本可以在新主节点继续运行。
👉 结果:Redis 的计算虽然简单,但通过 Cluster 分片并行 + Sentinel 自动恢复 + 客户端容错,保证了计算的高可用。
Memcached
Memcached 和 HBase、Redis 都不太一样,它是一个 纯内存的分布式缓存系统,目标是“简单、快速”,所以在 存储/计算/高可用 设计上比较轻量。
存储高性能
纯内存存储
所有数据都存放在内存中,直接通过哈希表定位,速度极快。
高效数据结构
使用 Slab Allocation(分片分配器):将内存划分成固定大小的块,避免内存碎片,提高分配效率。
内部维护一个大哈希表,O(1) 时间复杂度访问。
多线程 + 非阻塞 IO
支持多线程处理请求,采用 事件驱动(libevent) 实现高并发。
👉 结果:Memcached 可以轻松达到 百万级 QPS。
计算高性能
轻量计算
Memcached 的定位是 缓存层,主要是 KV 存取,不负责复杂计算。
原子操作
提供一些简单的原子操作(如 INCR/DECR),避免并发冲突。
无额外计算逻辑
不像 Redis 有 Lua 脚本或复杂数据结构,Memcached 保持简单,性能开销更低。
👉 结果:计算性能高,但能力有限。
存储高可用
无内置持久化
Memcached 不支持数据持久化,数据全部存在内存里,进程重启/宕机数据就丢失。
无原生高可用
Memcached 没有主从复制机制;
高可用需要在 客户端或外部系统实现。
常见做法
通过 一致性哈希 将数据分布到多个节点,某个节点宕机时,客户端自动将请求路由到其他节点;
依赖 应用层重建缓存(从数据库重新加载)。
👉 结果:存储高可用基本靠外部补充(DB 持久化 + 一致性哈希路由)。
计算高可用
客户端分布式路由
客户端使用一致性哈希等算法决定数据存放在哪个节点;
某个节点不可用时,客户端自动跳过并路由到下一个节点。
无集中协调节点
没有类似 Redis Sentinel 或 Zookeeper 的集中式管理;
故障恢复由客户端和上层业务保证。
👉 结果:计算请求的高可用依赖于客户端的容错逻辑,而不是 Memcached 本身。
ElasticSearch
Elasticsearch(ES)跟 HBase、Redis、Memcached 不同,它是 基于 Lucene 的分布式搜索和分析引擎,既强调 存储能力,也强调 搜索/计算能力。
存储高性能
基于 Lucene 的倒排索引
文档写入时会建立倒排索引(token → docID 列表),检索非常快。
支持 倒排 + 列存,同时满足搜索和聚合需求。
写入优化
写请求先进入 Translog(事务日志),再写入内存缓冲区(In-Memory Buffer);
定期 flush 到 segment(Lucene 文件),segment 是只读的,写入是追加操作,避免随机写。
合并机制(Merge)
小 segment 会定期合并成大 segment,减少文件数量,提高查询性能。
分片机制(Sharding)
索引按 shard 切分,分布在不同节点上,写入/查询天然并行。
👉 效果:支持海量数据的高吞吐写入和存储,同时保证快速检索。
计算高性能
分布式并行搜索
查询请求会广播到所有分片(primary/replica),分片并行执行搜索;
Coordinator 节点汇总结果并返回。
倒排索引加速查询
基于倒排结构,关键词查询复杂度接近 O(1)。
列式存储(Doc Values)
聚合(aggregation)和排序基于列存储,避免扫描整个文档,提高分析性能。
缓存
Query Cache:缓存过滤结果;
Field Data Cache:缓存排序/聚合需要的字段数据。
近实时(NRT)搜索
通过 refresh 机制,索引写入到 segment 后即可被搜索(默认 1 秒延迟)。
👉 效果:搜索/聚合支持秒级甚至毫秒级响应,能支撑复杂分析。
存储高可用
主从分片(Primary & Replica Shard)机制
每个 shard 都有一个 primary 和若干 replica;
Replica 不仅用于容错,还能分担读请求。
Translog 日志
写入操作会先写 translog,节点宕机时可从日志恢复,保证数据不丢。
集群管理(Master 节点)
Master 节点负责 shard 的分配和迁移;
节点宕机时,Master 会把 shard 副本提升为 primary。
自动数据再平衡
新节点加入或老节点宕机时,shard 会自动迁移,保证数据均衡分布。
👉 效果:数据有副本保障,单节点故障不会导致数据丢失或服务不可用。
计算高可用
分片级并行计算
搜索/聚合请求在多个分片上并行执行,某个分片宕机时,可以用 replica 继续计算。
副本分片参与计算
读请求既可以走 primary 也可以走 replica,提高吞吐量并保证高可用。
客户端透明容错
客户端不需要感知分片位置变化,节点故障/迁移由集群自动处理。
Master 协调
Master 节点维护元数据,确保计算请求能正确路由到分片。
结合外部大数据引擎
与 Spark、Flink 集成时,作业也有任务级容错机制。
👉 效果:搜索/聚合任务不会因单个节点故障而失败,查询结果依然可用。
ClickHouse
ClickHouse 是一个 面向 OLAP 的列式数据库,主要用于高并发、大规模的分析查询场景。它的高性能和高可用设计思路和 HBase/Redis/ES 都不一样,更贴近 数据仓库 + 分布式计算引擎 的结合。
存储高性能
列式存储(Columnar Storage)
数据按列存储而非按行存储,扫描列时只读必要字段,大幅减少 I/O。
压缩机制
LZ4、ZSTD 等压缩算法,减少存储空间和磁盘 I/O。
分区(Partition) + 主键索引(Primary Key Index)
数据按分区存放,结合稀疏索引加速范围查询。
MergeTree 系列引擎
写入先写小文件(part),后台合并成大文件,保证写入快,同时存储结构有序,查询效率高。
异步写入和批量导入
支持批量 insert,降低单条写入开销。
👉 效果:海量数据的高吞吐写入和高压缩比存储,同时保证查询时少读、快读。
计算高性能
向量化执行引擎
查询运算按列批处理(SIMD 向量化计算),显著提升 CPU 利用率。
多线程并行计算
单节点利用多核并发执行,分布式集群跨节点并行执行。
分布式执行计划
查询拆分为多个子任务(scatter-gather 模式),各节点并行计算,Coordinator 汇总。
预聚合与数据跳过
利用稀疏索引和分区裁剪,查询时跳过不相关数据。
内存计算优化
大量操作在内存中完成(join、aggregation),减少磁盘中间结果读写。
👉 效果:ClickHouse 在百万/十亿级数据量下依然能在秒级返回结果,适合实时分析。
存储高可用
副本机制(Replication)
MergeTree 家族引擎支持 ReplicatedMergeTree,数据有多个副本存储在不同节点。
ZooKeeper 协调
使用 ZooKeeper 进行副本一致性管理(写入、合并、同步),保证副本间数据一致。
数据恢复能力
节点宕机后,副本可自动恢复丢失的数据。
分布式存储容错
shard 级别的数据有副本,不会因为单节点宕机导致数据丢失。
👉 效果:节点故障时可从副本恢复,数据不会丢失,保证高可用。
计算高可用
分布式查询容错
查询请求可以在多个副本上执行,如果 primary 节点不可用,查询可转发到 replica。
多副本参与查询
副本不仅用于容灾,还能分担读请求,提高吞吐量。
任务级失败重试
查询子任务在某个节点失败时,可以在其他副本上重试。
无中心化架构
查询调度是分布式的(虽然通常有协调节点),不会因单点故障而瘫痪。
👉 效果:单节点宕机不会导致查询失败,整个分布式集群依然能对外提供查询服务。
ZooKeeper
ZooKeeper 本身是一个 分布式协调服务(主要用于配置管理、命名服务、分布式锁、Leader 选举等),它和 HBase / ES / ClickHouse 不同,不是数据库,也不是计算引擎,而是保证分布式系统“一致性与协调”的核心组件。
它的重点考虑的是一致性,性能并不是它的主要目标。
存储高性能
内存为主,磁盘为辅
数据(ZNode)主要存储在内存中,读操作直接从内存读取,速度极快。
磁盘仅用于事务日志(WAL)和快照,用于持久化和恢复。
顺序写日志
所有更新操作写入事务日志(append-only),顺序写磁盘,写性能稳定。
数据量设计
ZooKeeper 不是用来存储大数据的,只存储少量的配置和状态信息,因此能保持轻量高效。
👉 结论:ZooKeeper 的“存储高性能”主要来自 内存读写 + 顺序写日志,但它不适合大规模数据存储。
计算高性能
轻量化服务
ZooKeeper 只做简单的一致性和状态管理,不做复杂计算,因此计算本身没有“性能瓶颈”。
Watcher 机制(事件通知)
通过监听机制,客户端不用频繁轮询,减少不必要的计算和网络开销。
请求处理线程池
读请求可以高并发处理(从内存直接返回),写请求则通过顺序日志+原子广播处理。
👉 结论:ZooKeeper 并不是计算引擎,它的“计算高性能”体现在 高并发读、低开销事件通知。
存储高可用
复制机制(ZAB 协议)
数据通过 Zookeeper Atomic Broadcast (ZAB) 协议复制到集群中的所有节点。
类似于 Paxos/Raft 的一致性协议,保证数据一致。
事务日志 + 快照
所有更新请求先写 WAL,再写内存,定期生成快照,保证持久化。
过半写成功
更新请求必须得到超过半数节点确认才算成功,保证写入可靠性。
👉 结论:ZooKeeper 的存储高可用依赖 ZAB 协议 + WAL + 多副本一致性。
计算高可用
Leader-Follower 架构
集群选举出一个 Leader 处理写请求,Follower 处理读请求。
Leader 挂掉时,Follower 会发起新一轮选举,保证计算(协调服务)不中断。
过半原则
只要超过半数节点存活,ZooKeeper 就能继续提供服务。
客户端透明容错
客户端会自动感知 Leader 切换,计算请求自动路由到新的 Leader。
分布式锁与一致性保证
即使在网络分区情况下,也能保证一致性(CP 系统:一致性 + 分区容忍性)。
👉 结论:ZooKeeper 的计算高可用是通过 Leader 选举 + 过半机制 + 客户端容错 来实现的。
Kafka
Kafka 本质上是一个 分布式消息队列 + 流式处理平台,既要保证 高性能日志存储,又要提供 高吞吐的消息传递与流式计算。
存储高性能
顺序写磁盘
消息写入采用追加(append-only)模式,避免随机写,充分利用磁盘顺序写的高性能。
分段存储(Segment)
Topic 的每个分区(Partition)由多个 Segment 文件组成,方便快速写入和旧数据清理。
零拷贝(Zero Copy)
发送消息时使用 sendfile 系统调用,直接从文件缓存传输到网络,避免内核/用户态数据拷贝。
页缓存(Page Cache)
Kafka 利用操作系统页缓存,减少磁盘 I/O,提高读写性能。
批量写入(Batching)
Producer 支持批量发送,减少网络开销。
👉 效果:Kafka 在单机上可支撑百万级消息吞吐,靠的是 顺序写 + 批量 + 零拷贝。
计算高性能
分区并行(Partition Parallelism)
Topic 按分区存储,Producer/Consumer 可并行处理不同分区的数据。
消费者组(Consumer Group)
同一组内的消费者分摊分区数据,实现水平扩展。
流式计算(Kafka Streams / ksqlDB)
内置流处理库(Kafka Streams)支持窗口聚合、状态管理、join 等操作;
ksqlDB 提供 SQL 化的流计算接口。
压缩传输
支持 GZIP、Snappy、LZ4、ZSTD 压缩,减少网络带宽占用。
👉 效果:Kafka 可以作为 高性能流式计算平台,依赖 分区并行 + 消费者组 + 内置流处理引擎。
存储高可用
多副本机制(Replication)
每个分区有多个副本(replica),分布在不同 broker 上。
Leader-Follower 架构
分区副本分为一个 Leader 和多个 Follower;
Leader 负责处理读写请求,Follower 异步拉取数据。
ISR(In-Sync Replica)集合
只有同步进度足够接近 Leader 的副本才属于 ISR;
只有 ISR 内的副本才可被选为新的 Leader。
持久化保证
消息写入时可配置 acks=all,确保所有 ISR 副本确认才算写入成功。
👉 效果:即使部分 broker 宕机,只要 ISR 保持过半,数据依然安全,服务不受影响。
计算高可用
副本参与容错
当 Leader 节点宕机时,Kafka 自动从 ISR 中选出新的 Leader,保证消息继续生产/消费。
消费者组重平衡(Rebalance)
当消费者加入/退出时,Kafka 会自动重新分配分区,保证消费不中断。
事务与幂等(Exactly Once)
Kafka 支持事务性写入和幂等 Producer,避免重复消费或消息丢失。
高可靠流处理
Kafka Streams 支持 checkpoint(状态快照)和任务重分配,保证计算任务在失败后可恢复。
👉 效果:Kafka 在流式计算场景下能保证 高可用计算 + 精确一次处理语义。

浙公网安备 33010602011771号