TiDB 4.0 在 VIPKID 的应用实践

做者介绍:许超,VIPKID 资深 DBA 工程师。

本文主要分享 TiDB 4.0 版本在 VIPKID 的一个应用实践。主要涉及两个部分,第一部分是如今 TiDB 在 VIPKID 的一些应用场景,第二部分是介绍一下 TiDB 4.0 给咱们带来哪些惊喜和收益。算法

TiDB 在 VIPKID 的应用场景

首先简单介绍一下 VIPKID,VIPKID 是一家在线少儿英语教育公司,专一于服务 4-15 岁的青少儿和他们家长们,主要提供北美外教一对一授课服务,目前已经有超过 70 万的付费用户。微信

场景一:大数据量及高并发写入

回归主题, TiDB 在 VIPKID 的第一个应用场景是一些大数据量和高并发写入的场景,以下图所示:架构

举其中一个例子,咱们如今有一套教室排障的系统,这套系统会实时收集教室内的一些事件信息,好比进出教室还有教室内服务初始化的信息,这些信息是经过家长端还有教师端统一上报的,业务同窗能够根据这些信息快速定位到教室内的故障,而且作一些排障手段,好比说切换线路之类的来保证一些上课质量。并发

这套系统目前 TPS 峰值在 1 万左右,天天的新增数据量大概有 1800 万,这张表只保留最近两个月的数据,目前单表有 12 亿左右,数据量其实相对来讲已经比较大了,这种数据量若是如今放在 MySQL 里维护成本比较高,因此咱们把这套系统的数据整个迁移到 TiDB。app

在迁移过程咱们作了一些小的变更,在原有表的基础上把原来的自增 ID 去掉了,在建表的时候经过指定配置作一下预先打散,避免高写入量的时候出现写热点问题。关于热点定位,其实 TiDB 自己以前就提供了不少方式了,好比 3.0 版本其实通 information_schema.TIDB_HOT_REGIONS 这张表就能够定位,或者直接能够在 PD 里获取相应的热点 Region 信息,可是经过这种方式拿到的其实只是一个 Region ID,还须要调用具体的 TiDB server 的 API 来获取定位到具体的表或者索引。在 4.0 里,TiDB Dashboard 让热点直观地呈如今咱们面前,咱们能够直接看到热点写入量、读取量等等热点信息。异步

场景二:核心模块分库分表后的多维度查询

第二个场景是如今咱们的不少核心业务在早期就已经作了分库分表,好比约课表。对分库分表比较了解的同窗其实知道,通常分库分表的状况下只会以一个业务列做为 Sharding Key 作拆分,可是约课表这种状况下可能涉及到的维度比较多,既有教室、老师、学生还有课程;另外可能其余端也会访问这部分数据,好比教师端来访问这部分数据的时候他可能会以教师的维度来访问,若是作拆分的时候是以学生的维度拆分的,那么教师的访问请求会广播到全部分片上,这在线上是并不容许的。针对这个问题,咱们最开始有两种解决方案,一种是咱们把全部的数据汇聚完放在 ES,还有一种方式是业务双写,写两套集群,两套集群以各自的维度拆分。不管哪一种方案,不管是对 RD 来讲仍是对咱们 DBA 来讲维护成本都比较高。分布式

因此咱们就借助 DM,经过 DM 将上游全部分片的表实时同步到下游,而且合并成一张全局表,全部的跨维度的查询,不管是管理端运营平台,仍是业务指标监控的系统都走 TiDB 这套系统,查这张全局表,以下图所示:函数

