1.结论
哪个好?
简短的回答是:没有绝对的“好”,只有“更适合”。
- 存算一体(Coupled):胜在 极致性能(尤其是低延迟)。
- 存算分离(Disaggregated):胜在 弹性、成本和灵活性。
目前的行业大趋势是:从“存算一体”向“存算分离”演进,特别是在云原生(Cloud Native)和大数据分析(OLAP)领域。但在对延迟极度敏感的交易型(OLTP)场景中,存算一体依然是主流。
核心区别
| 特性 | 存算一体 (Shared-Nothing / Coupled) | 存算分离 (Shared-Storage / Disaggregated) |
|---|---|---|
| 架构逻辑 | 每个节点既负责计算(CPU/内存),又负责存储(本地磁盘)。 | 计算节点只负责计算(无状态),数据存储在独立的分布式存储池(如 S3, HDFS, EBS)。 |
| 扩容方式 | 耦合扩容:想加磁盘就必须买新机器(哪怕CPU是空闲的);想加CPU就得买新机器(哪怕磁盘是空的)。 | 独立扩容:计算不够加计算节点,存储不够加存储容量。互不干扰。 |
| 数据迁移 | 困难:节点下线或扩容时,需要大量的数据Rebalance(搬迁),由于涉及物理拷贝,非常慢且影响性能。 | 极快:数据在远端存储,计算节点无状态。新增节点只需挂载数据即可,几乎秒级完成。 |
| 性能 (延迟) | 极高:利用“数据本地性”(Data Locality),CPU直接读本地盘,网络开销小。 | 中等:所有数据读写都要走网络(Network I/O),受限于网络带宽和延迟。 |
| 成本 | 较高:资源利用率低(存在短板效应),且通常需要高性能本地盘。 | 较低:可以使用廉价的对象存储(如 AWS S3, OSS),且计算资源可以按需启停(Serverless 基础)。 |
演进的核心原因
- 现在的网络非常快(100Gbps/RDMA),网络不再是绝对瓶颈。
- 企业上云后发现“存算一体”太僵硬了。
主流数据库
1. 交易型数据库 (OLTP)
主流现状:主要还是存算一体,但云厂商正在推存算分离。
- 传统派(存算一体): **MySQL, PostgreSQL, Oracle (单机/非RAC)**。
- 原因: 交易系统(如下单、支付)对延迟要求极高(毫秒级),本地磁盘读写依然是最稳的。
- 云原生派(存算分离): Amazon Aurora, 阿里云 PolarDB, Google AlloyDB。
- 架构: 它们也是 MySQL/PG 协议,但底层把存储剥离到了共享存储层(Shared Storage)。
- 优势: 一写多读,故障恢复极快(不用拷贝数据),存储自动扩容。
2. 分析型数据库 (OLAP) / 数据湖
主流现状:已全面转向存算分离。
- 绝对标杆: Snowflake。它是存算分离架构的鼻祖和推广者,计算节点完全无状态,数据全在 S3 上。
- 大数据体系: Databricks (Spark), Presto/Trino。天然就是存算分离的,计算引擎查 S3/HDFS 数据。
- 国产/开源新秀的转型:
- StarRocks / Doris: 最初是存算一体(为了极致性能),但现在最新的版本都大力主推“存算分离模式”(Shared-data mode),为了降低成本和提高弹性。
- ClickHouse: 典型的一体架构(本地表),性能极快但运维极其痛苦(扩容难)。目前也在尝试通过 S3 存储策略实现分离,但架构包袱较重。
3. 分布式数据库 (NewSQL)
- TiDB / OceanBase: 逻辑上是分离的(KV存储层 TiKV 和 SQL计算层 TiDB 是分开的),但部署上通常为了性能建议混合部署或走专用网络。
如何选择?
选“存算一体”: 如果你的业务是核心交易系统,或者数据量相对固定(TB级),且对查询延迟(Latency)要求在毫秒级。
- 代表: MySQL, ClickHouse (Local模式), Redis。
选“存算分离”: 如果你的业务是海量数据分析(PB级),数据量增长极快,负载波动大(白天忙晚上闲),或者希望降本增效。
- 代表: Snowflake, StarRocks (存算分离模式), 云原生数据库 (Aurora/PolarDB)。
2.ClickHouse
本地表与分布式表
| 表类型 | 本地表 (Local Table) | 分布式表 (Distributed Table) |
|---|---|---|
| 是否存真实数据 | 是 (YES) | 否 (NO) |
| 本质 | 仓库。物理文件真实地存在磁盘上。 | 传送门/路由器。它只是一个视图(View),本身不存数据,只存“配置信息”。 |
| 作用 | 负责存数据、压缩数据、通过索引找文件。 | 负责把请求“分发”给各个节点,并把结果“汇总”起来。 |
| 对应关系 | N 个节点就有 N 个本地表。 | 集群里逻辑上只有一个入口。 |
查询 (Read): 必须查分布式表!
- 如果你查本地表,你只能查到当前连接的那个节点的数据(比如 1/3 的数据),结果是不对的。
- 只有查分布式表,CK 才会帮你去所有节点把数据捞一遍并汇总。
写入 (Write): 这里有分歧(重点)
- 方案 A(官方建议/简单):写分布式表。
- 代码直接 insert 到
test_table_all。 - 优点: 简单,不用管路由。
- 缺点: 数据会先到一个节点,然后再次转发到其他节点,写入性能有损耗,且如果那个转发节点挂了,可能会丢数据或卡住。
- 代码直接 insert 到
- 方案 B(高性能/老鸟做法):写本地表。
- 代码里通过负载均衡(Load Balancer)或者自己在代码里算 Hash,把数据直接 insert 到各个节点的
test_table_local。 - 优点: 性能最强,没有二次转发。
- 缺点: 代码复杂,你需要知道后端有多少个 IP 地址。
- 代码里通过负载均衡(Load Balancer)或者自己在代码里算 Hash,把数据直接 insert 到各个节点的