十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

从ECS自建MySQL迁移到瑶池RDS:小应用上云全流程实战

从ECS自建MySQL迁移到瑶池RDS:小应用上云全流程实战 接到一个内部小应用的迁移需求一套运行在 ECS 上的自建 MySQL要迁到瑶池数据库 RDS。数据量不大业务也不复杂属于典型的小应用场景但真上手做的时候发现流程虽然标准细节却一点都不少。我把自己这次从评估、迁移、校验到成本对比的完整过程写下来希望能给正准备做同类迁移的同行提供一份“照着做就行”的参考。先说背景。这是一套内部业务系统前后端部署在一台 4 核 8G 的 ECS 上MySQL 是 5.7跑在同一个实例里用 Docker 方式部署数据量约 180GB线上峰值 QPS 在 300 左右没有从库备份靠 crontab 每天凌晨执行 mysqldump备份文件通过 ossutil 传到 OSS。这套架构初期没什么问题但运行一年多后三个问题越来越明显磁盘空间告警频率变高mysqldump 全量备份耗时从 20 分钟涨到 40 多分钟偶尔大查询会把磁盘 IO 打满导致应用接口超时。简单说自建方案把“数据库稳定运行”这个压力全压在了一个人身上——升级要自己来参数调优要自己来出了问题还得半夜爬起来处理。所以在评估完业务现状后我决定把数据库迁到瑶池数据库 RDS MySQL把运维压力交出去顺便重新梳理一下成本账。1. 先说结论我为什么决定从 ECS 自建 MySQL 迁到瑶池 RDS1.1 从 ECS 自建 MySQL 的痛点到底痛在哪很多人觉得小应用用自建 MySQL 挺合适毕竟数据量不大、并发不高一台 ECS 就能带起来。这个说法在业务初期没问题可一旦系统变成长期运行的生产业务自建的隐性成本就显现了。第一个痛点是备份。mysqldump 做逻辑备份数据量上了百 GB 之后从执行到完成往往要半小时以上而且备份期间会对实例产生额外 IO 压力。我遇到过两次因为备份时间和业务高峰期重叠导致慢查询明显增多的情况后来只能把备份时间调到凌晨 3 点。哪怕是这样也没法完全放心如果某天磁盘满了mysqldump 写不进去那当天的备份就是失败的而失败监控并不会主动报警。第二个痛点是高可用。自建环境下要保证高可用得自己搭主从复制、自己处理故障切换。小团队通常没有精力维护一套完整的 HA 方案于是“可用性”就退化成“挂了之后快速恢复”。但数据库这种基础设施恢复时间直接决定业务不可用时长一旦数据文件损坏恢复过程只会比想象中更复杂。第三个痛点是版本升级和参数优化。MySQL 5.7 已经停更维护继续跑在公网上本身就有安全风险。但升级到 8.0 并不是改个镜像版本那么简单涉及字符集、认证插件、SQL 兼容性还要做全量回归测试。这些事单独抽出来看都是小事加在一起就是不小的工程。1.2 瑶池数据库 RDS 解决了什么问题瑶池数据库 RDS 是云上的托管数据库服务简单理解就是你不用再管服务器和数据库软件本身只需要关注“库表结构、SQL 质量、数据内容”这些业务侧的事。对这个小应用来说我拿到的最直接收益有三个自动备份策略可以配置每日自动备份加日志备份支持任意时间点恢复不用再自己写 crontab 脚本。高可用能力高可用版实例默认会做主备切换主库发生故障时自动恢复应用侧只会在切换瞬间感知到连接抖动。参数模板和监控告警RDS 提供了完整的监控项连接数、CPU、内存、磁盘、慢查询、死锁都能看到还能直接配置告警规则。当然托管不等于万能。RDS 实例在参数上会有一些限制比如部分高级参数不能随便改某些超级权限被收回SQL 如果有特殊需求需要提前测试。这个在后面实操章节会详细说。1.3 迁移之前必须想清楚的几个决策迁移数据库不能上来就迁有几个决策必须在动手前敲定第一目标实例的版本。如果原库是 MySQL 5.7我建议直接选用 RDS MySQL 8.0。一方面 5.7 已进入生命末期另一方面 8.0 的默认字符集是 utf8mb4对中文和 emoji 支持更友好。但要注意如果应用里用了老版本特有的 SQL 写法或者依赖 mysql_native_password 认证插件的老客户端就要先做兼容性检查。第二目标实例的规格。不要直接照搬 ECS 的 CPU 内存配置。RDS 的规格选择要看实际负载而不是物理机器配置。我这个小应用ECS 是 4 核 8G但 MySQL 在实际运行中 CPU 使用率连 20% 都不到所以 RDS 我选了 2 核 4G预留一部分突发能力。第三网络规划。RDS 在工作时是通过专有网络连接的应用所在的 ECS 必须和 RDS 在同一个 VPC 下或者通过云企业网打通。这一步如果前期没规划好后面连不上数据库最容易让人抓狂。第四停机窗口。小应用迁移最大优势就是可接受的停机时间可以压缩。我这次和业务方约的是周日凌晨 1 点到 3 点预留 2 小时窗口实际观察下来在线迁移方式几乎可以做到不停机。2. 迁移前准备盘点业务依赖和数据库家底2.1 盘点应用侧对数据库的使用方式在正式迁移前我花了一天时间梳理应用和数据库的交互方式具体做了三件事从应用代码里搜索所有直接执行 SQL 的地方确认用了哪些数据库账号、连接的是哪个库、有没有跨库查询。把 MySQL 通用日志短暂开启半天抓取实际运行的 SQL 样本确认有没有定时任务在跑存储过程、触发器或事件。确认应用连接串的配置位置是写在配置文件里还是通过环境变量注入方便迁移后快速切换。这次排查发现了一个容易踩坑的点应用里有一个定时任务每天凌晨会通过一个只读账号执行报表查询而这个账号是应用代码里硬编码创建的并没有纳入统一账号管理。RDS 默认不允许通过 SQL 语句直接创建高权限账号必须先通过控制台创建账号再授权。所以我在迁移前就规划好了目标实例的账号体系模拟了原实例的账号权限模型。2.2 数据量、字符集和排序规则的评估数据量直接影响迁移方案的选择。这次实例总数据量 180GB其中一个大表占了 110GB单表行数超过 2 亿。这种体量如果用 mysqldump 全量导出再导入整个流程会在导出导出两端都消耗大量时间而且很容易在导入阶段碰到索引构建慢的问题。所以我直接把 DTS 在线迁移作为首选方案逻辑备份方案只作为补充预案。字符集方面源库是 utf8mb4目标库也保持 utf8mb4避免中文和特殊字符出现乱码。这里有个细节MySQL 8.0 的默认排序规则是 utf8mb4_0900_ai_ci而 5.7 里常见的排序规则是 utf8mb4_general_ci。如果应用里的 ORDER BY 语句依赖特定排序规则迁移后可能出现排序结果不一致。我在迁移前就把目标实例的库表字符集和排序规则都显式指定成和源库一致。2.3 账号权限与安全组规划RDS 的账号体系分成“高权限账号”和“普通账号”两类。高权限账号可以管理所有库普通账号只能管理被授权的库。这个和自建 MySQL 里用 root 一把梭的习惯很不一样。我在目标实例上创建了一个与应用同名的业务账号只授予了业务库的增删改查权限并单独创建了一个只读账号给报表任务用。网络访问控制上RDS 默认启用了 IP 白名单。迁移前我把应用 ECS 的私网 IP 加进白名单并严格限制只允许内网访问。这里特别提醒不要把 0.0.0.0/0 直接加进白名单尤其是在生产环境这是云数据库安全的基础底线。3. 数据迁移实操三种方案选型与完整执行步骤3.1 方案一mysqldump 逻辑备份 mysql 导入这是最传统的方案适合数据量小比如 10GB 以内、停机时间充裕的场景。步骤并不复杂但每一步都有细节。先导数据注意参数mysqldump -h 源库地址 -u 迁移账号 -p \ --single-transaction \ --set-gtid-purgedOFF \ --routines --events --triggers \ --databases myapp myapp_backup.sql几个参数说明一下--single-transaction在 InnoDB 表上通过开启一个可重复读事务来保证备份一致性不锁表--routines导出存储过程和函数--events导出定时事件--triggers导出触发器。我见过不少人在这一步漏掉 routines结果迁移完发现存储过程全没了。导入目标库mysql -h rds地址 -u 业务账号 -p myapp myapp_backup.sql导入前先确认目标库字符集和排序规则导入过程中用tee记录输出方便排查报错。这套方案我用在一次测试库迁移上验证过1GB 的库大概 3 分钟能完成。但对 180GB 的生产库我不建议用这个方案原因很简单导出 40 分钟导入至少 1 小时加上中途可能出现的索引重建整体耗时太长而且源库是单实例导出过程对线上有一定性能影响。3.2 方案二DTS 数据传输服务做全量加增量迁移推荐这是我这边的正式方案。DTS 的核心逻辑是先做一次全量数据迁移然后持续同步源库产生的增量数据等两边追平后在业务低峰期做一次短暂的写操作切换实现近乎不停机的迁移。具体步骤分四步第一步在控制台创建迁移任务。源库类型选 MySQL接入方式选“有公网 IP 的自建数据库”或“ECS 自建数据库”源库实例地区对应到 ECS 所在地域。目标库选“瑶池数据库 RDS MySQL”。任务类型勾选“结构迁移 全量数据迁移 增量数据迁移”。第二步配置源库和目标库的连接信息。需要源库的 IP、端口、数据库账号我建议单独创建一个迁移专用账号只授予 SELECT、LOCK TABLES、SHOW VIEW、REPLICATION CLIENT、REPLICATION SLAVE 这些权限避免在源库上暴露过多权限。同时源库需要开启 binlog且 binlog_format 必须设置为 ROW否则增量同步会失败。第三步启动任务并观察状态。DTS 会先跑结构迁移再跑全量数据迁移最后自动进入增量同步阶段。全量阶段我重点看两个指标迁移速度和延迟。一旦进入增量同步源库和目标库的数据就会保持准实时一致。第四步业务切换。在确认增量同步延迟持续低于 5 秒后我申请了一个维护窗口。窗口开始时先停掉应用对源库的写操作我是通过暂时把应用实例缩容并停掉定时任务实现的然后确认延迟归零最后修改应用连接串指向 RDS重启应用服务。这里要提醒一个关键点连接串切换后一定要检查“存量连接”是否都断干净了。因为 DNS 或者连接池缓存可能有一些应用节点还保持着源库的旧连接导致写操作又回到源库。我这次是在切换后直接用命令查了源库的 processlist确认没有来自应用的连接才放心。3.3 方案三基于物理备份或克隆实例的快速迁移如果你有超大数据库TB 级别mysqldump 和 DTS 的全量初始化阶段都会比较慢。这时可以考虑物理备份迁移先用 xtrabackup 在源库做物理全量备份把备份文件传到目标环境后恢复。云上还可能用到 DTS 支持的“迁移可用区”或“从备份创建实例”等功能但这个方案对大多数小应用都过于重了。我这次没有采用物理备份因为 180GB 在 DTS 全量阶段表现已经不错而且物理备份需要对 xtrabackup 的兼容性做验证额外的工作量并不划算。但如果你手里有几百 GB 甚至 TB 级的库建议提前评估物理方案别等到全量迁移跑到一半才后悔。3.4 迁移后的校验清单迁移完成不代表结束数据一致性校验必须做。我习惯检查以下项目表数量通过 information_schema.tables 对比源库和目标库每个库的表数量是否一致。行数抽样对比大表的 COUNT(*) 结果尤其是超过千万行的表。自增主键确认 AUTO_INCREMENT 的下一值与原库一致避免插入数据时出现主键冲突。存储过程、触发器、事件核查这些对象是否完整迁移。字符集抽查中文数据、emoji 特殊字符确认显示正常。权限账号确认目标库的账号授权和原库一致特别检查应用账号对关键表的权限。我用一段 SQL 快速统计了表行数偏差SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema myapp ORDER BY table_name;然后和源库的输出做 diff发现有一张表行数不一致。排查原因是有频繁写入COUNT() 的采样信息存在延迟。于是我用真实 COUNT 再对比一次。这里也给同行提个醒information_schema 里的 table_rows 是估算值不适合做精确校验只能做粗筛最终以 COUNT() 为准。4. 成本对比小应用视角下的真实账本4.1 自建 MySQL 的成本构成别只看 ECS 价格很多人对比自建和云数据库只盯着 ECS 实例的价格然后得出“自建更便宜”的结论。这是最大的误区。自建 MySQL 的成本至少包含五块ECS 实例费用按 CPU 内存规格计费包年包月或按量付费。云盘存储费用数据盘、系统盘都需要单独付费我这边用的是 ESSD容量 300GB。备份存储费用mysqldump 出来的备份文件还要传 OSSOSS 的存储费用和流量费用都得算进去。运维人力成本升级内核、修复漏洞、处理故障、优化慢 SQL这些时间换算成成本月均至少 0.5 个工作日。高可用成本如果要搭主从至少要再买一台 ECS 和一倍的云盘。那天我把自建方案的费用逐项拉出来发现 ECS 加云盘加 OSS 的死人成本并没有想象中低再加上升级到 MySQL 8.0 需要的额外测试工作量自建方案的综合支出已经逼近托管方案了。4.2 瑶池 RDS 的成本构成其实更透明瑶池 RDS 的计费模型相对简单主要三个维度实例规格按 CPU、内存规格计费可以选择包年包月或按量付费。存储空间包含数据容量和日志容量超出赠送备份空间的部分另计。备份空间实例赠送一定额度的备份空间超过后按实际占用收费。以我这个 2 核 4G、存储 100GB 的实例为例包年包月的费用大约是自建方案中一台同规格 ECS 的 1.2 到 1.5 倍但省掉了云盘费用、备份脚本维护、高可用搭建的额外成本。最关键的是RDS 的高可用版自动提供主备切换而自建方案中主从同步的搭建、监控和切换演练至少需要连续几天的开发和验证。4.3 三年 TCO 视角下的成本对比我列了一张对比表把三年内可能涉及的主要花费做了个粗略估算仅供参考具体价格以控制台实时报价为准成本项ECS 自建 MySQL瑶池 RDS MySQL云资源实例存储备份ECS 4核8G 云盘300GB OSS备份年费用约 6000-9000 元2核4G 100GB存储 备份空间年费用约 5000-7000 元高可用部署额外一台ECS主从配置年增加约 3000-5000 元高可用版自带主备差价已在规格中体现运维工时每月至少半天处理备份、优化、故障几乎可以忽略监控告警自动处理升级成本版本升级需要大量测试风险高控制台选择版本升级过程平台承担从三年 TCO 来看自建方案的数据存储其实更灵活因为你可以自由控制磁盘容量但加上高可用和运维托管方案的总体拥有成本反而低。对小应用而言RDS 的开销并没有传说中的那么“贵”关键在于规格别一步到位买太高先按实际监控数据选型后续不够再加。4.4 成本中容易忽略的隐藏项说几个容易踩的隐藏费用坑IOPS 费用部分 RDS 存储类型会在超出基础 IOPS 后按量计费。如果业务有大量全表扫描或频繁刷脏页IOPS 可能成为隐性开销。只读实例费用如果需要扩展读能力额外的只读实例是单独计费的。公网流量费用在使用公网连接 RDS 时会产生流量费用。生产环境建议保持内网访问既安全又省钱。数据迁移工具费用DTS 在特定功能或数据量下可能产生额外费用迁移前先看帮助文档确认计费模式。5. 迁移过程中的典型问题与排查实录5.1 字符集导致的中文乱码迁移完成后第一次用应用写数据发现新写入的中文在页面上显示正常但个别旧数据里出现了“?”。排查后发现问题不在迁移而是应用连接串里没有指定 characterEncoding导致写入按平台默认编码处理。这个在自建环境里因为服务器 locale 一致没暴露换到 RDS 后连接参数就变得敏感了。解决办法是应用侧 JDBC 连接串显式加上characterEncodingutf8mb4并在 RDS 控制台把实例和库表的字符集统一设置为 utf8mb4。这里注意连接串的字符集和数据库字符集最好都设置双保险。5.2 自增主键冲突迁移过程中由于 DTS 在全量迁移阶段没有同步自增序列的当前值导致目标库的 AUTO_INCREMENT 值比源库小切换后应用插入数据时碰到“Duplicate entry for PRIMARY KEY”报错。当时第一时间去目标库执行了ALTER TABLE my_big_table AUTO_INCREMENT 2200000001;把自增值调整为略大于源库当前最大 ID 的值。这个操作在 MySQL 8.0 上执行很快但如果是大表InnoDB 会在内存中重建自增计数器建议在低峰期操作。5.3 连接池参数导致连接数打满RDS 对最大连接数有默认限制比如 2 核 4G 的实例默认最大连接数是 800。如果应用连接池的 maxActive 配置得太大比如 200并且在多个节点上部署连接数就很容易打满。我这次遇到的是应用连接池初始化和预热导致短时间连接数突增。排查思路是先看监控里的“当前连接数”再通过 processlist 查看连接来源确认是哪个应用节点在创建连接然后适当调小连接池上限。小应用的并发通常不高连接池设成 50 到 100 完全够用没必要追求大水体配置。5.4 慢 SQL 在云数据库上更明显迁移后我发现一些查询的耗时略有增加。这主要是实例规格比原来的 ECS 低一档导致的并非 RDS 性能差。排查方式是在 RDS 控制台开启慢查询日志发现有一条带全表扫描的排序查询在源库时因为数据量小不明显迁到新实例后索引失效。解决方法是给查询涉及的字段补一个组合索引ALTER TABLE order_list ADD INDEX idx_user_time (user_id, create_time);这条 SQL 执行前我先在测试环境验证了执行计划确认走索引后才在生产执行。RDS 的慢查询日志和 SQL 洞察功能在这种场景下特别有用能直观看到每类 SQL 的耗时分布这也是自建环境很难具备的体验。5.5 只读账号和权限边界的问题最后说一个和权限相关的坑。原来自建环境里应用用一个账号DBA 用另一个账号但 DBA 账号权限几乎是全部授权。到了 RDS 后控制台创建的账号默认不允许 GRANT OPTION也就是说普通账号不能把权限转授给其他账号。如果有业务需求需要动态创建账号得通过高权限账号操作或者提前在控制台规划好。此外RDS 部分系统库如 mysql 库的访问权限默认不开放如果应用里存在恶意的“跨库查询”比如直接查询 mysql.user 表迁移后会直接报权限不足。这样的代码必须提前改掉。写在最后这次迁移我学到的东西整个迁移从评估到切换前后花了一个多星期真正在维护窗口里操作的时间不到半小时。最大的感受是小应用做数据库上云难点从来不在“导出导入”这个动作而在前期的依赖梳理、字符集与权限规划以及切换后的校验。自建 MySQL 并不是不行但前提是你有足够的精力持续维护它对一个只有两三个后端同学的小团队来说把数据库运维交给瑶池数据库 RDS 这样的托管服务确实能省下不少时间去做业务。再补一个小技巧迁移切换前一晚我把源库的数据目录和备份文件都做了一次快照或异地备份以防万一目标库出问题还能快速回滚。结果迁移非常顺利这份备份虽然没派上用场但心里踏实了很多。对于数据库迁移这类“只能成功”的操作多点保险措施永远值得。
返回列表