TiDB / TiSpark 在易果集团实时数仓中的创新实践

项目背景

目前企业大多数的数据分析场景的解决方案底层都是围绕 Hadoop 大数据生态展开的,常见的如 HDFS + Hive + Spark + Presto + Kylin,在易果集团,咱们初期也是采起这种思路,可是随着业务规模的快速增加和需求的不断变化,一些实时或者准实时的需求变得愈来愈多,这类业务除了有实时的 OLTP 需求,还伴随着一些有必定复杂度的 OLAP 的需求,单纯地使用 Hadoop 已经没法知足需求。git

现有的准实时系统运行在 SQL Server 之上,经过开发人员编写和维护相应的存储过程来实现。因为数据量不大,SQL Server 可以知足需求,可是随着业务的发展,数据量随之增加,SQL Server 愈来愈不能知足需求,当数据量到达必定的阶段,性能便会出现拐点。这个时候,这套方案已彻底没法支撑业务,不得不从新设计新的方案。github

选型评估

在评估初期,Greenplum、Kudu、TiDB 都进入了咱们的视野,对于新的实时系统,咱们有主要考虑点:算法

  • 首先,系统既要知足 OLAP 还要知足 OLTP 的基本需求;sql

  • 其次,新系统要尽可能下降业务的使用要求;数据库

  • 最后,新系统最好可以与现有的 Hadoop 体系相结合。缓存

Greenplum 是一套基于 PostgreSQL 分析为主的 MPP 引擎,大多用在并发度不高的离线分析场景,但在 OLTP 方面,咱们的初步测试发现其对比 TiDB 的性能差不少。架构

再说说 Kudu。Kudu 是 CDH 2015年发布的一套介于 Hbase 和 HDFS 中间的一套存储系统,目前在国内主要是小米公司应用的较多,在测试中,咱们发现其在 OLTP 表现大体与 TiDB 至关,可是一些中等数据量下,其分析性能相比 TiDB 有必定差距。另外咱们的查询目前主要以 Presto 为主,Presto 对接 Kudu 和 PostgreSQL 都是须要考虑兼容性的问题,而 TiDB 兼容 MySQL 协议,在应用初期能够直接使用 Presto-MySQL 进行统一查询,下一步再考虑专门开发 Presto-TiDB。并发

另外,咱们但愿将来的实时系统和离线系统可以通用,一套代码在两个系统中都可以彻底兼容,目前 Tispark 和 SparkSQL 已经很大程度上实现了这点,这支持咱们在之后离线上的小时级任务能够直接切换到 TiDB上,在 TiDB 上实现实时业务的同时,若是有 T+1 的需求也可以直接指 HDFS 便可,不用二次开发,这是 Kudu 和 GP 暂时实现不了的。app

最后,TiSpark 是创建在 Spark 引擎之上,Spark 在机器学习领域里有诸如 Mllib 等诸多成熟的项目,对比 GP 和 Kudu,算法工程师们使用 TiSpark 去操做 TiDB 的门槛很是低,同时也会大大提高算法工程师们的效率。运维

通过综合的考虑,咱们最终决定使用 TiDB 做为新的实时系统。同时,目前 TiDB 的社区活跃度很是好,这也是咱们考虑的一个很重要的方面。

TiDB 简介

在这里介绍一下 TiDB 的相关特性:TiDB 是基于 Google Spanner/F1 论文启发开源的一套 NewSQL 数据库,它具有以下 NewSQL 核心特性:

  • SQL支持 (TiDB 是 MySQL 兼容的)

  • 水平线性弹性扩展

  • 分布式事务

  • 数据强一致性保证

  • 故障自恢复的高可用

同时,TiDB 还有一套丰富的生态工具,例如:快速部署的 TiDB-Ansible、无缝迁移 MySQL 的 Syncer、异构数据迁移工具 Wormhole、以及 TiDB-Binlog、Backup & Recovery 等。

SQL Server 迁移到 TiDB

因为咱们公司的架构是 .NET + SQL Server 架构,因此咱们没法像大多数公司同样去使用 MySQL Binlog 去作数据同步,固然也就没法使用 TiDB 官方提供的 Syncer 工具了。所以咱们采用了 Flume + Kafka 的架构,咱们本身开发了基于 Flume 的 SQL Server Source 去实时监控 SQL Server 数据变化,进行捕捉并写入 Kafka 中,同时,咱们使用 Spark Streaming 去读取 Kafka 中的数据并写入 TiDB,同时咱们将以前 SQL Server 的存储过程改形成定时调度的 MySQL 脚本。