再简单介绍一下 DM 分库分表的逻辑,其实逻辑相对比较简单,DM 其实会拉取线上全部分片的 Binlog 日志,而后根据黑白名单过滤匹配出须要同步的那部分 binlog event,再去匹配制定的路由规则,经过改写而后应用到下游的全局表里,这里也区分两种状况:一种状况是上游的分库分表包含全局 ID,这种状况其实自然的避免了合并以后的主键冲突的问题。还有一种是没有全局 ID 的状况,这种状况以前官方提供了一个解决方案是经过 Column mapping 的方式,其实就至关于对 ID 列在同步以前作一些预处理,处理以后至关于在底层同步的时候就不会有主键冲突的问题了。可是咱们和 PingCAP 同窗沟通了一下,其实他们如今已经不建议用这种方式了。因此咱们换了另一种方式,由于咱们的业务对于这种自增 ID、主键 ID 是没有业务依赖的,因此在下游 TiDB 这块我其实提早建了下图所示的这样一张表,而后把对应 ID 的主键属性和自增属性去掉,而且将这个 ID 加入我原先仅有的一个联合的惟一索引里就解决这个问题了:高并发

在 DM 这块咱们简单地作了两件事。第一是 DM 的延迟监控,其实 DM 自己支持延迟监控,也是经过写心跳的方式去作的,但在咱们线上把 DM 并非挂在 MySQL 集群的主节点下,而是挂在一个只读存库上,因此咱们不太容许 DM 直接去写存库的心跳。咱们线上有一套心跳机制来监控延迟,因此在实际 DM 这块延迟监控实际复用的是线上的那套心跳表,至关于把线上的那套心跳直接同步下来,也是经过路由规则匹配一下,而后改写。这样的话虽然在 TiDB 里可能涉及到多个集群,但其实每一个集群对应单独的一个心跳表,这样就能够作 DM 的延迟监控。在下图里你们能够看到,大部分状况下分库分表合并的场景同步延迟基本都在 200 毫秒之内:工具

第二件事就是解决 DM 高可用问题,因为 DM 自己并不具备高可用性,可能一个 DM worker down 的时候可以支持自动拉起,但若是出现整个节点 down 的状况下实际上是一筹莫展的。以下图所示,咱们作了一个简单的尝试:

至关于把 DM-master、DM-worker 的全部的持久化的数据全放在共享存储上,DM-worker 是经过容器启动的,若是发生节点宕机的状况下,只须要在备用机上把对应的 worker 提起来,而且关联到本身指定的 DM-worker 的共享存储上 DM 的路径就行。这里有一个问题是 IP 是固化不了的,因此在这个过程当中还须要去变动 DM-master 的配置文件,以后作一次 Rolling Update。

场景三:数据生命周期管理

TiDB 在 VIPKID 的第三个场景其实就是在数据生命周期管理。若是用过 MySQL 的都知道,其实大表在 MySQL 里维护起来成本是比较高的,因此通常不少公司会作逐级的数据归档。咱们如今是根据具体业务,按照读写状况将数据划分红多个等级,并把其中温数据、冷数据,其实还有线上读流量的放在 TiDB 里。

这个场景里引入 TiDB 的考虑是要把数据的流转、运转起来的一个前提要保证冷热数据的表结构一致,但实际状况是,冷数据大部分状况下比热数据体量大不少,好比线上热数据作了一次表结构变动,好比加一列,同时若是冷数据一样要作这个操做,成本实际上是很高的,多是热表的十几倍或者几十倍都有可能,所以咱们想借助 TiDB 来作这个事情。自己一方面 TiDB 的 DDL 有一些特性,加字段、减字段都是秒级的,另外一方面就是借助 TiDB 自己的水平扩展的能力,咱们能够每一个业务端复用一套 TiDB 归档集群。下面再简单总结一下咱们在使用 TiDB DDL 的相关经验,以下图所示:

左半部分我列了几个相对比较常见的 DDL 操做,好比删表、删索引,其实在 TiDB 里分了两步作,第一步只变动元数据,这时候就已经秒级返回给用户了,剩下实际数据的清理,是放在后台经过 GC 异步来处理的。而添加索引操做由于涉及到数据的填充和重组,因此这个操做的时间是依赖于数据量,可是并不会阻塞线上业务,我以前看了一下官方的介绍,TiDB 中数据填充的过程被拆分为多个单元,每一个单元内部并发进行读写操做。线上更常见的是删列和减列,在 TiDB 里跟 MySQL 的实现就不同了,也只是变动元数据就好了,并不须要作底层的数据的 rebuild,好比增长一个列,并不须要对原始数据再作一个回填,这里分两种状况,一种是默认值是空的,一种是有一个指定的默认值,其实只须要把这个默认值记录到 TiKV 里跟表结构记录在一块,当你查询这个数据对列值作 decode 的时候,若是是空的,直接返回空;若是是有指定的默认值的,直接返回指定默认值,并不须要对历史数据作变动。

