本文来自 InfoQ,作者云盛海宏 ToC 业务团队崔文涛、邓有才。
云盛海宏是一家零售业科技公司,以科技的力量为门店和线上客户打造 360 度的优秀体验,目前服务中国 6000 余家的线下门店和千万级别的线上会员。云盛海宏的 To C 系统分为私域商城和会员营销两条业务线,它为 7000 多万注册会员提供了丰富的权益和服务,是我们非常核心的系统。
2. 个别单库架构的 MySQL,数据增长远超预期,单表数据量过大,性能问题凸显
● 数据量千万级以上表:87 张;亿级以上表:21 张
● 需要将单库架构改造成分库分表架构才能解决
1. TiDB 兼容 MySQL 协议,并且是原生分布式,无需规划分片规则,对应用友好,能够很好的解决之前分库分表数据倾斜的问题
2. TiDB 架构下提供的动态水平扩展、热点自动调度等能力,大幅简化了一系列运维成本,能够支撑应用规模持续的增长,即使数据增长超过预期也能动态增加节点解决
3. 另外我们的零售系统在去年成功切换到 TiDB,也给了我们团队很大的信心
1. 迁移数据的完整性:数据是企业的核心资产,不容许丢失
2. SQL 兼容性及性能:这意味着我们迁移改造的成本
3. 资源隔离能力:多个业务库合并后如何保障其服务质量
● SQL 录制:MySQL 数据库在开启慢查询功能时,会将慢 SQL 输出到慢查询日志
● SQL 回放:playback 工具解析慢查询文件中的 SQL,并连接到目标数据库进行回放
● 报告展示:回放完成会输出报告(执行失败的 SQL 含结果不一致等、性能数据)
● SQL 录制:将生产 MySQL 库的 long_query_time 设置为 0,运行一个业务周期(一天),记录一天内所有 SQL(样本数越大测试结果越准确)
● SQL 处理 :部分慢查询日志未记录 schema 信息,通过脚本指定 schema(还存在将 db_1 映射成 db 这样的 schema 转换)
○ 1 处业务 SQL 错误:“during query: Data too long for column”,原因字段精度不够,调大后解决,其余业务 SQL 均兼容
○ 剩余 1220855 次均为非业务 SQL 的报错:如 MySQL 中"show binary logs/status/events"、set 特有变量、系统表查询,或慢查询格式调整时出现的一些格式错误等
○ 无业务 SQL 错误,业务 SQL 均兼容
○ 所有错误均为非业务 SQL:如 MySQL 中"show binary logs/status/events"、set 特有变量、系统表查询,或慢查询格式调整时出现的一些格式错误等
1. 由于 TiDB 是存储计算分离的分布式架构,1000us 内的 SQL 数很少,基础操作(如 show variables/start transaction/set ... 等)执行时间均高于 MySQL;同时另一个极端,大于 10 秒以上的 SQL 数,两个系统在 TiDB 中下降了一个数量级。
2. 通过一些采样分析,我们发现在 TiDB 中一些 commit/rollback 操作的时间也普遍高于 MySQL,个别操作从几百微秒变成几十 / 几百毫秒。查阅了 TiDB 中的事务机制,发现 TiDB 提交成本高于 MySQL,首先是 2PC 跨节点事务,另外就是事务中的脏数据直到 commit 时才开始刷到存储(计算节点 ->存储节点),对于这种类型的 SQL 在性能分析时也可以忽略掉。
3. 我们将样本数据整理成桑基图,将这部分性能退化、并且影响用户体验的 SQL 识别出来,进行分析和优化
以上为会员运营中 SQL 性能数据桑基图,如红色箭头以及红色框的这些 SQL,需要重点分析
以上为会员运营中原本 10 秒以上 SQL 性能变化
4. 私域商城的 SQL 性能提升很明显,100ms 内 SQL 数量均高于 MySQL,同时 1s 以上的 SQL 少于 MySQL,说明用户体验提升明显。但还是需要根据桑基图来分析是否存在异常的 SQL
以上为私域商城系统 SQL 性能桑基图,红框对应的 SQL 应该重点分析
以上为私域商城原本 10 秒以上 SQL 性能变化
○ 当某个系统中出现一个大查询时,如何限制其资源消耗,避免对该应用、对整个集群造成影响
○ 当某个系统中批量调度作业到白天还没跑完时,如何限制其资源消耗,避免对白天业务造成影响
○ 应用监控等定时调度操作往往比较复杂,如何限制其运行时的资源消耗
○ 客户端数据查询场景难以避免 SQL 条件不规范的情况,当出现这种情况时,如何避免人工查询导致的系统不可用
- 按用户设置资源规格
- 按会话设置资源规格
- 按 SQL 设置资源规格
SQLSELECT ... FROM shop_****_pic scp WHERE is_valid=1 AND sort = (SELECT MIN(sort) FROM shop_****_pic WHERE shop_****_id = scp.`shop_****_id`) AND shop_****_id IN ( ... );
SQLSELECT ... FROM shop_****_pic scp WHERE is_valid = 1 AND sort = ( SELECT MIN(sort) FROM shop_****_pic WHERE shop_****_id = scp.`shop_****_id` GROUP BY shop_****_id) AND shop_****_id IN (...);
💡 点击文末【阅读原文】,立即下载试用 TiDB!
网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。
加入交流群
请使用微信扫一扫!