图:SQL Server 数据迁移到 TiDB

TiDB 前期测试

在测试初期,咱们采用 TiDB 的版本为 RC4,在测试过程当中曾经在同时对一张表进行读写时,出现 Region is stale 的错误,在 GitHub 上提出 Issue 后,TiDB 官方很快在 Pre-GA 版本中进行了修复。在测试环境,咱们是手动经过二进制包的形式来部署 TiDB ,虽然比较简单,可是当 TiDB 发布 GA 版本以后,版本升级倒是一个比较大的问题,因为早期没有使用 TiDB-ansible 安装,官方制做的升级脚本没法使用,而手动进行滚动升级等操做很是麻烦。因为当时是测试环境,在听取了 TiDB 官方的建议以后,咱们从新利用 TiDB 官方提供的 TiDB-ansible 部署了 TiDB 的 GA 版本。只须要下载官方提供的包,修改相应的配置,就能完成安装和部署。官方也提供了升级脚本,可以在相邻的 TiDB 版本以前完成无缝滚动升级。同时 TiDB-ansible 默认会提供 Prometheus + Grafana 的监控安装,官方提供了很是丰富完善的 Grafana 模板,省去了运维不少监控配置的工做量,借着 TiDB 部署监控的契机,咱们也完成了诸如 Redis,RabbitMQ,Elasticsearch 等不少应用程序的监控由 Zabbix 往 Prometheus 的迁移。这里须要注意的是,若是是用官方提供的部署工具部署 Prometheus 和 Grafana,在执行官方的中止脚本时切记跳过相应的组件,以避免干扰其余程序的监控。

TiDB 上线过程

在10月中旬,随着新机器的采购到位,咱们正式将 TiDB 部署到生产环境进行测试,整个架构为 3 台机器,3TiKV+3PD+2TiDB 的架构。在生产环境中的大数据量场景下,遇到了一些新的问题。

首先遇到的问题是 OLTP 方面,Spark Streaming 程序设置的 5 秒一个窗口,当 5 秒以内不能处理完当前批次的数据,就会产生延迟,同时 Streaming 在这个批次结束后会立刻启动下一个批次,可是随着时间的积累,延迟的数据就会愈来愈多,最后甚至延迟了 8 小时之久;另外一方面,因为咱们使用的是机械硬盘,所以写入的效率十分不稳定,这也是形成写入延迟的一个很主要的因素。

出现问题以后咱们当即与 TiDB 官方取得联系,确认 TiDB 总体架构主要基于 SSD 存储性能之上进行设计的。咱们将 3 台机器的硬盘都换成了 SSD;与此同时,咱们的工程师也开发了相应的同步程序来替代 Spark Streaming,随着硬件的更新以及程序的替换,写入方面逐渐稳定,程序运行的方式也和 Streaming 程序相似,多程序同时指定一个 Kafka 的 Group ID,同时链接不一样机器的 TiDB 以达到写入效率最大化,同时也实现了 HA,保证了即便一个进程挂掉也不影响总体数据的写入。

在 OLTP 优化结束以后,随之而来的是分析方面的需求。因为咱们对 TiDB 的定位是实时数据仓库,这样就会像 Hadoop 同样存在不少 ETL 的流程,在 Hadoop 的流程中,以 T+1 为主的任务占据了绝大多数,而这些任务广泛在凌晨启动执行,所以只能用于对时间延迟比较大的场景,对实时性要求比较高的场景则不适合,而 TiDB 则能很好的知足实时或者准实时的需求,在咱们的业务场景下,不少任务以 5-10 分钟为执行周期,所以,必须确保任务的执行时长在间隔周期内完成。

咱们取了两个在 SQL Server 上跑的比较慢的重要脚本作了迁移,相比于 SQL Server/MySQL 迁移至 Hadoop,从 SQL Server 迁移至 TiDB 的改动很是小,SQL Server 的 Merge 操做在 TiDB 里也经过 replace into 可以完成,其他一些 SQL Server 的特性,也可以经过 TiDB 的多行事务得以实现,在这一方面,TiDB 的 GA 版本已经作的很是完善,高度兼容 MySQL,所以迁移的成本很是小,从而使咱们可以将大部分精力放在了调优方面。

