作者:vivo 互联网大数据团队 - Wang Zhiwen

本文介绍了vivo在大数据元数据服务横向扩大路线上的摸索历程,由理论面临的问题登程,对以后支流的横向扩大计划进行了调研及比照测试,通过多方面比照数据择优抉择TiDB计划。其次分享了整个扩大计划流程、施行遇到的问题及解决方案,对于在大数据元数据性能上面临同样窘境的开发者本篇文章具备十分高的参考借鉴价值。

一、背景

大数据元数据服务Hive Metastore Service(以下简称HMS),存储着数据仓库中所依赖的所有元数据并提供相应的查问服务,使得计算引擎(Hive、Spark、Presto)能在海量数据中精确拜访到须要拜访的具体数据,其在离线数仓的稳固构建上扮演着无足轻重的角色。vivo离线数仓的Hadoop集群基于CDH 5.14.4版本构建,HMS的版本抉择追随CDH大版本,以后应用版本为1.1.0-cdh5.14.4。

vivo在HMS底层存储架构未降级前应用的是MySQL存储引擎,但随着vivo业务倒退,数据爆炸式增长,存储的元数据也相应的增长到亿级别(PARTITION_PARAMS:8.1亿、PARTITION_KEY_VALS:3.5亿、PARTITIONS:1.4亿),在如此大量的数据基数下,咱们团队常常面临机器资源的性能瓶颈,往往用户多并发的去查问某些大分区表(50w+分区),机器资源的使用率就会被打满,从而导致元数据查问超时,重大时甚至整个HMS集群不可用,此时复原伎俩只能临时停服所有HMS节点,直到MySQL机器负载降下来后在逐渐复原服务。为此,针对以后MySQL计划存在的重大性能瓶颈,HMS急需一套欠缺的横向扩大计划来解决以后当务之急。

二、横向扩大技术计划选型

为解决HMS的性能问题,咱们团队对HMS横向扩大计划做了大量的调研工作,总体下来业内在HMS的横向扩大思路上次要分为对MySQL进行拆库扩大或用高性能的分布式引擎代替MySQL。在第一种思路上做的比拟成熟的计划有Hotels.com公司开源的Waggle Dance,实现了一个跨集群的Hive Metastore代理网关,他容许用户同时拜访多个集群的数据,这些集群能够部署在不同的平台上,特地是云平台。第二种思路以后支流的做法是用分布式存储引擎TiDB替换传统的MySQL引擎,在Hive社区中有不少公司对hive 2.x接入TiDB做了大量的测试并利用到生产中(详情点击)。

2.1 Waggle Dance

Waggle-dance向用户提供对立的入口,将来自Metastore客户端的申请路由到底层对应的Metastore服务,同时向用户暗藏了底层的Metastore散布,从而在逻辑层面整合了多个Metastore的Hive库表信息。Waggle-dance实现了Metastore的Thrift API,客户端无需改变,对用户来说,Waggle-dance就是一个Metastore。其整体架构如下:

Waggle Dance架构

从Waggle-dance的架构中最突出的个性是其采纳了多个不同的MySQL实例分担了原单MySQL实例的压力,除此之外其还有如下劣势:

  1. 用户侧能够沿用Metastore客户端的用法,配置多台Waggle-dance的连贯,在以后Waggle-dance连贯服务不可用的时候切换到其余的Waggle-dance服务上。
  2. Waggle-dance只需几秒即可启动,加上其无状态服务的个性,使得Waggle-dance具备高效的动静伸缩性,能够在业务高峰期疾速上线新的服务节点扩散压力,在低峰期下线局部服务节点开释资源。
  3. Waggle-dance作为一个网关服务,除了路由性能外,还反对后续的定制化开发和差异化部署,平台可依据须要增加诸如鉴权、防火墙过滤等性能。

2.2 TiDB

TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库,是一款同时反对在线事务处理与在线剖析解决 (Hybrid Transactional and Analytical Processing, HTAP) 的交融型分布式数据库产品,具备程度扩容或者缩容、金融级高可用、实时 HTAP、云原生的分布式数据库、兼容 MySQL 5.7 协定和 MySQL 生态等重要个性。在TiDB 4.x版本中,其性能及稳定性较与之前版本失去了很大的晋升并满足HMS的元数据查问性能需求。故咱们对TiDB也做了相应的调研及测试。联合HMS及大数据生态,采纳TiDB作为元数据存储整体的部署架构如下:

HMS on TiDB架构 

因为TiDB自身具备程度扩大能力,扩大后能均分查问压力,该个性就是咱们解决HMS查问性能瓶颈的大杀器。除此外该架构还有如下劣势:

  1. 用户无需任何改变;HMS侧面没有任何改变,只是其依赖的底层存储发生变化。
  2. 不毁坏数据的完整性,无需将数据拆分多个实例来分担压力,对HMS来说其就是一个残缺、独立的数据库。
  3. 除引入TiDB作为存储引擎外,不须要额定的其余服务撑持整个架构的运行。

2.3 TiDB和Waggle Dance比照

后面内容对Waggle-dance计划和TiDB计划做了简略的介绍及劣势总结,以下列举了这两个计划在多个维度的比照:

通过上述多个维度的比照,TiDB计划在性能体现、程度扩大、运维复杂度及机器老本上都优于waggle-dance计划,故咱们线上抉择了前者进行上线利用。 

三、TiDB上线计划

抉择TiDB引擎代替原MySQL存储引擎,因为TiDB与MySQL之间不能做双主架构,在切换过程中HMS服务须齐全停服后并重新启动切换至TiDB,为保障切换过程顺利及前面若有重大问题产生能及时回滚,在切换前做了如下数据同步架构以保障切换前MySQL与TiDB数据统一以及切换后仍有MySQL兜底。

TiDB&MySQL上线前后数据同步架构

在上述架构中,切换前惟一可写入的数据源只有源数据库主库,其余所有TiDB、MySQL节点都为只读状态,当且仅当所有HMS节点停服后,MySQL源数据库从库及TiDB源数据库主库的数据同步最大工夫戳与源数据库主库统一时,TiDB源数据库主库才凋谢可写入权限,并在批改HMS底层存储连贯串后逐个拉起HMS服务。

在上述架构实现后,即可开始具体的切换流程,切换整体流程如下:

HMS切换底层存储流程

其中在保障源MySQL与TiDB数据失常同步前,须要对TiDB做以下配置:

  • tidb_skip_isolation_level_check须要配置为1 ,否则启动HMS存在MetaException异样。
  • tidb_txn_mode需配置为pessimistic ,晋升事务一致性强度。
  • 事务大小限度设置为3G,可依据本人业务理论状况进行调整。
  • 连贯限度设置为最大3000 ,可依据本人业务理论状况进行调整。

此外在开启sentry服务状态下,需确认sentry元数据中NOTIFICATION_ID的值是否落后于HMS元数据库中NOTIFICATION_SEQUENCE表中的NEXT_EVENT_ID值,若落后需将后者替换为前者的值,否则可能会产生建表或创立分区超时异样。

以下为TiDB计划在在不同维度上的体现:

  1. 在对HQL的兼容性上TiDB计划齐全兼容线上所有引擎对元数据的查问,不存在语法兼容问题,对HQL语法兼容度达100% 
  2. 在性能体现上查问类接口均匀耗时优于MySQL,性能整体晋升15%;建表耗时升高了80%,且反对更高的并发,TiDB性能体现不差于MySQL
  3. 在机器资源应用状况上整体磁盘使用率在10%以下;在没有热点数据拜访的状况下,CPU均匀使用率在12%;CPU.WAIT.IO平均值在0.025%以下;集群不存在资源应用瓶颈。
  4. 在可扩展性上TiDB反对一键程度扩缩容,且外部实现查问平衡算法,在数据达到平衡的状况下各节点可平摊查问压力。
  5. 在容灾性上TiDB Binlog技术可稳固撑持TiDB与MySQL及TiDB之间的数据同步,实现残缺的数据备份及可回退抉择。
  6. 在服务高可用性上TiDB可抉择LVS或HaProxy等服务实现负载平衡及故障转移。

