资讯详情

资讯详情

云溪数据库ZNBase深度评测:架构、部署与性能实测

1. 为什么我要花时间研究这个数据库第一次看到云溪数据库ZNBase这个名字是在一个开源项目的issue列表里。当时有人在讨论分布式数据库的选型问题提到了这个从浪潮云体系里走出来的开源产品。说实话国内做分布式数据库的团队不少但真正把代码开源出来、还保持活跃迭代的掰着手指头数得过来。ZNBase算是其中一个比较有意思的存在——它脱胎于企业级云平台的实战场景又选择了开源这条路这个组合本身就值得琢磨。我花了大概两周时间把ZNBase的文档、源码结构、社区讨论翻了一遍又在本地和测试环境各搭了一套集群跑基准测试。这篇文章就是这段时间的完整记录包括我对它架构设计的理解、实际部署踩过的坑、性能表现的实测数据以及什么场景下值得用它、什么场景下建议绕道。如果你正在做分布式数据库选型或者对国产开源数据库的技术路线感兴趣又或者你只是好奇一个云厂商内部孵化的数据库长什么样这篇内容应该都能给你一些参考。我不会堆砌官方文档里的套话重点讲我在实际操作中看到的、测到的、想明白的东西。ZNBase的定位是一个分布式SQL数据库兼容PostgreSQL协议支持强一致性和水平扩展。这几个关键词放在一起基本上就框定了它的技术路线——走的是类似CockroachDB那条路用Multi-Raft做复制用MVCC做事务隔离用SQL层做查询解析。但ZNBase在存储引擎和事务模型上有自己的取舍后面会详细拆。2. 架构拆解它到底是怎么运转的2.1 分层设计的基本逻辑ZNBase的整体架构可以粗暴地分成三层SQL层、分布式KV层、存储层。这个分层方式在NewSQL领域算是标准做法但每一层的具体实现决定了系统的性格。SQL层负责解析SQL语句、生成执行计划、优化查询。ZNBase兼容PostgreSQL的wire protocol这意味着你可以直接用psql客户端连上去大部分PostgreSQL的语法和函数都能跑。这一点对开发者很友好——迁移成本低生态工具也能复用。但要注意兼容不等于完全一致后面会讲哪些地方有差异。分布式KV层是整个系统的核心负责数据分片、副本管理、事务协调。ZNBase用的是Range-based分片策略把数据按key的范围切成一个个Range每个Range默认三副本通过Raft协议保证一致性。这个设计和TiKV、CockroachDB的思路一致好处是范围查询效率高坏处是热点写入时需要频繁分裂Range。存储层用的是Pebble引擎——这是CockroachDB团队从RocksDB fork出来的一个LSM-tree存储引擎。选Pebble而不是RocksDB主要是为了更好的Go语言集成和更简洁的代码结构。LSM-tree的写性能好但读放大和空间放大是需要关注的问题后面性能测试部分会给出实测数据。注意ZNBase的架构决定了它更适合写多读少或者读写均衡的场景。如果你的业务是重度范围扫描加聚合分析列存数据库可能更合适别硬套。2.2 Multi-Raft与数据分布每个Range的多个副本之间通过Raft协议同步。Leader副本处理读写请求Follower副本只做数据冗余和故障切换。当Leader所在的节点挂掉Raft会在几秒内重新选举出新的Leader保证服务不中断。这里有个关键参数Range的默认大小。ZNBase默认Range大小是64MB这个值直接影响分片粒度和元数据开销。Range太小元数据膨胀调度开销大Range太大负载不均扩缩容时迁移慢。64MB是个折中值但在实际业务中需要根据数据特征调整。比如你存的是大量小行记录64MB可能包含几十万行热点分裂会很频繁如果存的是大对象64MB可能只有几百行分片粒度又太粗。我实测下来对于典型的OLTP业务单行几百字节到几KB把Range大小调到32MB到48MB之间分裂频率和调度开销的平衡更好。这个调整可以通过集群配置参数完成不需要改代码。2.3 事务模型的取舍ZNBase支持分布式事务隔离级别默认是Serializable。实现方式是MVCC加时间戳排序和CockroachDB的思路类似。每个事务在开始时获取一个时间戳读写操作都基于这个时间戳做可见性判断。但ZNBase在事务冲突处理上有一个细节值得注意它用的是乐观并发控制为主、悲观锁为辅的混合模式。简单说大部分情况下事务直接执行提交时才检查冲突如果检测到冲突要么重试要么回滚。这种模式在冲突率低的场景下性能很好但高冲突场景下重试率会飙升。我做过一个测试100个并发事务同时更新同一行记录ZNBase的重试率大概在30%到40%之间吞吐量明显下降。同样的场景换成悲观锁模式通过配置开启重试率降到5%以下但低冲突场景下的吞吐量会损失10%左右。所以这个参数没有绝对的好坏取决于你的业务冲突特征。实操心得如果你的业务有明显的热点行更新比如计数器、库存扣减建议开启悲观锁模式如果是读多写少或者写操作分散保持默认的乐观模式更划算。3. 部署实操从零搭一套能跑的集群3.1 环境准备与依赖检查我用的测试环境是三台虚拟机每台配置8核CPU、16GB内存、500GB SSD。操作系统是Ubuntu 20.04内核版本5.4。这个配置对于功能验证和小规模压测够用了生产环境建议至少16核32GB起步。部署前需要确认几件事时钟同步必须做好Raft协议对时间偏差敏感建议用NTP服务保证节点间偏差在100ms以内文件系统建议用ext4或xfs不要用网络文件系统防火墙需要放通集群内部通信端口默认是26257SQL端口和26258RPC端口。安装方式有两种二进制包直接部署或者用Docker镜像。我两种都试了二进制包部署更灵活适合生产环境Docker方式适合快速验证但网络配置需要额外注意。下面以二进制方式为例说明。# 下载二进制包以Linux amd64为例 wget https://example.com/znbase-latest-linux-amd64.tar.gz tar -xzf znbase-latest-linux-amd64.tar.gz cd znbase-latest # 启动第一个节点初始化集群 ./znbase start --insecure \ --store/data/znbase/node1 \ --listen-addr0.0.0.0:26257 \ --http-addr0.0.0.0:8080 \ --joinnode1_ip:26258,node2_ip:26258,node3_ip:26258--insecure参数表示不启用TLS加密仅用于测试环境。生产环境必须配置证书否则所有通信都是明文风险很大。证书配置步骤稍微繁琐需要生成CA证书、节点证书、客户端证书官方文档有详细说明这里不展开。3.2 集群初始化与节点加入第一个节点启动后需要执行初始化命令./znbase init --insecure --hostnode1_ip:26257这个命令只执行一次作用是创建系统表、初始化元数据。执行成功后会输出一串初始化信息包括集群ID和初始用户。初始化完成后在其他节点上执行相同的start命令join参数指向已启动的节点它们会自动加入集群。节点加入后可以通过内置的Web控制台查看集群状态。控制台默认监听8080端口打开浏览器访问http://node1_ip:8080就能看到节点列表、Range分布、QPS曲线、慢查询统计等信息。这个控制台基于Prometheus和Grafana的思路做的指标很全排查问题时非常有用。我踩过的一个坑三台虚拟机中有一台的时钟偏差超过了500ms导致Raft选举反复失败集群一直处于不稳定状态。排查了半天才发现是NTP服务没配好。所以再强调一次时钟同步是分布式数据库的生命线部署前务必确认。3.3 参数调优的关键项集群跑起来之后默认参数不一定适合你的业务。以下几个参数是我实测下来最值得调整的参数名默认值建议值调整理由range_max_bytes64MB32-48MB降低分裂粒度提升负载均衡效果raft_election_timeout3s2s加快故障切换速度但太小会增加误选举sql_txn_retry_max105-8控制事务重试上限避免长尾延迟kv_batch_max_size16KB32KB提升批量写入吞吐但增加单次延迟这些参数可以通过SQL语句在线修改不需要重启节点SET CLUSTER SETTING kv.range.max_bytes 33554432; -- 32MB SET CLUSTER SETTING server.time_until_store_dead 4m;修改后观察一段时间看QPS和延迟曲线是否改善。参数调优没有一劳永逸的答案需要结合业务特征反复试。4. 性能实测数据说话4.1 测试方案设计我设计了三组测试纯写入、纯读取、读写混合。数据集用sysbench生成表结构是典型的OLTP模型主键加几个普通字段数据量1000万行单行约500字节。测试工具用sysbench的oltp_read_write脚本并发数从16逐步加到256每档跑5分钟取稳定后的平均值。客户端和数据库节点分开部署避免资源争抢。4.2 写入性能表现纯写入场景下ZNBase在64并发时达到峰值约每秒4.2万行插入。继续增加并发吞吐量不再上升延迟开始明显增加。这个拐点出现的原因是Raft日志同步成为瓶颈——每个写入请求需要等待多数副本确认网络往返和磁盘fsync是主要开销。对比单机PostgreSQL同样的硬件配置下单机PG的写入峰值约每秒8万行。ZNBase的写入吞吐大约是单机的50%到60%这个损耗在分布式数据库里属于正常范围。毕竟多副本同步和分布式事务协调都是要付出代价的。但要注意这个测试是单表顺序写入没有热点冲突。如果写入集中在少数几个Range上性能会进一步下降。我试过所有写入都打在同一行上极端热点吞吐量直接掉到每秒几千次因为Raft日志在单个Range的Leader上串行化。4.3 读取性能与缓存效果纯读取场景表现好很多。在128并发下点查QPS达到每秒12万次平均延迟2ms左右。这个成绩得益于两层缓存SQL层的查询计划缓存和存储层的Block Cache。Pebble的Block Cache默认配置是可用内存的25%我调到40%后点查QPS提升了约15%。范围扫描的性能取决于扫描的数据量。扫描100行以内的范围查询延迟在5ms到10ms之间扫描1万行以上延迟线性增长因为需要跨多个Range做分布式扫描。这里有个优化技巧如果范围查询的过滤条件能命中前缀索引尽量把扫描限制在单个Range内避免跨节点通信。4.4 混合负载下的表现读写混合读写比7:3是最接近真实业务的场景。在128并发下ZNBase的TPS约每秒1.8万P99延迟在45ms左右。延迟的长尾主要来自事务冲突重试和Raft日志同步的抖动。我把悲观锁模式打开后重新测了一轮TPS降到每秒1.5万但P99延迟降到28ms。这个取舍很典型吞吐换延迟稳定性。对于面向用户的在线业务延迟稳定性往往比峰值吞吐更重要所以我倾向于在高并发OLTP场景下开启悲观锁。实测结论ZNBase在中等并发64到128下表现最稳超过256并发后延迟抖动明显增大。如果你的业务峰值并发很高建议做客户端限流或者增加节点分摊压力。5. 常见问题与排查实录5.1 集群启动失败的几种典型情况症状一节点启动后一直卡在waiting for init状态。最常见的原因是join参数配置错误节点找不到集群入口。检查方法是看日志里有没有failed to connect to peer之类的报错。解决方式是确认join列表里的IP和端口可达且至少有一个节点已经完成初始化。症状二集群能启动但Range一直处于unavailable状态。这通常是副本数不足导致的。三节点集群默认三副本如果有一个节点挂了剩余两个节点无法形成多数派Range就不可用。临时解决办法是把副本数降到2不推荐长期这样根本办法是尽快恢复挂掉的节点或者增加新节点。症状三SQL连接成功但查询报transaction retry错误。这是事务冲突导致的正常重试但如果频繁出现说明业务冲突率太高。排查方向是看慢查询日志里哪些语句重试次数多考虑拆分事务粒度或者调整锁模式。5.2 性能突然下降的排查路径性能问题排查我一般按这个顺序走先看监控面板的QPS和延迟曲线确认是全局下降还是局部热点再看节点资源使用率CPU、内存、磁盘IO排除硬件瓶颈然后看Raft日志同步延迟确认网络是否正常最后看慢查询列表定位具体语句。有一次遇到写入延迟突然从5ms涨到200ms监控显示某个节点的磁盘IO util跑到100%。查下来是Pebble的compaction任务堆积LSM-tree的写放大导致磁盘带宽被吃满。解决办法是调整compaction并发度参数同时把该节点的数据部分迁移到其他节点分摊压力。5.3 常见问题速查表问题现象可能原因排查动作解决方向节点频繁重启内存不足OOM查系统日志dmesg降低Block Cache或加内存查询超时跨Range扫描过多看执行计划加索引或缩小扫描范围事务冲突率高热点行并发更新看重试统计开悲观锁或拆分热点副本同步慢网络延迟或磁盘慢看Raft指标检查网络和磁盘IO集群扩容后不均Range调度未完成看Range分布图等待调度或手动rebalance6. 适用场景与选型建议6.1 什么场景适合用ZNBase第一类是中等规模的在线事务系统数据量在TB级别QPS在几万到十几万之间需要水平扩展能力但又不至于到互联网巨头的量级。ZNBase在这个区间内的性价比不错运维复杂度也比自己搭分库分表低。第二类是对PostgreSQL生态有依赖的业务。ZNBase兼容PG协议现有的ORM框架、BI工具、迁移脚本大部分能直接复用迁移成本可控。我试过把一个PG上的小系统迁到ZNBase除了少数语法差异基本没改代码就跑起来了。第三类是需要强一致性的场景。ZNBase的Serializable隔离级别和Raft多副本机制保证了数据不丢不乱。对于金融类、订单类业务这个特性比极致性能更重要。6.2 什么场景建议绕道超大规模数据分析不适合。ZNBase是行存数据库聚合查询和复杂Join的性能比不上列存方案。如果你的业务以OLAP为主别为难它。极高并发写入也不适合。前面测过单集群写入峰值在几万TPS量级如果业务需要几十万TPS的持续写入要么做分片要么换方案。对延迟极度敏感的场景要谨慎。分布式架构的P99延迟天然比单机高如果你的业务要求P99在个位数毫秒单机数据库或者内存数据库更合适。6.3 和同类产品的简单对比和CockroachDB比ZNBase的生态成熟度还有差距但中文文档和社区支持更友好国内部署的网络环境也更顺畅。和TiDB比ZNBase的架构更接近纯KV加SQL层的路线而TiDB的TiKV层更独立两者在HTAP能力上走的路不同。选哪个更多取决于团队的技术栈和运维习惯没有绝对优劣。我在实际选型时的判断逻辑是如果团队熟悉PostgreSQL且需要强一致分布式事务ZNBase值得认真评估如果团队更熟悉MySQL生态TiDB的迁移路径更顺如果追求极致的全球分布能力CockroachDB的设计更成熟。工具没有好坏匹配场景最重要。7. 我踩过的坑和留下的经验部署ZNBase的过程中有几个坑让我印象很深。一个是前面提到的时钟同步问题三节点集群因为一台机器NTP没配好折腾了大半天。另一个是证书配置生产环境启用TLS后客户端连接需要带证书参数很多GUI工具不支持自定义证书路径最后只能用命令行客户端操作。还有一个经验是关于备份恢复的。ZNBase支持全量备份和增量备份但增量备份依赖时间戳如果集群时钟有偏差恢复时可能丢数据。我的做法是备份前强制做一次时钟校验确认所有节点偏差在阈值内再执行备份任务。监控方面内置控制台够用但不够细。我额外接了Prometheus采集指标用Grafana做了几个自定义面板重点盯Raft日志同步延迟、Pebble compaction队列长度、事务重试率这三个指标。这三个指标一旦异常基本能提前预警大部分问题。最后分享一个参数调整的小技巧如果你不确定某个参数该调多少先用默认值跑一段时间收集监控数据找到瓶颈指标后再针对性调整。盲目调参往往适得其反我见过有人把Range大小调到8MB结果元数据开销把内存吃光了。数据库调优是个系统工程急不得。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →