车好多集团系国内领军的汽车消费服务一站式平台,旗下拥有瓜子二手车、毛豆新车、车好多车后三大核心业务。
车好多集团关注 TiDB 始于 2018 年初,像大多数公司同样,公司发展初期为了快速适配业务开发,大部分数据都存储在 MySQL 中。但随着业务快速发展,存量数据愈来愈多,咱们在 MySQL 面临着以下痛点:git
公司业务发展快,单实例的 QPS 和数据存储会超出预期,这时候须要对业务线实例进行拆分。 每次业务线拆分须要从数据产生端 (APP) 到数据流转端 (CDC) 最后到数据仓库(DW)一块儿配合调整; 若是涉及到多方同时使用相同库表,还须要多个应用的负责人协调; 同时一些脚本类程序可能在迁移时被忽略,部分业务数据会受到影响。 每次业务线拆分的周期大概在 2-4 周,耗费人力。github
业务发展到必定程度以后,一些数据表的数据量超过千万级别,常规作法是分库分表。这里有几个可能遇到的问题:sql
咱们公司的业务模式变化快,为了快速响应业务,表结构常常调整。在对一些数据在百万级别以上的大表作 DDL 的时候,会借助第三方工具,如 pt-osc。修改过程当中须要先复制一份临时表,这种方式修改的时间较长,对存储空间、IO、业务有必定的影响。数据库
面对以上痛点,咱们开始考虑对数据库的架构进行升级改造,咱们根据业务方的诉求,将一些常见数据库技术方案,作了一些对比:后端
数据库类型 | 优势 | 缺点 |
---|---|---|
MySQL 分库分表 | 1. 根据 ID 查询的层面基本上无多余工做量。2. 短时间技术实现成本低。 | 1. 库表数量线性增加,运维压力大,按百万级别数据量分表计算,每一年增加表的数量至少 30 张,且单表容量仍然较大。2. 分库分表在代码层实现需改动代码。3. 如引入分库分表中间件,则须要投入专门人员。 |
MongoDB | 1. 技术比较成熟。2. 大数据量下,可经过分片进行扩展。 | 1. 业务须要所有重构,短时间内没法实现。2. 文档型数据库,须要业务来控制数据较验。 |
ElasticSearch | 搜索功能强大(多二级索引)。 | 1. ElasticSearch 写入性能稍差,遇到大量写入操做时候,可能延迟。2. 无 schema 管理,长期维护成本较高。 |
HBase | 1. 技术比较成熟。2. 普通根据 rowkey 查询,无工做量。3. 可横向扩展。 | 1. 没法经过 rowkey 直接获取数据的场景,都须要额外开发,接口通用性较低。2. 不支持二级索引。3. 协议与现有程序不一致,须要从新开发相关读写程序。 |
HBase+phoenix | 1. 底层 kv 存储复用 HBase,存储引擎的稳定性强。2. 可横向扩展。 | 1. SQL 语法小众。好比只有 upsert,没有单独的 insert 和 update。2. Phoenix 的事务功能依赖开源的 percolator 实现,可信度略低。事务仍是一个比较严谨的技术,Phoenix 社区和 Google 也没能查到太多事务相关的信息。 |
HBase+ES | 1. HBase 做为 OLTP 的记录存储,ES 做为 HBase 的二级索引。2. 兼顾了 HBase 的优势(快速的 kv 能力,海量存储能力,可变字段能力)和 ES 的优势(强大的二级索引能力)。 | 1. 不支持事务。2. HBase 和 ES 两端的数据一致保障难度高。 |
TiDB | 1. 彻底兼容 MySQL 协议,业务层几乎不须要改动。2. 分布式存储,节点无限扩容,高可用。3. 完美替代 MySQL 分库分表。4. 大表 DDL不影响业务。5. 支持事务,隔离级别为'快照级别隔离' [见附录]。6. 可兼容 CDC 链路。 | 1. 资源需求较高。2. 无触发器、存储过程、某些语法不兼容。 |
TiDB 具备水平弹性扩展,高度兼容 MySQL,在线 DDL,一致性的分布式事务等特性,符合车好多部分数据量大,业务变动频繁,数据保存周期长等场景。 咱们通过 TiDB 的内部测试后,确承认以知足现有业务需求。咱们最终选择了 TiDB 作为这类需求的数据存储。架构
综合 TiDB 的特性和车好多集团的业务场景,咱们比较适合引入 TiDB 的场景有: 工单分配 / 流转、电话销售系统、业务中台-帐务系统等业务。首先这些业务积累的数据量比较大,在此基础上一部分业务会有频繁增长字段的需求,也有一部分业务会使用到事务,这些场景都很是适用于 TiDB。运维
与目标业务方进行了一轮沟通以后,业务方给咱们介绍了一些数据的现状和业务上的需求:分布式
因为 TiDB 的资源要求较高,咱们对接入的业务提出了如下要求:工具
面对一个新的数据库,大部分核心业务仍是担忧数据库的稳定性和数据的可靠性,不敢直接尝试。咱们优先选择一些数据量比较大而且实时性需求相对较低的场景进行试点,可是业务方仍然担忧服务的稳定性和性能等诸多问题。咱们屡次与业务方沟通,制定和实施了分段落地的计划:性能
第一步,将 TiDB 做为 MySQL 的从库使用,经过 DM 工具同步数据。业务方使用这套 TiDB 集群做为从库,验证数据的准确性 / 服务的稳定性 / 查询的性能等是否符合业务需求,测试正常后灰度小比例的线上流量到该集群上进行查询,确认数据正常后逐步放大灰度的比例直至全流量。这一步充分的验证了 TiDB 的数据同步和数据查询,业务方对 TiDB 有了初步的认知,也逐渐积累了对 TiDB 和维护人员的信任。
第二步,业务方改造程序,对 MySQL 和 TiDB 进行双写,断开 DM 同步。业务方将 TiDB 做为主库直接读写,但仍然保留了 MySQL 中的数据写入,将 MySQL 做为 TiDB 发生异常以后的降级方案。这个阶段持续了 2 个季度左右。在这期间读写 TiDB 的程序运行正常,天天的数据校验保持一致。
第三步,下线双写,仅保留直接操做 TiDB 的部分。经过第一步和第二步的验证和积累的信任,TiDB 正式做为独立的数据库投入到生产环境使用.
新车业务接入 TiDB 以后,业务上将原先只支持近期三个月的查询扩展到支持全量查询,这部分数据对用户行为精细化管理带来了必定的帮助。随着业务发展,存量数据从千万级别逐步上升到亿级别,到如今将近十亿,在 1000 QPS 下查询的 99.9th 延迟低于 128 毫秒,用户体验良好。通过了整个接入过程后,新车计划将存在数据库瓶颈的业务逐步迁移到 TiDB 中来。通过一年的发展,目前车好多的二手车收售车管理、台帐、支付网关、用户社群等业务逐步尝试 TiDB,而且在试用以后慢慢从 MySQL 中迁移更多的业务模块到 TiDB 中。
在推动 TiDB 的过程当中,咱们也遇到了各类问题,除了一些常见的慢 SQL、热点读写、DM 同步数据异常等问题外,咱们在车好多的业务背景下,遇到了一些相对特殊的问题:
TiDB 是一项比较新的技术,社区的版本在不断的迭代更新,有不少 bugfix 和新特性在持续集成到 TiDB 中。咱们从开始调研到如今,经历了 2.X 到 4.0.X 的多个版本。咱们选择了一些比较关心的内容进行跟进,如: Lightning 导入数据 bug 修复、悲观锁、TiFlash、TiUP 管理工具、TiCDC 等等。有一次咱们从 2.1.x 的版本升级到 3.0.x 版本,未注意到 sql mode 变动,刚好业务上正好有 SQL 被 ONLY_FULL_GROUP_BY 规则影响,紧急修改 SQL 后从新上线。咱们增量的业务选择版本的时候,一般会选择一些已经平稳运行一段时间的版本,上线以后,若是没有严重的 bug 或者急需的特性,一般再也不进行升级,以保障业务不由于数据库的升级受到影响。
使用 TiDB 一段时间后,某个业务线单表存量数据数据已经超过 5 亿,QPS 也超过了 200。某天业务方反馈,线上系统发生大量查询超时,结果无返回,TiDB-admin 协助排查问题。观察监控数据,发现 CPU 被打满,IO 上升明显。继续观察慢 SQL 日志,发如今 analyze 收集统计信息的末尾阶段,有一类 SQL 索引的选择发生了改变,每次扫描的 key 从正常索引下的百级别到异常索引下的百万到千万的级别。为了快速恢复业务,结合 TiDB 承载的业务的特性,将影响优化器选择的未使用到的索引删除,同时将自动 analyze 操做设置为业务低谷时间段执行。
咱们以这个案例咨询了 PingCAP 官方,由于 TiDB 使用的是基于成本的优化器(CBO),在统计信息变动的时候,有可能选择与以前不一致的索引,建议经过 SQL binding 解决此类问题。不久时间后,另外一条业务线的 SQL 由于相似问题,使用了 SQL binding 进行了绑定,在程序使用到 prepare statement 的时候遇到了另外一个 bug [见附录] ,上报社区后已经加入到修复计划中。
随着 TiDB 技术在车好多集团的推动,和第一批吃了螃蟹的业务方的推荐,愈来愈多的业务线但愿尝试 TiDB。受机房设备采购周期的限制,咱们很难短时间内凑出多套独立的 TiDB 集群,服务忽然上升的需求量。结合这些新增需求的业务特性: 大部分是增量比较高可是没有存量数据的业务,前期对资源的需求并非很是高,因而咱们 TiDB-admin 开始调研在同一组机器中混和部署多套集群,而且进行进程之间的资源隔离。TiDB 分为多个组件,PD 对资源的需求不高,暂时忽略;TiKV 能够经过软件层配置最大的 CPU 和内存,IO 的隔离咱们选择在同一台机器部署多块 SSD 进行物理隔离,也比较好控制;TiDB 虽然能够经过软件层配置最大的 CPU 和内存,可是没法阻止瞬时的内存暴增,调研后发如今经过 TiUP 部署的时候,能够设置 systemd 的参数 memory_limit,经过系统的 cgroup 限制最大使用内存,这也催生了咱们经过 K8s+Docker 来全面控制资源的想法。咱们在混合部署以后,提供给了业务方进行验证,确承认以隔离某一方的异常 SQL 对通物理机下其余TiDB 集群的影响,新业务逐步用上了 TiDB。
附录:
https://docs.pingcap.com/zh/t...