场景四:实时数据分析的场景

还有一个场景就是作实时数据分析的场景,下图实际上是最先 TiDB 在 VIPKID 引入的一个场景:

这个场景主要是 BI 分析师还有一些 BI 平台在用,架构上,至关于经过 DM 把线上的数据所有同步到 TiDB 里,借助 TiDB 的水平扩展能力,还有一些计算下推的能力,作一些实时数据分析。

TiDB 4.0 给咱们带来哪些惊喜和收益?

TiFlash 列式存储引擎

TiFlash是一个列式存储引擎,相对来讲对 AP 场景更友好一些,而且他自己本身有计算能力,支持一些算子下推、计算加速。另外,TiFlash 能够实时复制 TiKV 中的数据,而且没有打破以前 TiKV 的运行模式,它把本身做为一个 Learner 角色加入以前的 Raft Group 里能够支持表粒度的同步;还有一个就是智能选择,TiFlash 能够自动选择使用 TiFlash 列存或者 TiKV 行存,甚至在同一查询内混合使用以提供最佳查询速度,它已经不只仅是单纯的一个 SQL 选择哪一种存储引擎,粒度能够细化到同一个 SQL 里具体某个算子,好比一个 SQL 打过来,一部分能够走索引的其实走行存更快,还有一部分涉及到全表扫描的走列存,经过这种方式总体提升 SQL 查询速度。最后,TiFlash 支持独立部署,能够跟 TiKV 独立分开,某种程度上作到了硬件资源的隔离。

下面谈谈 TiFlash 给咱们带来的收益。

首先是性能提高,我这里作了一个简单测试,测试环境如今是有五个 TiKV 节点,一个 TiFlash 节点,有一个单表 2.5 亿数据,而后我对这个单表作 count,在 TiKV 里走了索引的状况下跑了 40 多秒。而在单个 TiFlash 场景下 10 秒就跑出来了,这只是单个 TiFlash 节点,若是我再新添一些 TiFlash 节点,这个速度应该还能够进一步提升。

<div class=”caption-center”>TiFlash</div>

<div class=”caption-center”>TiKV</div>

第二是成本的降低,咱们原来有一套给 BI 用的集群,如今用新的 TiDB 4.0 的集群替换了,能够看一下下图左边的表格是新的 4.0 的集群各个组件资源分配比例,左边是新、老集群一样负载状况下的资源分配状况。能够看到,部署新集群让咱们总体成本降低了 35%。

第三 TiFlash 上线解决了一些稳定性的问题。以前在 TiKV 这一层若是跑了一些 TP 业务,这时候有一个  SQL  涉及到一个全表扫描,整个 TiKV 的集群负载就会变大,可能致使 TP 查询总体响应时间变长。如今我能够加入一个 TiFlash 节点,把对应集群里的大表自动添加一个 TiFlash 的副本,在这种状况下若是有一些相似的状况,能够优先会走 TiFlash,而保证 TiKV 尽可能不受影响。

再说两点咱们在使用 TiFlash 过程当中遇到的一些“限制”。

第一,若是你的 SQL 中涉及到一些 TiFlash 尚未实现的函数,实际上是没法作到计算下推的,只是利用到了 TiFlash 自己做为列存的一个加速能力(注:若是有还没有实现的下推需求,能够与 PingCAP 官方联系技术支持,添加微信号XXX,备注“TiFlash 技术咨询”便可)。

