常见分布式系统的架构模型分析

在日常开发过程中,经常遇到很多分布式系统或组件,他们的架构、部署方式、读写方式、集群实现方式各不相同,为什么会出现这种情况,就需要结合产生的背景、适用场景来综合分析,本文希望就常见的分布式系统的架构、存储、读写模型,设计的分布式系统包括: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 在流式计算场景下能保证 高可用计算 + 精确一次处理语义。

posted @ 2025-09-05 18:04  星辰下的键盘  阅读(66)  评论(0)    收藏  举报