1. 评估背景与测试环境准备
先说清楚我这次为什么要做TDSQL的评估。我们手上有一套跑了快五年的MySQL在线业务系统,用户量涨上来之后,单库单表的写入压力已经明显顶不住了。主从复制延迟在高峰期经常飙到十几秒,半夜跑批任务的时候甚至会出现锁等待堆积。换硬件、分库分表中间件都聊过,但团队最终把目光落到了分布式数据库上,TDSQL就是重点考察对象之一。
TDSQL是腾讯推出的分布式数据库产品,底层依然是MySQL生态,对外兼容MySQL协议。这个定位对我们这种存量MySQL业务来说非常关键——意味着应用层改造成本能压到最低,DBA的运维习惯也能大部分沿用。但“兼容”这件事不能光看官方文档怎么吹,必须自己动手测。所以这轮评估我没有只看宣传材料,而是专门搭了一套独立的测试环境,从兼容性、运维能力、性能表现三个维度做了完整的实测。
1.1 为什么分布式数据库是刚需,而不是可选
在聊TDSQL的具体表现之前,得先把“为什么需要分布式数据库”这个问题说透。单机MySQL的瓶颈其实就三个:存储容量、计算能力、连接数。容量不够可以堆磁盘,但单库的写入瓶颈卡在磁盘IO和binlog串行写入上;计算能力不够可以加CPU,但一条慢SQL扫全表的时候,再多的核也帮不上忙;连接数更不用说,应用一扩容,连接池一开,几千个连接直接能把数据库打挂。
分库分表中间件(比如ShardingSphere、MyCAT这种)能解决一部分问题,但引入了新的复杂度:中间件本身的高可用、全局ID生成、分布式事务、跨节点join限制、数据迁移工具链……每一个都是坑。TDSQL这类原生分布式数据库的思路是,把分片、路由、分布式事务、弹性扩缩容这些能力内置到数据库内核里,对应用暴露的还是“一个数据库”的逻辑形态。这个思路对业务团队来说是最友好的——你不需要自己维护中间件,也不需要改一大堆SQL,只需要在建表的时候指定分表键,剩下的交给数据库。
1.2 测试环境怎么搭,配置怎么选
这次评估我用了三套环境做对比:一套是原生的单机MySQL 5.7(作为基线),一套是TDSQL单分片(1个分片、1主2从),还有一套是TDSQL三分片(3个分片、每分片1主1从)。这样既能测出TDSQL相对于单机MySQL的损耗,也能看出分片扩展带来的线性度提升。
硬件配置上,所有节点统一用16核32GB的云主机,数据盘用SSD,网络走内网VPC,避免公网延迟干扰测试结果。操作系统是CentOS 7.9,MySQL版本5.7,TDSQL版本用的是当时最新的公开版本。这里有个经验:评估分布式数据库的时候,一定要保证每个分片的硬件规格和单机基线一致,否则测出来的性能差异无法归因——到底是分布式架构的损耗,还是硬件规格不同导致的,根本说不清楚。
另外,测试数据要尽量贴近真实业务。我直接导了一份线上业务的脱敏数据,包含用户表、订单表、商品表、流水表,总共大概10张核心表,数据量在200GB左右。表结构里既有纯int主键的,也有varchar业务主键的,还有需要分表的超大流水表。这样测出来的兼容性和性能结果,比用sysbench灌出来的假数据有说服力得多。
2. 兼容性实测:从MySQL迁移到TDSQL,到底改多少代码
兼容性是这次评估我最关心的维度,因为直接决定了迁移成本。TDSQL对外宣称兼容MySQL协议,但“协议兼容”和“语法全面兼容”是两码事。我的实测方法很简单:把线上库的表结构、存储过程、常用SQL全部导出来,在TDSQL上跑一遍,看报多少错;然后把应用层的Mapper XML和ORM生成的SQL全部抓出来,逐个执行对比结果。
2.1 SQL语法与数据库对象的兼容情况
先说结论:常规的DML、DDL语句基本无障碍。SELECT、INSERT、UPDATE、DELETE、JOIN、子查询、GROUP BY、ORDER BY、UNION这些核心语法,TDSQL都能直接跑,结果与MySQL一致。实际迁移中,我们500多条Mapper SQL里,只有不到10条需要微调,这个比例比我预想的要低很多。
但有几个点必须注意,属于典型的“文档里写了但没人会认真看”的坑:
第一,自增列不能当全局主键用。在单机MySQL里,auto_increment配主键是常规操作。但在分布式架构下,自增列只能在每个分片内保证唯一,跨分片会重复。TDSQL虽然提供了全局自增的能力(通过自增序列实现),但性能上有限制,而且在分布式事务里会有额外开销。我的建议是:凡是需要全局唯一的业务主键,都改成应用层生成的分布式ID(雪花算法或号段模式),或者用UUID。自增列保留用于排序、分页这种非主键场景倒问题不大。
第二,分表键(shardkey)必须提前设计好。这是TDSQL和单机MySQL最大的使用差异。建表时必须指定一个shardkey,后续所有查询如果带上shardkey条件,就能直接路由到对应分片执行;如果不带,就会变成全分片扫描,性能天差地别。比如订单表我用order_id做shardkey,按订单号查询是毫秒级,但如果是按user_id查某个用户的所有订单,就必须全表扫描。这个限制不是TDSQL独有的,所有分布式数据库都这样,关键是要在表结构设计阶段就把业务查询模式想清楚。
第三,跨分片JOIN、子查询和事务有性能红线。语法上支持,但执行效率可能让你怀疑人生。比如A表和B表分片键不同,两个表做JOIN的时候,数据要拉到一个节点上再做关联。数据量小时还凑合,数据量一旦上去,这个操作的代价就是灾难级的。我的经验是:优先把经常一起查询的表设计成相同的shardkey,让关联发生在同一个分片内(TDSQL称之为“亲和性表”),或者干脆在应用层做数据组装。
2.2 事务与隔离级别:分布式事务没你想的那么可怕
TDSQL支持分布式事务,默认隔离级别是读已提交(RC),这点和MySQL默认一致,对大部分业务来说无感。我专门测了跨分片事务的一致性:
- 启动一个事务,分别往两个分片上的表插入数据,手动kill掉其中一个分片节点,再提交事务。
- 结果是另一个分片的写入也回滚了,没有出现“一半提交一半没提交”的脏数据。
- 这个表现说明分布式事务的原子性是靠谱的,底层用的是两阶段提交(2PC)+ 全局时间戳的方案。
但要注意性能。跨分片事务的提交延迟比单分片事务高,实测数据大概是单分片事务的1.5到2倍。如果业务里有大量跨分片事务,一定要评估清楚对整体QPS的影响,或者尽量从业务设计上避免——比如把需要强一致的写操作都收敛到同一个分片内。
隔离级别方面,TDSQL不支持可重复读(RR),只支持读已提交(RC)。对于从MySQL默认RR迁过来的业务,这个问题不大,因为现在主流互联网业务基本都是RC。但如果有依赖RR场景的报表类查询(比如事务内多次读取要求结果一致),就要注意改造,否则可能出现结果漂移。
2.3 索引、字符集与存储过程:容易被忽略的细节
索引方面,TDSQL支持普通索引、唯一索引、联合索引,和MySQL基本一致。但有个坑:唯一索引必须包含shardkey。原因很好理解——如果唯一索引不包含分片键,数据库就没办法在写入时快速定位到唯一性校验的目标分片,只能全分片检查,性能开销极大,而且在高并发下会出现并发冲突。这个限制在建表时就要遵守,不然后面改起来很痛苦。
字符集方面,TDSQL支持utf8、utf8mb4,线上utf8mb4的表直接迁移没问题。排序规则(collation)也基本兼容,但不同版本之间默认值有差异,迁移后最好检查一遍建表语句里的collation是否和原库一致,避免出现排序结果不一致的问题。
存储过程和触发器,TDSQL支持创建和调用,但有一些限制——比如不允许跨分片访问、不允许在存储过程中动态拼接表名,实际我这轮测试里把线上100多个存储过程全部导入,有4个因为跨分片访问报了错,需要改写。我的建议是:能不用存储过程的尽量不用,这个玩意儿在分布式数据库里维护成本高,而且一旦涉及数据迁移和分片调整,排查问题非常痛苦。
3. 运维能力评估:集群运营过程中的真实体验
数据库选型不能只看性能和兼容性,运维能力直接决定了产品上线后DBA团队累不累、事故概率高不高。这一趴我重点测了监控告警、备份恢复、扩缩容三个运维核心场景。
3.1 监控告警体系:能一眼看到集群健康状态吗
TDSQL自带的赤兔管理平台,相当于整个集群的运维驾驶舱。先说优点:集群拓扑一目了然,分片状态、主从关系、延迟情况、存储水位全部可视化展示,这点比纯手工运维MySQL强太多。我实际用下来的核心监控指标包括:
| 监控项 | 查看位置 | 告警阈值建议 |
|---|---|---|
| CPU使用率 | 节点监控 | 大于80%持续10分钟 |
| QPS/TPS | 集群监控 | 按业务峰值留30%余量 |
| 慢查询数 | 慢日志分析 | 单节点大于100条/5分钟 |
| 主从复制延迟 | 分片监控 | 大于5秒持续1分钟 |
| 磁盘使用率 | 节点监控 | 大于70%提前扩容 |
| 连接数 | 节点监控 | 大于80%上限 |
需要批评的是:赤兔平台默认的告警模板偏保守,很多指标默认不开启告警。我遇到过磁盘使用率到了85%都不告警的情况,后来发现是没配置。所以上线前一定要逐项核对告警规则,别依赖默认配置。这个经验适用于所有云数据库产品,不是TDSQL特有的问题。
另外,TDSQL的慢查询日志是独立收集的,可以在平台里直接按分片查看,比单机MySQL的slow log好用。利用这个功能,我在压测阶段定位了好几条隐藏的跨分片扫描SQL,都是在开发环境跑得快、生产环境数据量大之后才暴露的问题。
3.2 备份恢复实战:关键时候别掉链子
备份恢复是我每次选型必测的项目,因为平时用不到,出了事故才见真章。TDSQL支持物理备份和逻辑备份,可以在平台上一键发起。我实际测了两个场景:
场景一:误删数据恢复。模拟了一张业务表被delete误删,通过备份集恢复到指定时间点。整个过程大概40分钟(200GB数据量),恢复出来的数据稽核无缺失。有一个操作细节值得分享:TDSQL的备份文件是保存在腾讯云COS上的,恢复时需要指定COS路径,恢复之前务必确认COS的读写权限和网络连通性,否则会恢复失败。
场景二:全集群容灾演练。我把整个集群的数据节点全部停机,然后从备份集重建了一个全新的集群。这个操作不是TDSQL自动完成的,需要手动创建新集群、导入配置、恢复数据、重新挂载proxy节点,耗时大概3小时。整体流程可操作,但对DBA的要求比较高,需要熟悉整个架构。我的建议是:每个季度至少做一次完整的恢复演练,而且要换人做——因为只有不同的人都按文档能恢复成功,才算真的靠谱。
3.3 扩容缩容:分布式数据库的核心价值所在
扩容能力是分布式数据库相较于单机MySQL的核心优势,我必须实测。测试场景:集群从3个分片扩展到6个分片,观察数据迁移过程对业务的影响。
实际操作下来,TDSQL的扩容流程是:在管理平台上发起扩容 → 自动创建新的分片节点 → 数据自动重新均衡分布。整个扩容过程中,业务读写不受影响,只有部分数据在迁移时会略有延迟上升。我记录了数据:
- 500GB数据从3分片扩展到6分片,耗时约2小时。
- 扩容期间,业务读写QPS稳定,P99延迟从12ms上升到30ms左右,扩容结束后恢复到10ms。
- 有一个细节要注意:扩容期间不要执行大事务和批量DDL,否则会和数据迁移竞争资源,可能拖慢扩容进度甚至报错。
缩容也一样支持,但操作的频率远低于扩容,我只做了功能验证,没有实际业务缩容。从运维角度看,这个弹性扩缩容能力确实比自建MySQL+中间件的方案省心太多,至少不用自己写迁移脚本、不用停机窗口、不用手工校验数据一致性。
4. 性能压测:benchmark数据与调优方向
性能是大家最关心的维度,也是测试耗时最长的一部分。我用了两种方式:一种是用标准工具sysbench做可控基准测试,另一种是用真实业务SQL做混合场景测试,两者结合才敢下结论。
4.1 压测方案设计与参数选择
sysbench压测我跑了四类经典场景:只读、只写、读写混合、复杂查询(含join和group by)。每个场景跑30分钟,预热5分钟,收集中间10分钟的稳定数据。并发数从50逐渐加到200、500。测试命令大概长这样:
# 准备数据,16个表,每表100万行 sysbench /usr/share/sysbench/oltp_common.lua \ --mysql-host=x.x.x.x --mysql-port=15001 \ --mysql-user=test --mysql-password=xxx \ --mysql-db=testdb \ --tables=16 --table_size=1000000 \ --threads=50 --time=1800 --report-interval=10 \ prepare # 跑只读场景 sysbench /usr/share/sysbench/oltp_read_only.lua \ --mysql-host=x.x.x.x --mysql-port=15001 \ --mysql-user=test --mysql-password=xxx \ --mysql-db=testdb \ --tables=16 --table_size=1000000 \ --threads=200 --time=1800 --report-interval=10 \ run真实业务SQL测试的方式是:把线上应用的SQL日志抓下来,按实际调用比例重放,直接用JMeter压测网关接口,让请求穿透到数据库层。这样得到的数据比sysbench更接近真实表现,但缺点是很难隔离数据库本身的瓶颈——如果应用层或网络有问题,数据库测出来的数据就不准。所以两种方式要配合使用,互相验证。
4.2 实测数据解读:分片扩展到底给你带来了什么
先看sysbench的结果。以读写混合场景、200并发为例:
| 环境 | QPS | TPS | P99延迟(ms) |
|---|---|---|---|
| 单机MySQL 5.7 | 18500 | 1200 | 28 |
| TDSQL 单分片 | 17000 | 1100 | 30 |
| TDSQL 三分片 | 46000 | 2900 | 19 |
这组数据有几个非常值得注意的点:
第一,TDSQL单分片的性能相比单机MySQL有微弱损耗。QPS大概下降了8%,这个损耗主要来自代理层的转发开销和分布式事务的时间戳获取。完全可以接受,毕竟多了一层分布式调度能力。
第二,三分片带来的扩展比在2.7倍左右,不是完美的3倍线性扩展。原因有两个:一是部分聚合查询和跨分片操作在分片变多之后,反而需要更多的协调开销;二是测试模型不是完全分布均匀的,热点数据集中在某些分片上。这个结果在分布式数据库里属于正常水平,但也说明一个真相——三节点就能到完美线性扩展属于理想情况,真实业务大多在2倍到2.5倍之间浮动。
第三,分片变多之后,P99延迟反而下降了。这个观察很有意思。原因是并发请求被分散到更多分片上,单个分片的负载降低,队列排队时间减少。所以分布式数据库的价值不仅是提升吞吐上限,还能在大并发下保持更稳定的延迟。
4.3 性能瓶颈定位与几个有效的调优动作
压测过程中遇到的第一个瓶颈是连接数。TDSQL默认的最大连接数设置得比较保守,应用侧连接池一开大,直接触达连接数上限,新的连接请求被拒绝。处理方式是调大max_connections,同时把proxy层的连接空闲超时时间调短,及时回收无效连接。
第二个瓶颈是单分片的热点问题。有张订单表按order_id做shardkey,但某几个头部商家的订单量特别大,导致特定分片的写入压力远高于其他分片。这种场景下单纯加节点解决不了问题,因为热点数据始终落在同一个分片上。我的方案是把订单表改成按user_id+order_id的组合键做shardkey,让同一个用户的订单尽量分散到不同分片,缓解热点。
第三个值得说的优化是批量写入。如果业务需要批量插入数据,尽量用一条INSERT语句插入多行,而不是循环执行单行INSERT。TDSQL对多行批量插入有专门优化,性能差距可以达到5倍以上。这个经验在压测阶段帮了大忙,因为我们灌数据的时候一开始是逐行insert,速度极慢,改成批量insert之后,灌数据的效率直接起飞。
性能调优表(基于实测):
| 调优项 | 操作 | 效果 |
|---|---|---|
| 连接数限制 | 调大max_connections,调短proxy空闲超时 | 避免连接拒绝 |
| 热点数据 | 调整shardkey字段组合 | 分散热点分片压力 |
| 批量写入 | 改用多行INSERT | 写入性能提升5倍以上 |
| 慢SQL | 定位跨分片扫描,改写SQL带shardkey | 关键查询耗时降低90% |
| 参数调优 | 调大innodb_buffer_pool_size到物理内存70% | 读写整体提升约20% |
5. 常见问题与避坑实录
这一节把我这轮评估里实际踩过的坑、以及同行业务迁移TDSQL时普遍遇到的问题做个整理,都是花时间换来的经验。
5.1 高频问题排查速查表
| 问题现象 | 可能原因 | 排查思路 | 解决方法 |
|---|---|---|---|
| 查询特别慢,但单分片数据量不大 | SQL没带shardkey | 查看慢日志是否全分片扫描 | 改写SQL强制带shardkey条件 |
| 应用报“分布式事务冲突” | 多个跨分片事务并发操作同一批数据 | 查看事务阻塞监控 | 业务侧加分布式锁,减少冲突 |
| 扩容后部分查询结果不一致 | 数据还在迁移中 | 查看数据均衡状态 | 等迁移完成后再做数据一致性校验 |
| 备份恢复失败 | COS路径权限配置错误 | 查看恢复任务的错误日志 | 检查COS访问权限和网络连通性 |
| 连接数告警频繁 | proxy连接泄漏 | 查看应用连接池配置 | 调小连接池闲置超时,及时回收 |
| 建表报错“shardkey类型不支持” | 用了float/double做分片键 | 查看错误信息 | 换bigint或varchar类型 |
| 主从延迟持续放大 | 大事务或批量DDL | 查看分片主从延迟监控 | 拆分批处理,避免事务过大 |
5.2 迁移过程中容易忽略的三个风险
风险一:字段类型隐式转换导致路由失效。如果分片键字段是varchar类型,但应用传入的参数是int,MySQL在比较时会把varchar转成int,导致路由计算结果不一致,请求被发错分片。这个问题在单机MySQL里顶多是性能略降,放到分布式数据库里就是全分片扫描的灾难。迁移后一定要检查应用传参类型和表字段类型是否严格一致。
风险二:全局唯一性依赖数据库自增序列。有个业务表原本用自增ID当业务主键,迁移之后发现多个分片写入了重复ID。前面提过,TDSQL的全局自增需要通过特定方式实现,如果你没配置正确,自增列只在分片内唯一。这个问题最容易在迁移初期被发现,但也最容易在迁移设计阶段被忽略。我强烈建议,所有上TDSQL的表,业务主键全部改成应用层生成的分布式ID,不要依赖数据库自增。
风险三:容量规划未考虑分片间不均衡。很多团队做容量规划时,是“总数据量除以分片数”然后按平均值配磁盘。真实业务里数据分布不可能完全均衡,热点表、大字段表、归档数据都可能导致某些分片提前打满。规划时建议按“最大分片不超过均值1.5倍”来做容量冗余,宁可多买一点空间,也不要上线几个月后就要扩容。
5.3 TDSQL与自建MySQL选型建议
最后聊聊选型判断。如果你们的业务只是单库数据量不大、QPS平稳、没有快速增长的迹象,那完全没必要上分布式数据库,单机MySQL加读写分离就够了,这是最省成本的方案。但如果你符合下面任何一个条件,就值得认真考虑TDSQL这类产品:
- 单表数据量超过5000万行,DDL和执行性能都开始恶化。
- 写入QPS持续超过单库上限,并且未来3年还有增长预期。
- 团队已经明确要上微服务拆分,数据库需要按业务维度水平扩展。
- 不想自己维护分库分表中间件和自研数据迁移工具链。
TDSQL不是万能的,它也有自己的限制:跨分片事务性能、数据类型限制、运维复杂度和成本。但作为从MySQL生态平滑演进到分布式架构的路径,它在兼容性和运维体验上的完成度,确实比自建方案或者纯中间件方案高不少。选数据库没有绝对的最好,只有是否匹配你的业务阶段和团队能力。对于大多数MySQL存量业务来说,TDSQL给出的是一条务实、平滑的升级路径。