在脚本迁移完毕以后,一些简单的脚本可以在秒级完成达到了咱们的预期。可是一些复杂的脚本的表如今初期并没表现出优点,一些脚本与 SQL Server 持平甚至更慢,其中最大的脚本 SQL 代码量一共 1000 多行,涉及将近 20 张中间表。在以前的 SQL Server 上,随着数据量慢慢增大,天天的执行时长逐渐由 1-2 分钟增加到 5-6 分钟甚至更久,在双11当天凌晨,随着单量的涌入和其余任务的干扰延迟到 20 分钟甚至以上。在迁移至 TiDB 初期,在半天的数据量下 TiDB 的执行时长大体为 15 分钟左右,与 SQL Server 大体相同,可是并不能知足咱们的预期。咱们参考了 TiDB 的相关文档对查询参数作了一些调优,几个重要参数为:tidb_distsql_scan_concurrency,tidb_index_serial_scan_concurrency,tidb_index_join_batch_size(TiDB 提供了很好的并行计算能力)。通过验证,调整参数后,一些 SQL 可以缩短一倍的执行时间,但这里依旧不能彻底知足咱们的需求。

引入 TiSpark

随后,咱们把目光转向了 TiDB 的一个子项目 TiSpark,用官网的介绍来说 TiSpark 就是借助 Spark 平台,同时融合 TiKV 分布式集群的优点,和 TiDB 一块儿解决 HTAP 的需求。TiDB-ansible 中也带有 TiSpark 的配置,因为咱们已经拥有了 Spark 集群,因此直接在现有的 Spark 集群中集成了 TiSpark。虽然该项目开发不久,可是通过测试,收益很是明显。

TiSpark 的配置很是简单,只须要把 TiSprak 相关的 jar 包放入 Spark 集群中的 jars 文件夹中就能引入 TiSpark,同时官方也提供了 3 个脚本,其中两个是启动和中止 TiSpark 的 Thrift Server,另外一个是提供的 TiSpark 的 cli 客户端,这样咱们就能像使用 Hive 同样使用 TiSpark 去作查询。

在初步使用以后,咱们发现一些诸如 select count(*) from table 等 SQL 相比于 TiDB 有很是明显的提高,一些简单的 OLAP 的查询基本上都可以在 5 秒以内返回结果。通过初步测试,大体在 OLAP 的结论以下:一些简单的查询 SQL,在数据量百万级左右,TiDB 的执行效率可能会比 TiSpark 更好,在数据量增多以后 TiSpark 的执行效率会超过 TiDB,固然这也看 TiKV 的配置、表结构等。在 TiSpark 的使用过程当中,咱们发现 TiSpark 的查询结果在百万级时,执行时间都很是稳定,而 TiDB 的查询时间则会随着数据量的增加而增加(通过与 TiDB 官方沟通,这个状况主要是由于没有比较好的索引进行数据筛选)。针对咱们的订单表作测试,在数据量为近百万级时,TiDB 的执行时间为 2 秒左右,TiSpark 的执行时间为 7 秒;当数据量增加为近千万级时,TiDB 的执行时间大体为 12 秒(不考虑缓存),TiSpark 依旧为 7 秒,很是稳定。

所以,咱们决定将一些复杂的 ETL 脚本用 TiSpark 来实现,对上述的复杂脚本进行分析后,咱们发现,大多数脚本中间表不少,在 SQL Server 中是经过 SQL Server 内存表实现,而迁移至 TiDB,每张中间表都要删除和插入落地,这些开销大大增长了执行时长(据官方答复 TiDB 很快也会支持 View、内存表)。在有了 TiSpark 以后,咱们便利用 TiSpark 将中间表缓存为 Spark 的内存表,只须要将最后的数据落地回 TiDB,再执行 Merge 操做便可,这样省掉了不少中间数据的落地,大大节省了不少脚本执行的时间。

在查询速度解决以后,咱们发现脚本中会有不少针对中间表 update 和 delete 的语句。目前 TiSpark 暂时不支持 update 和 delete 的操做(和 TiSpark 做者沟通,后续会考虑支持这两个操做),咱们便尝试了两种方案,一部分执行相似于 Hive,采用 insert into 一张新表的方式来解决;另一部分,咱们引入了 Spark 中的 Snappydata 做为一部份内存表存储,在 Snappydata 中进行 update 和 delete,以达到想要的目的。由于都是 Spark 的项目,所以在融合两个项目的时候仍是比较轻松的。

最后,关于实时的调度工具,目前咱们是和离线调度一块儿进行调度,这也带来了一些问题,每次脚本都会初始化一些 Spark 参数等,这也至关耗时。在将来,咱们打算采用 Spark Streaming 做为调度工具,每次执行完成以后记录时间戳,Spark Streaming 只需监控时间戳变化便可,可以避免屡次初始化的耗时,经过 Spark 监控,咱们也可以清楚的看到任务的延迟和一些状态,这一部分将在将来进行测试。