以下为上线后HMS次要API接口调用耗时状况统计:

四、问题及解决方案

4.1 在模仿TiDB回滚至MySQL过程中呈现主键抵触问题

在TiDB数据增长3倍后,切换回MySQL呈现主键反复异样,具体日志内容如下:

主键抵触异样日志

产生该问题的次要起因为每个 TiDB 节点在调配主键ID时,都申请一段 ID 作为缓存,用完之后再去取下一段,而不是每次调配都向存储节点申请。这意味着,TiDB的AUTO_INCREMENT自增值在单节点上能保障枯燥递增,但在多个节点下则可能会存在激烈跳跃。因而,在多节点下,TiDB的AUTO_INCREMENT自增值从全局来看,并非相对枯燥递增的,也即并非相对有序的,从而导致Metastore库里的SEQUENCE_TABLE表记录的值不是对应表的最大值。

造成主键抵触的次要起因是SEQUENCE_TABLE表记录的值不为元数据中理论的最大值,若存在该状况在切换回MySQL后就有可能生成已存在的主键导致初见抵触异样,此时只需将SEQUENCE_TABLE里的记录值设置以后理论表中的最大值即可。

4.2 PARTITION_KEY_VALS的索引取舍

在应用MySQL引擎中,咱们收集了局部慢查问日志,该类查问次要是查问分区表的分区,相似如下SQL:

#以下查问为查问三级分区表模板,且每级分区都有过去条件SELECT PARTITIONS.PART_IDFROM PARTITIONS  INNER JOIN TBLS  ON PARTITIONS.TBL_ID = TBLS.TBL_ID    AND TBLS.TBL_NAME = '${TABLE_NAME}'  INNER JOIN DBS  ON TBLS.DB_ID = DBS.DB_ID    AND DBS.NAME = '${DB_NAME}'  INNER JOIN PARTITION_KEY_VALS FILTER0  ON FILTER0.PART_ID = PARTITIONS.PART_ID    AND FILTER0.INTEGER_IDX = ${INDEX1}  INNER JOIN PARTITION_KEY_VALS FILTER1  ON FILTER1.PART_ID = PARTITIONS.PART_ID    AND FILTER1.INTEGER_IDX = ${INDEX2}  INNER JOIN PARTITION_KEY_VALS FILTER2  ON FILTER2.PART_ID = PARTITIONS.PART_ID    AND FILTER2.INTEGER_IDX = ${INDEX3}WHERE FILTER0.PART_KEY_VAL = '${PART_KEY}'  AND CASE     WHEN FILTER1.PART_KEY_VAL <> '__HIVE_DEFAULT_PARTITION__' THEN CAST(FILTER1.PART_KEY_VAL AS decimal(21, 0))    ELSE NULL  END = 10  AND FILTER2.PART_KEY_VAL = '068';

在测试中通过管制并发重放该类型的SQL,随着并发的减少,各个API的均匀耗时也会增长,且重放的SQL查问耗时随着并发的减少查问均匀耗时达到100s以上,尽管TiDB及HMS在压测期间没有呈现任何异样,但显然这种查问效率会让用户很难承受。DBA剖析该查问没有抉择适合的索引导致查问走了全表扫描,倡议对PARTITION_KEY_VALS的PARTITION_KEY_VAL字段增加了额定的索引以减速查问,最终该类型的查问失去了极大的优化,即便加大并发到100的状况下均匀耗时在500ms内,对此咱们曾尝试对PARTITION_KEY_VALS增加上述索引操作。

但在线上理论的查问中,那些没有产生慢查问的分区查问操作其实都是按天分区的进行一级分区查问的,其SQL相似如下:

SELECT "PARTITIONS"."PART_ID"FROM "PARTITIONS"  INNER JOIN "TBLS"  ON "PARTITIONS"."TBL_ID" = "TBLS"."TBL_ID"    AND "TBLS"."TBL_NAME" = 'tb1'  INNER JOIN "DBS"  ON "TBLS"."DB_ID" = "DBS"."DB_ID"    AND "DBS"."NAME" = 'db1'  INNER JOIN "PARTITION_KEY_VALS" "FILTER0"  ON "FILTER0"."PART_ID" = "PARTITIONS"."PART_ID"    AND "FILTER0"."INTEGER_IDX" = 0  INNER JOIN "PARTITION_KEY_VALS" "FILTER1"  ON "FILTER1"."PART_ID" = "PARTITIONS"."PART_ID"    AND "FILTER1"."INTEGER_IDX" = 1WHERE "FILTER0"."PART_KEY_VAL" = '2021-12-28'  AND CASE     WHEN "FILTER1"."PART_KEY_VAL" <> '__HIVE_DEFAULT_PARTITION__' THEN CAST("FILTER1"."PART_KEY_VAL" AS decimal(21, 0))    ELSE NULL  END = 10;

因为对PARTITION_KEY_VALS的PARTITION_KEY_VAL字段增加了索引做查问优化,会导致该类查问生成的执行打算中同样会应用idx_PART_KEY_VAL索引进行数据扫描,该执行打算如下:

走idx_PART_KEY_VAL索引执行打算

增加的idx_PART_KEY_VAL索引在该字段的具备雷同值的数据较少时,应用该索引能检索较少的数据晋升查问效率。在hive中的表一级分区根本是按天进行分区的,据统计每天天分区的增量为26w左右,如果应用idx_PART_KEY_VAL索引,按这个数值计算,查问条件为day>=2021-12-21 and day<2021-12-26的查问须要检索将近160w条数据,这显然不是一个很好的执行打算。

若执行打算不走idx_PART_KEY_VAL索引,TiDB可通过dbs、tbls检索出所有关联partition数据,在依据part_id和过滤条件扫描PARTITION_KEY_VALS数据并返回。此类执行打算扫描的数据量和须要查问的表的分区总量无关,如果该表只有多数的分区,则查问可能迅速响应,但如果查问的表有上百万的分区,则该类执行打算对于该类查问不是最优解。

不走idx_PART_KEY_VAL索引执行打算

针对不同执行打算的个性,整顿了以下比照点:

在理论生产中元数据根本都是按天分区为主,每天增长大略有26w左右,且范畴查问的应用场景较多,应用idx_PART_KEY_VAL索引查问的执行打算不太适宜线上场景,故该索引需不适宜增加到线上环境。

4.3 TiDB内存突增导致宕机问题

在刚上线TiDB服务初期,曾数次面临TiDB内存溢出的问题,每次呈现的工夫都随机不确定,呈现的时候内存突增简直在一瞬间,若期间TiDB的内存抗住了突增量,突增局部内存开释在很长时间都不会失去开释,最终对HMS服务稳定性带来抖动。

TiDB内存突增状况

通过和TiDB开发、DBA联结剖析下,确认TiDB内存飙高的起因为用户在应用Dashboard功能分析慢查问引起;在剖析慢查问过程中,TiDB须要加载本地所有的slow-query日志到内存,如果这些日志过大,则会造成TiDB内存突增,此外,如果在剖析期间,用户点击了勾销按钮,则有可能会造成TiDB的内存透露。针对该问题制订如下解决方案:

  1. 应用大内存机器替换原小内存机器,防止剖析慢查问时内存不够
  2. 调大慢查问阈值为3s,缩小日志产生
  3. 定时mv慢查问日志到备份目录

4.4 locate函数查问不走索引导致TiKV负异常

在HMS中存在局部通过JDO的形式去获取分区的查问,该类查问的过滤条件中用locate函数过滤PART_NAME数据,在TiDB中通过函数作用在字段中是不会触发索引查问的,所以在该类查问会加载对应表的所有数据到TiDB端计算过滤,TiKV则需一直扫描全表并传输数据到TiDB段,从而导致TiKV负载异样。

locate函数导致全表扫描

然而上述的查问条件能够通过like形式去实现,通过应用like语法,查问能够胜利应用到PARTITIONS表的UNIQUEPARTITION索引过滤,进而在TiKV端进行索引过滤升高负载。

like语法走索引过滤

通过实现将locate函数查问转换为like语法查问,无效升高了TiKV端的负载状况。在HMS端实现变更后,TiKV的CPU使用率升高了将近一倍,因为在KV端进行索引过滤,相应的io使用率有所回升,但网络传输则有显著的降落,由均匀1G升高到200M左右。

变更前后TiKV的负载状况

除TiKV负载有显著的升高,TiDB的整体性能也失去显著的晋升,各项操作耗时呈量级升高。以下整顿了TiDB增删改查的天均匀耗时状况:

TiDB P999天均匀耗时统计

4.5 get_all_functions优化

随着hive udf的一直增长,HMS的get_all_functions api均匀耗时增长的也越来越久,均匀在40-90s,而该api在hive shell中首次执行查问操作时会被调用注册所有的udf,过长的耗时会影响用户对hive引擎的应用体验,例如执行简略的show database须要期待一分钟甚至更久能力返回后果。

原get_all_functions api均匀耗时

导致该api耗时重大的次要起因是HMS通过JDO形式获取所有的Function,在获取所有的udf时后盾会遍历每条func去关联DBS、FUNC_RU两个表,获取性能极低。而应用directSQL的形式去获取所有udf数据,响应耗时都在1秒以内实现,性能晋升相当显著。以下为directSQL的SQL实现逻辑:

select FUNCS.FUNC_NAME,  DBS.NAME,  FUNCS.CLASS_NAME,  FUNCS.OWNER_NAME,  FUNCS.OWNER_TYPE,  FUNCS.CREATE_TIME,  FUNCS.FUNC_TYPE,  FUNC_RU.RESOURCE_URI,  FUNC_RU.RESOURCE_TYPEfrom FUNCSleft join FUNC_RU on FUNCS.FUNC_ID = FUNC_RU.FUNC_IDleft join DBS on FUNCS.DB_ID = DBS.DB_ID

五、总结

咱们从2021年7月份开始对TiDB进行调研,在经验数个月的测试于同年11月末将MySQL引擎切换到TiDB。因为后期测试次要集中在兼容性和性能测试上,疏忽了TiDB本身可能潜在的问题,在上线初期经验了数次因慢查问日志将TiDB内存打爆的状况,在这特别感谢咱们的DBA团队、平台经营团队及TiDB官网团队帮忙剖析、解决问题,得以防止该问题的再次发生;与此同时,因为以后HMS应用的版本较低,加上大数据的组件在一直的降级演进,咱们也须要去兼容降级带来的变动,如HDFS降级到3.x后对EC文件读取的反对,SPARK获取分区防止全表扫描革新等;此外因为TiDB的latin字符集反对中文字符的写入,该个性会导致用户误写入谬误的中文分区,对于此类型数据无奈通过现有API进行删除,还须要在应用层去禁止该类型谬误分区写入,防止无用数据累积。

经验了一年多的理论生产环境测验,TiDB内存整体应用在10%以内,TiKV CPU应用安稳,应用峰值均在30核内,暂不存在零碎瓶颈;HMS服务的稳定性整体可控,要害API性能指标满足业务的理论需要,为业务的增长提供牢靠反对。在将来三年内,咱们将放弃该架构去撑持整个大数据平台组件的稳固运行,期间咱们也将继续关注行业内的变动,排汇更多优良教训利用到咱们的生产环境中来,包含但不限于对性能更好的高版本TiDB尝试,HMS的性能优化案例。