ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TDSQL分布式数据库兼容性、运维与性能评估实战:从MySQL迁移到分片架构的避坑指南

TDSQL分布式数据库兼容性、运维与性能评估实战:从MySQL迁移到分片架构的避坑指南 前段时间帮一家做金融结算系统的客户做POC业务方把一套跑在MySQL上的账务模块直接丢过来丢下一句TDSQL不是兼容MySQL吗启动起来直接跑就行。结果前三天确实跑得很顺JDBC连上、建库建表、CRUD全通团队里已经有人下结论说这就是个MySQL换壳。等到开始做压测、跑故障演练、看监控面板的时候问题一个个冒出来——不是不能用而是能用和用得好之间隔着对分布式架构的理解鸿沟。那次之后我把整个评估过程重新整理了一遍从兼容性、运维方式、性能表现三个维度逐层拆解。如果你是 DBA、架构师或者正在做数据库选型的技术负责人这篇评估思路可以帮你少走不少弯路。1. 一场压测引发的评估我为什么盯上TDSQL1.1 评估的缘起与三张评估表客户当时的情况很典型核心业务跑在MySQL上数据量到了单库瓶颈读写延迟开始抖动。他们看了一圈分布式数据库TDSQL进入候选名单的理由无非三个腾讯系产品线有金融场景背书、对外宣传兼容MySQL、支持分布式事务。但我做选型有个习惯先把评估这件事拆成一张表避免被厂商的宣讲PPT带着走。当时的评估维度分三层评估维度核心问题评估方法兼容性现有业务代码改动能压到多小直接用真实业务SQL和代码迁移试跑运维性日常DBA工作能否沿用MySQL经验独立部署一整套实例模拟扩缩容/备份/故障性能分布式带来的收益和代价分别在哪SysbenchTPC-C压测分场景记录后面所有内容都是围绕这三张表展开的。先说结论TDSQL确实兼容MySQL但这个兼容是有边界的边界在哪、边界之外怎么处理才是评估真正有价值的部分。1.2 我给评估设的边界条件写这篇之前先交代清楚测试环境避免大家照着做的时候因为版本差异踩坑。我用的TDSQL分布式版版本是当时线上的稳定版本5.7内核兼容模式集群规模是3个数据节点、2个网关节点、2个调度节点另外单独部署了赤兔管理平台和扁鹊监控系统。整体拓扑是标准的计算层-网关层-存储层三层架构。业务场景用的是客户真实场景的简化版一张用户表、一张订单表、一张订单明细表共3100万行订单数据撑在10个分片上。所有压测和生产模拟都基于这套数据因为单纯用sysbench跑个select 1根本暴露不出分布式数据库的真实问题。2. 兼容性评估从JDBC到存储过程逐层过筛2.1 协议与驱动连接层几乎没有障碍先说最基础的连接层。TDSQL的接入节点对外提供标准MySQL协议所以Java系的Connector/J、Go的go-sql-driver、Python的PyMySQL、Node.js的mysql2全部可以直接连不需要换驱动。这一点当时节省了大量改造时间。不过有两个细节值得注意第一连接串里面不需要写特殊的分布式参数但如果你用老版本的JDBC驱动需要确认SSL握手的兼容性。我们当时用的Connector/J 5.1.x连TDSQL的网关节点偶发连接超时后来对比排查发现是网关节点默认开启了SSL校验老驱动握手慢导致的。解决办法要么升级驱动到8.0.x要么在连接串里显式关掉SSL。这不是TDSQL独有很多MySQL生态的中间件都有类似问题。第二连接池参数要重新调。TDSQL的网关节点本身会做连接聚合应用侧连的是proxy而不是后端数据节点所以应用连接池的maxActive可以比连MySQL时调大一些因为后端实际连接数会被proxy收敛。当时把Druid连接池的maxActive从50调到200后端数据节点的线程压力并没有明显上升这就是proxy连接复用的效果。2.2 SQL语义差异窗口函数、排序规则与自增字段连接层没问题SQL语义层才是兼容性的重头戏。先说好消息TDSQL对常见SQL语法支持得比较完整包括多表JOIN、子查询、UNION、聚合函数、窗口函数MySQL 8.0模式的窗口函数语法可以跑、大部分DDL和DML语句存储过程和触发器也能用。我们迁移第一轮业务侧600多条SQL只有不到30条需要改动比例大概5%。但这30条SQL的坑值得展开说第一个坑是分片表的JOIN限制。如果两张都是分片表JOIN的条件里必须带上两个表的分片键等值条件否则网关节点会把SQL下推到所有分片做全表扫描然后在网关层做聚合。功能上能跑通但性能会崩。我们有一条查询用户最近订单的SQLusers和orders表按user_id分片JOIN条件只写了u.id o.user_id这时候网关判断条件是等值分片键关联性能正常但如果写的是WHERE o.create_time xxx这种不带分片键的过滤就会触发全分片扫描一个本来20ms的查询直接变成900ms。第二个坑是自增字段。单机MySQL里自增主键是连续的TDSQL分片模式下自增保证的是全局唯一不保证连续。TDSQL内部是用自增序列实现的相当于一个全局发号器。业务方如果写了INSERT ... SELECT LAST_INSERT_ID()这种代码短连接场景下能拿到本次会话的ID但如果是连接池复用连接且没有清掉上一个会话状态可能拿到旧值。实际改造时统一改成了先插入再按业务订单号反查ID。第三个坑是排序规则和隐式转换。TDSQL内核走的还是MySQL那一套但分片键字段的数据类型如果和SQL里的参数类型不一致隐式转换可能导致网关路由计算错误。我们遇到过varchar分片键传入数字参数网关按哈希计算后路由到错误分片返回空结果集排查了很久。后来规范要求所有分片键的查询参数强制显式转成字符串。另外补一个冷门点GROUP_CONCAT函数在分片模式下返回的结果顺序不保证因为不同分片返回的partial结果在网关层合并时顺序取决于各分片返回的先后。业务上如果依赖这个函数的默认排序需要显式加ORDER BY。2.3 周边生态兼容ORM、中间件与BI工具实测现在很多业务系统用ORM框架这块也得过一遍。我们实测了MyBatis-Plus、Spring Data JPA、Hibernate三种只要不走分片键查询的查询条件都能直接跑通框架生成的SQL基本兼容。但注意一点MyBatis-Plus的Page分页插件在TDSQL上会生成LIMIT offset, size当offset很大的时候比如超过100万网关层的聚合排序和limit下推逻辑会让性能下降明显。这种深分页场景建议改成基于分片键的游标分页。中间件层面有个反直觉的事不要给TDSQL再套一层ShardingSphere。我们刚开始觉得加ShardingSphere可以做读写分离和数据脱敏结果两层分片逻辑叠在一起网关层路由和ShardingSphere的路由互相冲突数据分布完全乱掉。正确做法是让TDSQL网关承担分片路由业务侧只要保持单库连接方式就好。TDSQL的设计哲学就是对业务隐藏分片中间件层越薄越好。BI工具方面FineReport和帆软连接TDSQL走的也是MySQL协议连接和元数据读取正常但大量BI报表的SQL往往是复杂的多表JOIN不带分片键过滤条件的会触发全分片扫描。针对BI查询建议单独建一个汇聚库通过TDSQL的数据同步能力把各分片数据汇集到单表BI只查汇聚库避免查询压力打散到所有数据节点。3. 运维视角把TDSQL当MySQL管第一天就吃大亏3.1 节点拓扑与监控维度的变化传统MySQL DBA上手TDSQL的第一道坎是拓扑认知。以前管一主两从看主从延迟、看半同步复制状态、看binlog位点这套经验在TDSQL上不够用了。TDSQL分布式版的节点分三类网关节点接入和路由、调度节点元数据管理和任务调度、数据节点实际存储计算。数据节点内部还有强同步复制机制一组数据节点里通常包含一主一备主备之间通过强同步协议保证事务不丢失。所以监控维度从一个实例变成了整个集群监控对象MySQL传统指标TDSQL需要额外关注的指标网关层无对应proxy连接数、请求队列深度、分片路由耗时调度层无对应节点心跳、元数据一致性、任务调度延迟数据节点CPU/内存/磁盘/慢查询分片数据分布均匀度、主备强同步状态、binlog堆积集群整体无对应集群容量水位、重分布任务进度、跨分片事务比例刚开始我把MySQL那套告警规则直接搬过来结果第一天就漏了一个关键问题某个分片的磁盘使用率到了85%而其他分片只有40%。单看每个节点的磁盘监控85%还没触达90%的告警阈值但这是数据倾斜的征兆。等到建了倾斜告警才发现那个分片上的数据量已经是其他分片的两倍。这种事在MySQL单实例上不存在在分布式架构里必须当作一等一的故障隐患来看。3.2 备份恢复、扩容与版本升级的实际操作运维的高频操作是备份、扩容、升级这三项TDSQL都有配套方案但注意事项和MySQL差异很大。备份恢复。TDSQL支持物理备份和逻辑备份可以基于备份文件做时间点恢复。实际运维时我建议启用到备份文件所在的独立存储不要放在数据节点本地磁盘否则磁盘故障时备份和数据一起丢。恢复的流程和MySQL单体物理备份恢复有点类似但需要先在赤兔管理平台上注册一个空的集群再把备份文件分发到对应数据节点。整个流程走下来大概40分钟数据量1TB规模这和MySQL的恢复时间差不多但步骤多了一个集群注册环节。在线扩容。这是分布式数据库的核心卖点。TDSQL支持在线增加数据节点扩容过程会自动触发数据重分布。但要注意重分布期间IO压力明显上升如果业务高峰期扩容会让延迟翻倍。我们的操作经验是把扩容窗口安排到凌晨并且一次只加一个节点观察重分布速率正常后再加下一个。重分布速率受限于网络带宽和磁盘IO1TB数据迁到新节点大概需要1到2个小时期间旧节点数据只读不阻断业务。版本升级。TDSQL升级是滚动式的数据节点逐个升级每个节点升级时会把该分片的主备切换一次。这个切换过程业务无感知但如果你在升级期间刚好有分布式事务在跑事务会被回滚。稳妥做法是升级前先做一轮连接数高峰检测并且给每个业务账号设置一个维护窗口级别的只读权限切换开关。3.3 巡检清单我最常看到的几类隐患几个月运维下来我总结了一份分布式巡检清单不一定全面但都是亲眼见过的坑分片倾斜检查。每个分片的表行数、磁盘占用、活跃连接数三个指标拉出来对比偏差超过20%就要查分片键设计。网关节点资源。proxy的内存使用量会随着连接数增加而上升如果出现频繁Full GC往往是有业务连接泄漏。可以在网关节点的监控页面看活跃连接数和内存曲线是否同步增长。跨分片事务比例。如果监控里跨分片事务占比超过30%性能衰减会比较明显优先排查业务SQL是否漏写了分片键。binlog和日志空间。数据节点和网关节点的日志默认保留天数可能不一样磁盘小的时候网关节点的访问日志最容易先把磁盘撑满。强同步状态。强同步模式下如果备节点临时故障主节点的写入性能会受到影响。建议给强同步状态单独配一个告警通道别和普通告警混在一起这个状态变化非常值得留意。4. 性能测试的三种典型场景与结果分析4.1 压测方法与工具准备性能部分我是用Sysbench和TPC-C混合来测的。Sysbench主要测单表简单查询和只写场景TPC-C模拟的是订单库存支付这类复杂事务模型。压测环境是3个数据节点10个分片每分片300万行订单数据。机器配置统一是16核32G SSD网络万兆。测试前我把数据预热了30分钟确保InnoDB缓冲池里的数据页是热的避免冷数据读放大干扰结果。压测有几个前置条件容易被忽略先列一下关掉查询结果集的网络压缩。网关层默认开压缩的话CPU会有额外消耗压测数据不代表真实水平。确认binlog刷盘策略。TDSQL强同步模式下binlog刷盘策略对TPS影响很大建议测试时用生产同款配置不要用默认值。分片键要均匀。我用user_id做分片键测试数据先生成好再灌库确保每个分片的数据量和访问热度接近。4.2 读多写少场景网关路由的代价先测的是读多写少场景比例大概是95%读、5%写用Sysbench的oltp_read_write模式跑。结果比较有意思单分片键点查SELECT * FROM orders WHERE user_id ?的P99延迟是1.8ms左右对比客户原来的MySQL单机1.2ms网关层多了一次路由计算和网络转发大概增加了0.6ms。这个代价在点查场景下可以接受。但非分片键查询就是两个世界了。SELECT * FROM orders WHERE order_no ?这种查询order_no不是分片键网关只能把请求广播到所有10个分片然后等所有分片返回结果再做汇总。实测P99延迟到了38ms是分片键查询的21倍。数据量越大、分片越多这种全分片扫描的放大效应越严重。所以读多写少场景的结论是分片键命中与否决定了TDSQL和MySQL的性能差距方向。业务能保证每条查询都带分片键性能接近甚至超过单机MySQL一旦出现大量非分片键查询性能会随分片数量线性恶化。4.3 写入与分布式事务场景2PC的现实开销写场景我用TPC-C的新订单事务来压这个事务涉及订单表、订单明细表、库存表三张分片表的写入天然是分布式事务。TDSQL的分布式事务基于两阶段提交2PC配合内部协调者保证一致性。实测下来全部数据落在同一个分片的事务同分片事务TPS约8200。跨分片事务三张表分布在两个以上分片TPS掉到约2600降幅68%。这就是分布式事务的现实代价。每笔跨分片事务要多一倍的prepare/commit往返协调者还要写事务日志延迟和吞吐都会受影响。TPC-C标准的完整事务里约30%的订单跨分片整体TPS大约在3800左右比同分片事务差不少。这并不是TDSQL的问题任何分布式数据库处理跨分片强一致事务都有这个代价。关键在于设计上尽量让事务内所有的写操作落在同一个分片。举个例子把订单表、订单明细表都按user_id分片那么一个用户下订单这件事的所有写入都落到同一个分片上事务退化为单分片事务TPS可以拉回到7000以上。只有查询所有分片的汇总报表这类分析型事务才不得不跨分片。批量写入场景也测了一轮。原来MySQL习惯用INSERT INTO ... VALUES (...), (...)...批量插TDSQL同样支持而且效果明显。我们测了100条一批和单条插入对比批量模式总耗时只有单条的1/7业务方改造的时候强烈建议把写入接口改成批量模式收益立竿见影。4.4 慢查询分析与参数调优实测压测过程中暴露出几条慢SQL正好拿来做调优案例。第一条是统计类查询SELECT user_id, COUNT(*) FROM orders WHERE create_time ? GROUP BY user_id这条SQL不带分片键所有分片都要把符合条件的行全部扫描一遍再回网关层做GROUP BY。压测时这条SQL跑一次要4.2秒。优化方案有两个方向要么改成定时预计算结果写入一张按天汇总的分片表查询只扫汇总表要么在TDSQL的监控页面开启全分片扫描SQL明细功能把这类SQL找出来做应用层改造。预计算方案上线后查询时间降到了80ms。参数调优方面我实际调整过三个参数innodb_buffer_pool_size数据节点默认只分配了服务器物理内存的60%我们的机器是32G调到20G之后读写性能提升约15%。这个参数和MySQL完全一样。网关层连接队列长度压测中发现proxy的请求排队数超过200时P99延迟会明显拉高。把队列长度调大并配合应用端连接池上限调整后排队数稳定在50以下。事务日志刷盘策略强同步模式下为了数据安全默认每次事务提交都要同步刷盘。如果业务可以容忍秒级故障窗口可以调整为组提交模式TPS能提升30%左右。但这个取舍必须由业务方确认DBA不能自己拍板。5. 分片键分布式数据库性能与可用性的总开关5.1 分片键选错后的典型症状写到现在不管是兼容性、运维还是性能所有的坑最后都指向同一个根源——分片键。这也是整个评估过程中我们团队最痛的领悟。分片键选错的典型症状有三个第一数据倾斜。某个分片的磁盘使用率和活跃连接数比其他分片高出一大截热点全打在一个节点上。我们测试时一开始用订单日期作为分片键结果近三个月的数据全集中在两个分片里这两个分片的IO直接打满其他分片空闲。这个属于典型的按时间序列分片反模式。第二非分片键查询比例飙升。分片键如果是order_no业务员查某个客户的所有订单就尴尬了因为查询条件不带order_no网关只能全分片广播客户越大的查询越慢。第三分布式事务比例居高不下。分片键设计没有考虑业务的事务边界导致每个业务操作都要跨分片协调。5.2 三种分片方式与广播表的使用场景TDSQL支持三种分片方式按实际使用频率排序哈希HASH分片根据分片键的哈希值取模路由到分片。适合分片键取值分布均匀、查询以等值条件为主的场景。我们订单表默认就是这种。范围RANGE分片按分片键的值范围划分区间适合按时间范围做数据生命周期管理的场景比如日志表。但要注意范围分片天然容易产生写入热点最新时间段的数据会全部落在同一个分片里。列表LIST分片按分片键的枚举值列表路由适合省份、机构这类固定枚举。除了分片表TDSQL还有一个广播表小表广播的概念。把配置表、参数表这类数据量小、几乎不更新、高频关联查询的表设置为广播表每个分片都会存储一份完整副本查询时不需要跨分片JOIN。我们当时把客户等级表、产品配置表设成了广播表JOIN性能提升非常明显。注意广播表不适合频繁更新的表因为每次更新都要同步给所有分片写放大倍数等于分片数量。5.3 一次失败的改分片键经历讲个反面案例。产品经理在测试阶段提出原定的user_id分片键不能满足管理员后台按手机号模糊查用户的需求要求把分片键改成手机号。我们查了一圈TDSQL不支持在线修改分片键。想改分片键只能新建一个按手机号分片的新表把旧数据全量迁移过去业务代码里的查询条件全部改成先按手机号路由。旧表的数据还要保留一段时间做双写兼容。整个改造评估下来DBA工作量2人天业务改造工作量5人天数据全量迁移和校验3天而且迁移期间不能做在线DDL变更。后来我们说服产品经理采用了一个折中方案保留user_id分片新建一张手机号到user_id的映射表用手机号分片管理员后台先查映射表再查订单表。这样既满足了需求又不用动核心表的分片键。这个案例的教训是分片键必须在建表之前设计好而且设计依据不是哪个字段最常用而是这个表的所有重要查询条件里哪个字段能最大化把查询和事务收敛到单分片。通常联合主键里的业务标识字段比随机生成的sequence更适合当分片键因为业务上天然按它聚集数据。6. 回到现实TDSQL适合谁迁移前要想清楚什么6.1 哪些场景我建议用TDSQL经过这轮评估我对TDSQL的适用场景有了比较清晰的边界感。适合用TDSQL的场景有这么几类高并发在线事务处理OLTP业务量达到单机MySQL瓶颈需要水平扩展且查询能够按分片键收敛。典型如订单中心、支付流水、账户台账、积分系统。强一致事务要求高金融、交易类场景下数据不能丢、不能错TDSQL的强同步复制和分布式事务能力在这个维度上是加分项。已有MySQL技术栈团队全是MySQL DBA不想引入一套全新的运维知识体系TDSQL的学习曲线相对平缓。不建议用的场景也有报表和分析型业务大量跨分片聚合查询在分布式架构下反而是负担建议用分析型数据库。数据量不大、但关系复杂几十张表强关联分片键很难设计得让所有JOIN都收敛这种情况单机MySQL或者传统主从架构反而更简单高效。超高并发写入但无需强一致如果需要的是最终一致性加极致写入吞吐NoSQL或类NewSQL可能是更合适的路线。6.2 迁移改造的隐形成本很多决策者只盯着兼容MySQL四个字以为迁移成本约等于零。实际上迁移工作至少包含这几个隐藏项分片键改造存量表如果本身没有合适的分片键字段或者唯一键不包含分片键就得加字段、改写入逻辑。这是最大头的成本。SQL代码整改非分片键查询、跨分片JOIN、自增字段依赖这类问题需要逐条Review和改写。我们当时600条SQL改了30条但改这30条花了整个项目周期四分之一的时间。数据迁移工具链TDSQL提供了数据迁移工具但从MySQL迁移到TDSQL前建议先做一次全量数据校验脚本避免源库和目标库之间字符集、排序规则不一致导致的数据差异。运维流程重建备份恢复演练、扩容演练、故障切换流程都要重新设计和验证。这部分在项目计划里经常被压缩但恰恰是上线后最要命的环节。6.3 一张评估检查清单按我这轮评估的完整流程整理了一份清单可以直接拿去用作选型参考[ ] 列出业务核心表的所有查询场景标注每个查询是否带分片键等值条件[ ] 检查所有唯一索引和主键确认是否包含分片键[ ] 统计跨分片事务比例超过30%要重新评估分片键设计[ ] 验证JDBC/ORM/BI工具的连接兼容性[ ] 跑一遍真实业务SQL集统计需改写的SQL比例和复杂度[ ] 做一次备份恢复演练记录RTO和RPO是否符合预期[ ] 在线扩容演练确认扩容期间业务延迟可接受[ ] 压测同时覆盖分片键查询和非分片键查询别只测乐观场景[ ] 检查数据倾斜监控和告警是否完善[ ] 确认版本升级方案和回滚方案可执行这份清单不是TDSQL独有的任何分布式数据库选型都适用。核心逻辑就一条别在POC阶段只看厂商演示的顺畅场景把生产环境最难啃的存量SQL、最恶劣的查询模式、最高频的运维动作全部提前试一遍。我后来再参与分布式数据库选型习惯把分片键设计评审放在所有工作的第一步而不是等压测发现问题再回头改。数据库一旦分片架构上的取舍就基本定死了后面的兼容、运维、性能都是在为这个选择买单。TDSQL整体给我的印象是工程成熟度不错兼容性在同类产品里算很能打的但它再好用也解决不了分片键设计不合理带来的架构问题。评估工具的过程本质上是在评估自己团队的架构设计能力。
返回列表