TiDB 官方支持

在迁移过程当中,咱们获得了 TiDB 官方很好的支持,其中也包括 TiSpark 相关的技术负责人,一些 TiSpark 的 Corner Case 及使用问题,咱们都会在群里抛出,TiDB 的官方人员会很是及时的帮助咱们解决问题,在官方支持下,咱们迁移至 TiSpark 的过程很顺利,没有受到什么太大的技术阻碍。

实时数仓 TiDB / TiSpark

在迁移完成以后,其中一条复杂的 SQL,一共 Join 了 12 张表(最大表数量亿级,部分表百万级),在平时小批量的状况下,执行时间会在 5 分钟左右,咱们也拿了双11全量的数据进行了测试,执行时间在 9 分钟以上,而采用了 TiSpark 的方式去执行,双11全量的数据也仅仅花了 1 分钟,性能提高了 9 倍。整个大脚本在 SQL Server 上运行双11的全量数据之前至少要消耗 30 分钟,利用 TiDB 去执行大体须要 20 分钟左右,利用 TiSpark 只须要 8 分钟左右,相对 SQL Server 性能提高 4 倍,也就是说,每一年数据量最高峰的处理能力达到了分钟级,很好的知足了咱们的需求。

最后,无论是用 TiDB 仍是用 TiSpark 都会有一部分中间表以及与原表进行 Merge 的操做,这里因为 TiDB 对事务进行的限制,咱们也采用以万条为单批次进行批量的插入和 Merge,既避免了超过事务的报错又符合 TiDB 的设计理念,可以达到最佳实践。

有了 TiSpark 这个项目,TiDB 与 Hadoop 的生态体系获得进一步的融合,在没有 TiSpark 以前,咱们的系统设计以下:

图:多套数仓并存

能够发现,实时数仓与 T+1 异步数仓是两个相对独立的系统,并无任何交集,咱们须要进行数据实时的同步,同时也会在夜晚作一次异步同步,无论是 Datax 仍是 Sqoop 读取关系型数据库的效率都远远达不到 TiSpark 的速度,而在有了 TiSpark 以后,咱们能够对 T+1 异步数仓进行整合,因而咱们的架构进化为以下:

图:TiDB / TiSpark 实时数仓平台

这样就可以利用 TiSpark 将 TiDB 和 Hadoop 很好的串联起来,互为补充,TiDB 的功能也由单纯的实时数仓变成可以提供以下几个功能混合数据库:

  1. 实时数仓,上游 OLTP 的数据经过 TiDB 实时写入,下游 OLAP 的业务经过 TiDB / TiSpark 实时分析。

  2. T+1 的抽取可以从 TiDB 中利用 TiSpark 进行抽取。

  • TiSpark 速度远远超过 Datax 和 Sqoop 读取关系型数据库的速度;

  • 抽取工具也不用维护多个系统库,只须要维护一个 TiDB 便可,大大方便了业务的统一使用,还节省了屡次维护成本。

  • TiDB 自然分布式的设计也保证了系统的稳定、高可用。

  1. TiDB 分布式特性能够很好的平衡热点数据,能够用它做为业务库热点数据的一个备份库,或者直接迁入 TiDB 。

上面这三点也是咱们从此去努力的方向,因而可知,TiSpark 不只对于 ETL 脚本起到了很重要的做用,在咱们从此的架构中也起到了举足轻重的做用,为咱们建立一个实时的统一的混合数据库提供了可能。

与此同时,咱们也获得 TiDB 官方人员的确认,TiDB 将于近期支持视图、分区表,并会持续加强 SQL 优化器,同时也会提供一款名为 TiDB Wormhole 的异构平台数据实时迁移工具来便捷的支持用户的多元化迁移需求。咱们也计划将更多的产品线逐步迁入 TiDB。

总结

同时解决 OLAP 和 OLTP 是一件至关困难的事情,TiDB 和 TiSpark 虽然推出不久,可是已经知足不少应用场景,同时在易用性和技术支持上也很是值得称赞,相信 TiDB 必定可以在愈来愈多的企业中获得普遍应用。

做者简介:罗瑞星,曾就任于前程无忧,参加过 Elasticsearch 官方文档中文翻译工做,现就任于易果集团,担任资深大数据工程师,负责易果集团数据分析架构设计等工做。

相关文章
相关标签/搜索