一、背景数据库
小米关系型存储数据库首选 MySQL,单机 2.6T 磁盘。因为小米手机销量的快速上升和 MIUI 负一屏用户量的快速增长,致使负一屏快递业务数据的数据量增加很是快, 天天的读写量级均分别达到上亿级别,数据快速增加致使单机出现瓶颈,好比性能明显降低、可用存储空间不断下降、大表 DDL 没法执行等,不得不面临数据库扩展的问题。多线程
对于 MySQL 来说,最直接的方案就是采用分库分表的水平扩展方式,综合来看并非最优的方案,好比对于业务来说,对业务代码的侵入性较大;对于 DBA 来说提高管理成本,后续须要不断的拆分扩容,即便有中间件也有必定的局限性架构
二、迁移过程并发
整个迁移分为 2 大块:运维
数据迁移高并发
对于存量数据,可使用逻辑备份、导入的方式,除了传统的逻辑导入外,官方还提供一款物理导入的工具 TiDB Lightning。工具
对于增量备份可使用 TiDB 提供的 Syncer (新版已经改名为 DM - Data Migration)来保证数据同步。性能
流量迁移优化
流量切换到 TiDB 分为两部分:读、写流量迁移。每次切换保证灰度过程,观察周期为 1~2 周,作好回滚措施。线程
读流量切换到 TiDB,这个过程当中回滚比较简单,灰度无问题,则全量切换。
再将写入切换到 TiDB,须要考虑好数据回滚方案或者采用双写的方式(须要断掉 Syncer)。
对于初期上线的业务,咱们比较谨慎,基本的原则是:离线业务 -> 非核心业务 -> 核心业务
一、写入量大、读 QPS 高的离线业务
1.一、如今 TiDB 的 GC 对于每一个 kv-instance 是单线程的,当业务删除数据的量很是大时,会致使 GC 速度较慢,极可能 GC 的速度跟不上写入。目前能够经过增多 TiKV 个数来解决,长期须要靠 GC 改成多线程执行
1.二、Insert 响应时间愈来愈慢。业务上线初期,insert 的响应时间 80 线(Duration 80 By Instance)在 20ms 左右,随着运行时间增长,发现响应时间逐步增长到 200ms+。期间排查了多种可能缘由,定位在因为 Region 数量快速上涨,Raftstore 里面要作的事情变多了,而它又是单线程工做,每一个 Region 按期都要 heartbeat,带来了性能消耗
临时解决:增长 Heartbeat 的周期,从 1s 改成 2s,效果比较明显
完全解决:须要减小 Region 个数,Merge 掉空 Region,官方在 2.1 版本中已经实现了 Region Merge 功能,咱们在升级到 2.1 后,获得了完全解决
另外,等待 Raftstore 改成多线程,能进一步优化
二、在线 OLTP,对响应时间敏感的业务
执行计划偶尔不许
一、场景一:开关锁日志成功率统计
按照咱们的估计,这个业务一年的量在数百亿
最终经过对比分析,咱们选择了 TiDB 做为开关锁日志成功率统计项目的支撑数据库
二、场景二:实时在线 OLTP 业务
因为是典型 OLTP 场景,可选项并很少,并且数据量增加极快,这些数据库的数据在一年内轻松达到数百亿量级。这些场景在咱们有了 TiDB 的使用经验之后,发现 TiDB 的全部特性都很是契合这种海量高并发的 OLTP 场景。TiDB 的容量/并发可随意扩展的特性不在赘述,支持在线 DDL 这个特性特别适合这些业务,有须要业务更改不会阻塞业务,这是咱们业务快速迭代比较须要的特性。
目前,这两个在线 OLTP 集群拥有数十个节点,百亿级数据,上线之后很是稳定,PingCAP 客户支持团队也协助咱们进行该集群的平常运维工做。
三、订单集群(P0 级业务)
TiDB 合库做为 readonly 负责其余多维度的查询
TiDB 的出现,不只弥补了 MySQL 单机容量上限、传统 Sharding 方案查询维度单一等缺点,并且其计算存储分离的架构设计让集群水平扩展变得更容
一、活动场景
忽然接了一个元旦的活动,这个时候上传的图片就比较多,数据增加的就太大了,这种活动中 S3 系统压力比较大。咱们 MySQL 的单盘基本上稳定的在 2.0TB 以上(盘总计 2.8TB),对此咱们就只能删数据(一些很老的数据),跟业务部门沟通说,这个数据不要了,从 MySQL 的单盘里删掉,经过这种方式来支撑。
但即便这么作,单盘仍是扛不住如今数据增加的需求。而后当时就想干脆激进点,把一些写进来后当即就读、而且之后都不会读的一些流量切到 TiDB 里。由于 S3 存储分不少 bucket ,作活动的人就去新建一些 bucket, 这些 bucket 的元数据就直接存在 TiDB 里面,就不存 MySQL 了。
二、遇到的问题
Row id 的打散。这个问题正好是咱们这边碰到的一个性能上的问题。由于 TiDB 存储数据是这么存的:我要插入一行数据,他会有两行,第一行是索引,索引是 Key ,而后 value 是 row id;第二行是 row id 是 Key,value 是整行的数据,至关于第二行有点像汇集索引这种东西。可是这个汇集索引的 Key 是 row id。原来的版本实现上是说这个 row id 是个递增了,因此这种就致使无论你插入什么数据,这个 row id 都是递增的,由于 row id 一递增,这些数据都会打到一个 TiKV 的一个 region 上面。由于个人 TiKV 是一个有序的 Map,因此说 row id 若是递增的话,确定你们插入的时候都是打到一个 TiKV 上面。咱们当时业务的压力比较大,致使客户发现他把这个业务的机器实例数给扩容上去以后,会发现这个 insert 的 TPS 大概也就在两万,一行大概就一百多个字节吧,你再怎么加他上不去了,也就是说 insert 的这个 QPS 上不去了。
这一点 TiDB 新版本的方案就是,row id 不是单调递增,而是把 row id 打的很散,这种方案性能会比较好,没有热点。
内容出处: