随着业务高速增长、数据量逐步增多,单实例、单库、单表出现性能瓶颈和存储瓶颈。从选型和架构设计角度来看这很符合发展规律,一开始没必要引入过于复杂的架构导致资源成本和开发成本过高,而是逐步随着业务发展速度去迭代架构。为了应对这些问题,我们采取了诸多措施如单库按业务逻辑拆分成多个库的垂直拆分,分库分表的水平拆分、一主多从读写分离等。这些技改同时也使得整个业务层架构更加复杂,且无法做到透明的弹性,因此我们逐步把目光转向了已经趋于成熟的分布式关系型数据库 TiDB。
自 2020 年初开始使用 TiDB,随着运维体系的逐步完善,产品自身能力的逐步提升,接入业务已经涉及得物的多个 业务线,其中个别为关键业务场景。业界关于 TiDB 的功能剖析、场景落地、平台化建设都有很多优秀的文章。本文基于得物内部的实践情况,会从选型策略、运维手段、运营方式、核心场景实践等几个方向讲述TiDB 在得物实践落地过程。
2. TiDB 架构
上图是我们目前的接入方式和整体架构。TiDB 的部署架构这里就不做赘述了,需要了解的同学可以参考官方文档。我们之所以采用 SLB 来做 TiDB 的负载均衡接入,就是为了简化接入成本与运维成本,访问流量的负载均衡以及节点扩缩容可以通过调整 SLB 解决。当然如果能够实现 SDK 负载均衡与故障剔除,结合配置中心的流量调度也是非常好的解决方案。得物 TiDB 部署均采用单机单实例部署,TiDB Server、PD 采用无本地 SSD 机型,TiKV 采用本地 SSD 机型。既兼顾了性能,又能降低成本。详细的机型选择会在后面的内容提到。
3. MySQL 与 TiDB 的对比
圈内一直流传着一句话,没有一种数据库是"银弹"。绝大部分用户选择 TiDB 就是为了弥补 MySQL 的不足,所以选型阶段对两者做些比较也是在所难免的。本文基于我们内部的现状和场景对两个产品我们关注的点进行了简要对比。对比的目的不是为了去印证那个数据库产品能力更强。而是想通过对比来帮助团队在合适的场景选择合适的产品。
- 扩展性
- MySQL
MySQL 就自身扩展能力而言主要是来自于垂直扩容,但是这个会受限于机器的规格上限。水平扩容涉及业务改造和使用成本提升。改造为分库分表,对研发来说是一个费力度很高的方案。需要引入 Sharding 逻辑,改造完成后需要业务 SQL 必须带 Sharding Key 才能执行或者高效执行。所以并不是说做不到可扩展。
- TiDB
由于 TiDB 是计算存储分离的架构,且有状态的存储层 TiKV 是分布式存储。所以单从上面定义的扩展性来说,确实对比 MySQL 有很大优势。集群处理能力和存储能力,可以通过扩容 TiDB Server、TiKV 简单实现。这里需要注意的是,TiKV 属于有状态服务,扩容会涉及到数据的 Reblance,过程中 TiKV(region 迁移) 和 PD(调度) 产生大量交互,为避免影响业务,扩缩容过程中需要关注集群情况,根据需求适当调整迁移力度。
- 性能
- MySQL
关于 RT。MySQL 由于是单机数据库,所以对于点查或简单查询的 RT、热点更新的 RT 与 TPS ,相比分布式数据库有天然优势。数据获取链路短(单机数据库本地调用,分布式数据库涉及存算分离),且不用考虑分布式事务的冲突检测。所以总体的访问 RT 要低于 TiDB,具体数据这边就不罗列了,社区有不少性能压测的帖子。
关于聚合查询。互联网公司在 C 端基本不存在此类问题,也是不允许的。所以主要是场景在 B 端。解决方法一般是分为几种:1.提供专门的只读实例给 B 端提供查询能力;2.异构数据来解决(MySQL+ES、ADB 等等)。
关于优化器。MySQL 多年的积累,在优化器的稳定性虽然不如商用数据库那么可靠,偶尔也有走错索引的情况。一般只能通过修改 SQL、修改索引来解决,切记别用 force index 这种有坑的解决方案。但是总体来说我们遇到的 MySQL 走错索引的情况要远低于 TiDB。
- TiDB
关于 RT。分布式数据库解决的更多是吞吐量和容量上的需求,比如点查或简单查询的 RT 无法像单机数据库那么短,但是可以通过节点扩容的方式提升 QPS 吞吐量。热点数据这里就不展开讲了,它本身也不是分布式数据库能解决的范畴。如果你的业务场景是一个对 RT 要求很高的场景,那么优先使用 MySQL。如果是高吞吐量需求优先,可以尝试使用 TiDB。
关于聚合查询。由于 TiDB 的存储节点 TiKV 不只是具备存储能力,TiKV 实现了coprocessor 框架来支持分布式计算的能力。所以理论上通过加机器就能扩展计算能力,从我们实际使用的场景来看也是如此,这部分的能力就要优于 MySQL。具体的效果在本文最后的章节会有体现。
关于优化器。这个是大家对 TiDB 一直以来吐槽的点之一,有时候统计信息健康度 90 以上的情况下,还是会走错索引,当然这里有一部分原因可能是条件过多和索引过多导致的。为了解决问题,核心服务上线的 SQL 就必须一一 Review。如果无法正确使用索引的就使用 SPM 绑定,虽然能解决,但是使用成本还是略高。希望官方继续加油。
- 资源成本
- MySQL
如果是一个数据量小且查询模型比较简单的需求(比如:1-2TB,简单查询为主),那么肯定是 MySQL 成本较低。以我们 TiDB 基础配置为例,相比 MySQL 成本高出 27%(该成本是用高可用的 MySQL 对标3 TiDB、3 TiKV、3 PD 的 TiDB)。所以得物内部选型,单从资源成本角度考虑,还是首选 MySQL。
TiDB如果是一个数据量较大且持续增长或查询模型比较复杂的需求(比如:3-5 TB 以上,多条件查询、聚合查询等)。一般该类型的业务都采用分库分表的解决方案。以得物一个分库分表的集群(10个写实例、10个读实例)为例,替换为 TiDB(6 TiDB、12 TiKV、3 PD),成本相比 MySQL 成本节省 58%。此例子只作为得物一个业务场景的替换结果,不代表所有场景。为了验证这个结论,本文后面的内容会讲到这个核心场景的实践。
- 运维成本
- MySQL
MySQL 作为被使用最多的开源关系型数据库,从社区活跃度、产品成熟度、周边生态工具、解决方案积累等方面来看都是非常优先的产品。主从架构的 MySQL 维护成本极低,当主库异常或无法修复时,我们只需要切换即可。
另外得益于优秀的社区生态,运维工具、数据库接入组件、数据同步组件都有非常多的成熟工具,稍加改造就可以实现本地化适配。
- TiDB
分布式的架构的设计没有像 MySQL 这样的主从,每个存储节点都是提供读写。当一个节点出问题的时候,会影响整个集群的访问。无法实现 MySQL 这样通过主从切换实现快速的故障隔离。
TiDB 由 3 个角色组成,当出现问题的时候无法快速定位问题(当然也是我们个人能力需要提升的点),比如当某个时间点的查询超过预期的时候,需要排查执行计划、各个节点的负载情况、各节点的网络情况。虽然提供了完善的监控,但是指标与节点过多需要一一排查才能有结论。不像 MySQL 出现查询超预期的问题,基本上通过几个核心指标就能判断出根因。