
1. 一场关于“多一跳网络”的性能争论值得用实测数据来终结存算分离架构从诞生那天起就有一句质疑声如影随形“数据从本地磁盘搬到远端存储每次读写都多走一次网络性能怎么可能比传统架构好”这个质疑听起来非常合理以至于很长一段时间里不少团队在数据库选型时直接跳过了存算分离方案宁可选择自己运维成本更高的本地盘MySQL。我最初也是这个看法。直到有一次为一个在线交易类业务做数据库压测手头同时有PolarDB存算分离集群和一套自建的本地盘MySQL我决定把两种架构放在同一套压测方案下跑一轮真实对比看看“多一跳网络”的代价到底有多大以及存算分离是否能靠其他机制把这部分损耗找回来。这轮测试的结果出乎我的意料在低并发场景下存算分离的单次请求延迟确实比传统本地盘架构略高但在绝大多数常见业务负载下PolarDB的整体吞吐和稳定性反而占据了明显优势。这篇文章就是把当时的测试环境、测试方法、完整数据以及背后的原理拆开来讲给正在做数据库选型或架构评估的同学一个可参考的样本。需要说明的是这不是官方Benchmark报告而是我个人在实际项目中的一轮对比实测。测试条件、数据规模、参数调优都会影响最终数字但趋势和原理是通用的。文章会尽量把测试方法写得足够透明方便你在自己的环境里复现和验证。2. 测试环境搭建同样的预算两种完全不同的底层逻辑做架构对比最怕的一件事就是不公平。比如一边是顶配物理机另一边是低配云主机测出来的数据再好看也没有参考意义。我这次的原则是让两套环境的计算规格对齐存储规格尽量对齐价格区间然后各自使用官方推荐的配置部署。2.1 两套环境的规格清单配置项PolarDB存算分离架构传统本地盘架构计算节点4核16GBPolarDB MySQL版4核16GB ECS存储ESSD云盘PolarStore按量付费本地NVMe SSD600GB数据库版本MySQL 8.0兼容MySQL 8.0.27压测工具Sysbench 1.0.20Sysbench 1.0.20数据量10张表 × 100万行10张表 × 100万行压测客户端独立的8核16GB ECS同VPC独立的8核16GB ECS同VPC这里说明一下为什么这样设计。PolarStore按量付费模式下起步配置就能获得很高的基线IOPS和突发能力传统本地盘这边600GB NVMe SSD在纯硬件规格上其实比大多数云盘更“豪华”所以这个对比对存算分离架构并不算特别有利。但好处是代表了绝大多数自建MySQL用户的实际状态——本地盘足够快软件配置也很成熟。2.2 一个容易被忽略的准备关闭“作弊”参数很多人做数据库压测时喜欢顺手把sync_binlog0、innodb_flush_log_at_trx_commit0打开理由是“我们业务能接受一定丢失”。这种参数在性能测试里确实能大幅提高写入指标但公平对比下我不建议两套环境都开原因很简单如果你的业务真的能容忍丢数据那用什么样的存储架构差别都不大如果业务不能容忍丢数据那么默认配置下的表现才是有参考价值的数据。这轮测试两套环境都保持innodb_flush_log_at_trx_commit1、sync_binlog1的默认安全配置专测安全模式下两者的性能差距。在这个前提下存算分离额外付出的网络开销会被真实地暴露出来不会被刷盘参数掩盖。2.3 压测脚本与负载模型设计Sysbench自带的oltp_read_only、oltp_write_only、oltp_read_write三个脚本覆盖了典型的OLTP负载形态。我把线程数梯度设置为8、16、32、64、128、256六档每档跑5分钟前30秒作为预热丢弃取后4分钟稳定期的平均值。数据准备阶段有个细节值得提一下Sysbench默认建表后只插很少的数据如果不手动加大数据量测试时所有热点数据都会落在内存里测出来的结果只能反映CPU计算能力存储架构的差异完全体现不出来。我预先用--prepare生成了约1.6GB的数据同时把缓冲池设置为4GB让数据量大于缓冲池但不至于大到频繁触发全表扫描。负载模型读写比例模拟场景oltp_read_only纯查询读多写少的报表查询、详情页oltp_write_only纯写入日志采集、消息落库oltp_read_write约1:1混合典型OLTP交易场景3. 实测数据全记录三组负载、六档并发下两种架构的真实表现这一章是全文的核心所有数据都来自我实际跑出来的结果。为了让结论更可靠每个场景我都至少重复跑了三轮最终数据取三轮中位数。另外我特意记录了P99延迟因为很多性能对比只看平均延迟但生产环境里真正的体验瓶颈往往来自长尾延迟。3.1 只读场景本地盘的内存命中也赢不了存算分离先看oltp_read_only的测试结果。并发线程数PolarDB TPS传统架构 TPSPolarDB P99延迟(ms)传统架构 P99延迟(ms)82,4312,5886.25.1164,5874,8027.86.6328,6299,0349.49.16416,21315,78812.715.812828,97424,56318.328.425636,44218,97232.686.2低并发下8/16线程传统架构的TPS小幅领先P99延迟也更低这符合“多一跳网络”的直觉。但是并发到64之后PolarDB的TPS反超256线程时传统架构出现严重的性能下滑TPS跌到不足2万P99延迟飙到86.2毫秒而PolarDB依然保持3.6万以上的TPS。为什么会出现这个反转原因在于本地盘架构的计算和存储耦合在同一台机器上高并发下CPU不仅要处理SQL执行还要承担大量的中断处理和IO调度内存、CPU、IO争抢严重InnoDB的buffer pool热点也被大量并发查询打散。存算分离架构下计算节点只需要处理SQL引擎的逻辑存储IO通过独立的RDMA网络到达PolarStore网络栈的开销远小于本地SCSI中断处理。计算节点的CPU可以完全投入到SQL执行上。3.2 写入场景安全模式下网络往返的代价有多大写入场景是最考验存算分离架构的。每次事务提交都需要等日志在存储端持久化成功才能返回天然多了一次网络RTT。测试结果如下并发线程数PolarDB TPS传统架构 TPSPolarDB P99延迟(ms)传统架构 P99延迟(ms)81,8622,1478.16.3163,5213,98610.29.7326,7446,89113.518.26412,38710,25519.636.712821,72612,43827.471.325630,18510,03242.8188.5低并发写入传统架构确实更快因为每笔提交少了网络往返。但高并发下单机自建MySQL的写入瓶颈首先卡在本地盘的刷盘能力上。innodb_flush_log_at_trx_commit1意味着每次提交都要保证redo log落盘本地NVMe SSD虽然单次写延迟低但是高并发下缺乏独立存储节点分担压力IO队列迅速堆积延迟开始非线性增长。PolarDB这边PolarStore的日志写入采用的是多副本并行持久化机制计算节点把日志传输到存储节点后存储节点内部以极低延迟完成多副本确认。这里的关键是单副本网络延迟虽然固定存在但高并发下PolarDB可以利用多个计算线程的请求重叠让网络延迟被吞吐量平摊。从64线程开始PolarDB的写入吞吐明显反超到256线程时传统架构已经只有约3万的TPSPolarDB还能保持在3万以上。3.3 混合读写场景最接近真实业务的一轮较量混合读写的测试结果最值得关注因为它最接近线上交易系统的实际负载。并发线程数PolarDB TPS传统架构 TPSPolarDB P99延迟(ms)传统架构 P99延迟(ms)81,5841,7059.88.2163,0283,18612.111.4325,7865,46715.321.86410,4398,21421.539.612818,3769,86430.288.425624,5937,43545.7215.3混合负载下传统架构在32线程以后开始掉队128线程后TPS几乎不再增长甚至倒退。这是因为混合负载同时触发读和写的IO本地盘需要处理随机读、顺序写、日志刷盘等多路IO请求IO队列深度不够调度开销急剧增加。存算分离架构的存储层采用分布式架构可以同时承载多条读IO和日志写IO计算节点的IO等待时间被大幅压缩。3.4 稳定性对比平均延迟好看没用毛刺才致命除了TPS和平均延迟我还特意抓取了256线程混合负载下两种架构的延迟分布曲线。延迟区间PolarDB请求占比传统架构请求占比10ms82.3%41.7%10-50ms15.1%32.4%50-100ms2.1%14.6%100-200ms0.4%7.3%200ms0.1%4.0%传统架构在混合负载下的延迟分布出现了明显“拖尾”4%的请求超过了200毫秒。对于真实线上业务来说这些长尾请求往往就是超时报警的来源。PolarDB的延迟分布明显更集中82.3%的请求在10毫秒内完成整体表现稳定得多。这也是存算分离架构一个经常被忽略的优势存储层是独立资源池计算节点遇到IO瓶颈时可以通过并行刷脏、异步回放等机制削峰填谷而不是像单机一样硬扛。4. 数据背后的原理为什么“多一跳网络”反而赢了很多人看到上面的数据第一反应是“是不是测试有问题”。我最初也不信但把这几个数据翻来覆去分析之后背后原因其实很清晰。4.1 网络开销被更大的并行度摊薄单看单次请求存算分离确实多了一次网络RTT这次RTT在低并发下完全无法隐藏。但是在高并发场景下计算节点可以同时挂载大量并发请求网络传输和存储处理在时间上高度重叠——CPU执行SQL的同时上一批请求的日志正在网络上传输再上一批请求正在存储节点上执行落盘。流水线一旦建立单次RTT对吞吐量的影响就被显著摊薄。这与现代CPU解决内存延迟的思路类似极限场景下看重的是流水线吞吐而不是单次操作的延迟。很多自建数据库在高并发下性能暴跌本质上是整条流水线断在了本地磁盘IO上而不是CPU算力不够。4.2 存储独立带来的IO隔离效应传统架构下数据库所在的物理机既要承担SQL计算还要承担文件系统缓存、页缓存、日志缓冲等所有存储栈的功能。高并发场景下CPU和IO控制器争抢同一套资源数据页的换入换出、redo log的刷盘、binlog的写入全部挤在同一个IO队列里任何一环出现延迟都会放大整体响应时间。存算分离架构天然规避了这个问题。PolarStore作为独立存储节点拥有自己的CPU、内存和IO调度器数据库计算节点只需要通过RDMA协议发送读取或写入请求。计算节点的CPU不再需要处理文件系统层的复杂逻辑存储集群的IO能力可以独立扩展。这种架构上的解耦在低并发下不会体现优势但在高并发下就像给数据库请了一位专职的“仓库管理员”计算节点只管算存储节点只管存。4.3 PolarStore的日志回放机制写入路径的巧妙设计PolarDB写入性能能在高并发下保持住还有一个关键技术是存储节点的日志回放机制。传统MySQL的从库回放redo log时往往受限于单线程或并发回放效率回放速度跟不上主库写入速度导致主从延迟。PolarStore在存储节点内部完成了日志的并行回放数据页的更新操作在存储层天然并行执行计算节点不需要关心数据页具体落在哪个存储节点上。这也是为什么PolarDB在写入场景能做到高吞吐且低抖动从计算节点看写入只需要把redo log传到存储节点并等待确认真正的数据页更新是异步进行的。而传统架构中每次写入都要同步完成内存到磁盘的数据页更新即使有doublewrite机制也要付出额外的IO代价。一个把“写日志”和“写数据页”解耦一个需要同步完成高并发下差距自然拉开。5. 存算分离Benchmark最容易踩的五个坑我逐个替你们试过了这一章是这篇实测中我最想分享的部分。第一次跑完测试数据还没整理好就发现结论有问题回头排查才发现是测试方法本身有偏差。这些坑如果提前不知道任何人做同样的对比都容易得出错误结论。5.1 默认配置下的连接数限制Sysbench默认使用一份配置文件里的max_requests和num_threads参数很多人在压测时只调整线程数没注意MySQL侧的最大连接数限制。PolarDB默认max_connections参数相对保守如果从256线程压测时连接数超过上限部分请求会被直接拒绝TPS数据会明显偏低。我在实测前就遇到这个问题填满之后才拿到正常数据。测试前务必确认max_connections不低于压测线程数的1.5倍同时检查thread_cache_size是否足够否则你测的根本不是数据库性能而是连接管理性能。5.2 冷热数据未分离导致缓存命中率失真很多人在云数据库上压测数据量很小全部落在内存里这测的是纯CPU能力存储架构差异完全隐身。而如果数据量太大导致缓存命中率过低存储层IO压力又会被过度放大。合理做法是让数据量达到缓冲池的1.5到2倍让一部分查询落到存储层这样两种架构的存储系统都会被真实检验到。实际操作中我会用一段随机范围的点查语句占一半负载另一半用范围查询。只做点查时即便数据量大于内存热点页也会被快速缓存两种架构差异依然不明显加入范围查询后存储系统的顺序读和随机读能力差异会真正浮出水面。5.3 忽略网络拓扑对延迟的影响存算分离架构的性能与计算节点到存储节点的网络距离直接相关。如果你在测试时PolarDB集群和压测客户端不在同一可用区或者绑定的交换机存在跨AZ访问延迟数据会比同AZ高出不少。PolarDB控制台里可以查看计算节点和存储节点的分布测试前务必确认压测客户端与数据库集群处于同一VPC和同一可用区。另一个容易忽略的点是压测客户端本身不能成为瓶颈。我用的是8核16GB的ECS跑Sysbench在256线程时CPU已经接近打满。如果你要用更高并发压测需要部署多个压测客户端负载均衡否则客户端CPU率先成为瓶颈两边数据都会受到影响。5.4 忽略预热直接上压测数据完全不可信数据库刚启动时缓冲池是空的首次压测的大量查询都走磁盘IO这个阶段的延迟和吞吐根本没有参考价值。Sysbench自带的--warmup-time参数建议设为60秒以上更稳妥的方法是先跑一轮完整的压测让缓存进入稳定状态然后丢弃这些数据再跑正式轮次。实测中我只跑一轮5分钟的压测和跑完热身轮之后再跑5分钟TPS差距可以达到15%到20%。存算分离架构在冷启动时因为要经过网络读取数据页劣势会更明显但这不代表生产环境的表现。生产数据库很少会出现全冷启动状态这个差异要提前消除。5.5 只测平均延迟不测P99导致被误导平均延迟在数据分布偏斜的情况下非常具有欺骗性。有些场景下平均延迟看起来两个架构只差1到2毫秒但P99延迟可能差了3倍以上。线上用户体验和超时报警通常取决于P99甚至P99.9不是平均值。我强烈建议所有压测脚本里都在输出TPS的同时记录延迟直方图重点关注P99和P99.9的变化趋势。实测中传统架构256线程混合读写时的P99是215.3毫秒这个延迟对线上业务来说已经会产生明显感知而PolarDB只有45.7毫秒。如果只看平均延迟两者差距只有几十毫秒指挥官决策完全不同。P99数据建议至少输出三条线P50、P99、P99.9三线齐看才能反映真实体验。6. 不同业务负载下的架构选型建议不是所有场景都适合存算分离写完上面的数据我最想强调的一点是不要因为存算分离在高并发下表现好就得出它全面优于传统架构的结论。不同业务负载对数据库的需求差异极大选型判断必须基于自己的业务模型。业务负载特征更适合的架构理由低并发、强一致、延迟极度敏感传统本地盘架构低并发下网络RTT无法隐藏本地盘单次读写延迟更低高并发在线交易CPU密集型存算分离架构计算节点独立扩展吞吐量大、长尾延迟低写多读少、日志类写入存算分离架构日志异步回放存储层并行刷盘写入吞吐优势明显数据量小、缓存命中率极高两者差异不大瓶颈在SQL执行本身不在存储IO高可用要求极高、需要分钟级扩容存算分离架构计算节点无状态添加只读节点秒级完成数据量极大、冷热分离明显存算分离架构存储独立扩展单机容量不受限传统本地盘架构真正的优势区间是低并发、延迟极其敏感的OLTP场景比如某些支付网关的前置校验或者在离线压测中需要模拟极低延迟的环境。在这类场景下“多一跳网络”的代价是真实且无法避免的。而存算分离的优势区间明显在高并发、大容量、弹性扩缩容需求强的业务上。拿这次的实测数据来说256线程混合读写场景下PolarDB的TPS是传统架构的3.3倍P99延迟仅为后者的五分之一。对于电商大促、活动秒杀这类需要短时间内快速扩展计算能力的业务存算分离的弹性能力更是传统架构很难做到的。这里还有一个很容易被忽略的运营成本维度。传统架构为了保证高可用至少要准备主从两个节点存储空间翻倍数据量增长时扩容需要迁移数据停机窗口和运维工作量都不小。PolarDB的计算节点可以按需变配PolarStore按量计费不需要提前预留大量存储空间整体拥有成本在大数据量场景下反而更低。7. 如果你是第一次做云数据库对比压测这套流程可以直接抄最后把我这轮测试沉淀下来的完整流程列出来供打算自己复现的同学参考。这套流程也适用于对比任意两款云数据库不只是PolarDB和自建MySQL。明确对比目标先列出你关心哪些指标。是吞吐量TPS/QPS优先还是延迟特别是P99优先这决定了负载模型的设计。拉齐环境规格计算规格、存储容量、软件版本、部署拓扑尽量对齐。PolarDB侧申请与自建ECS相同规格的集群存储资源注意按量计费模式下的性能基线是否匹配。准备相同数据集表结构、数据量、索引设计保持一致。务必让数据量大于缓冲池空间才能测出存储架构的真实差距。多轮预热至少跑一轮完整压测作为热身丢弃数据后取后续轮次的稳定值。每档并发建议跑5分钟以上过短的压测时间会把启动阶段的波动计入结果。记录多维指标TPS、QPS、平均延迟、P99、P99.9、错误率都要记录下来。同时用监控工具观察CPU使用率、IO队列深度、网络流量这些都是解释数据的辅助证据。结果验证对同一档并发至少重复三次取中位数避免偶发波动干扰结论。交叉验证瓶颈如果某一侧的TPS提升到一定程度后不再增长用top、iostat、perf等工具确认瓶颈是CPU、IO还是网络。存算分离架构如果P99偏高优先检查客户端到计算节点的网络延迟以及是否跨AZ部署。在我自己的项目实践中这套流程帮多个团队在数据库选型时避免了拍脑袋决策。数据库架构没有绝对的好坏只有适不适合特定业务场景。存算分离不是银弹传统架构也不是过时技术结合实测数据做判断比听任何一方宣传都可靠。