第二,如今 TiFlash 对大表和大表之间的 JOIN 场景其实覆盖的还不够好,只针对小表和大表之间的 Join 作了一些优化(固然后来咱们经过 PingCAP 同窗了解到他们 7 月会发布一个优化大小表 JOIN 的功能,可让若干小表 JOIN 大表比现有方案数量级提高的优化,而且他们今年也会开始陆续优化剩下的 JOIN 场景)。若是你们对 Spark 比较了解的话,可能知道 Hash Join 其实有几种算法,其中一种至关于把一张小表广播到各个数据节点,而后在数据节点本地作 Hash Join 操做,能够看到下图左边的截图,是咱们一个教师招募相关的一个大屏统计:

这个查询执行了大概 17 分钟,实际过程当中也访问了 TiFlash,但总体的时间其实都耗费在 Hash Join 了,在 TiFlash 上消耗的时候并很少,图上能够看到 TiDB server 这一侧总体负载很高,因此瓶颈是在 TiDB server 这块。

所以咱们就考虑怎么把 Hash Join  这块打散,而后咱们引入了 TiSpark。以下图所示:

通过对比测试(单个 TiDB server 是 8C 64G 的),分配一样的计算资源给一个小的 TiSpark 集群跑了一个一样的查询,耗时差很少是原来的大概三分之一。下图是改造后给 BI 用的一个 TiDB server 的集群:

这里主要添加了 TiSpark 的组件和 TiFlash 的组件,因为大屏展现 SQL 能够明确,因此不少直接走了 TiSpark,而 BI 分析师和 BI 平台的查询统计,直接走 TiDB,而后智能选择让它走 TiKV 仍是 TiFlash。

TiDB Dashboard

TiDB 4.0 中内置的 Dashboard 在个人理解里,实际上是 TiDB 在产品易用性、“开箱即用”层面作了一次很大的提高。

在 3.0 版本像热点的问题也是有方式能够查的,可是相对来讲可能有必定的学习成本,另外可信息比较零散。如今 4.0 版本把这些都放在了 Dashboard 里,以一个更直观的方式展示给用户。而后就是 Dashboard 里好比说像日志搜集还有慢日志这块,这块其实跟刚才的逻辑同样其实就是为了让用户能够更简单的使用 TiDB,若是没有这些东西的话,用户集群小的话能够去具体节点上去查,若是集群规模比较大,可能用户要本身准备一套日志提取、日志上报的东西,实际上是存在必定的落地成本的。还有一块是在集群诊断这一块,集群诊断这块像咱们的业务其实每周有一个按期的活动,有时候研发会说我这周和上周的量并无明显的变化,但其实感受到下边的响应时间变长了,其实能够生成指定的诊断报告,里边我能够明确一个基准的区间作对比:

Backup & Restore 

以前 TiDB 在备份这块相对来讲相对空白了一点,只支持逻辑备份,但说大数据量的状况下逻辑备份效率是很低的,因此如今 4.0 中的 BR 工具偏物理备份,仍是让人很受鼓舞的。

BR 自己的程序去跟 PD 通讯,来获取当前的时间戳,还有目前 TiKV 的分布状况,而且 BR 本身在内部启动一个临时的 TiDB 实例,去构建一个备份相关的请求信息,而且将请求信息发给各个 TiKV 节点,因此这个过程当中备份实际上是一个分布式的备份,指定的 TiKV 节点会只备份本身当前实例上的主节点,作相似于物理备份,当他把  Region Leader 备份完了以后会把对应的元数据返回给 BR,BR 会把这些元数据保存在一个单独的文件里,而后待恢复的时候使用。

咱们简单试用了一下,以下图所示:

咱们按官方的建议,以共享存储的方式来作备份,至关于在 BR 那台机器还有全部 TiKV 的机器上都挂了相同的共享存储作了一次备份,一个 2.4T 左右的 TiDB 实例备份了大概几个小时,这个时间还能够进一步优化的,由于我看平均速度才 80 多兆,多是受限于如今 SAS 盘带宽的问题,后期作一下调整会更快。你们从上图也能看到 BR 备份的各个目录的大小,总体备份大小能够看到大概有 700 多 G。

以上就是所有分享,谢谢你们。

本文整理自许超在  TiDB DevCon 2020 上的演讲。
相关文章
相关标签/搜索