HTAP 还可以这么玩?丨TiDB 在 IoT 智慧园区的应用

原创
2023/12/01 15:45
阅读数 6

作者:某物联网公司设施云平台负责人
用户简介:我们是一家提供全链智慧园区整体解决方案的物联网公司,致力于打造可持续发展的智慧园区。

基础设施平台简介

基础设施平台是集团一线作业人员日常工作中高度依赖的重要系统,涵盖了各类基础设施的管理、报修、保养等一系列数字化办公功能,同时实现了对基础设施、作业人员、项目成本等多种维度的精细化管理。其使命在于不断提升一线作业效率,提高业主的服务满意度。

以下为该平台手机端应用截图。工作中心页面提供了大量常用的业务功能,同时还包含了面对一线、项目、集团等多个维度的报表功能,是一个典型的 HTAP 混合负载场景。

 

面临的挑战

随着数据规模达到亿级别、业务规模不断扩大以及数字化需求的增加,该平台面临的挑战变得愈发严峻。在日常的业务高峰期,特别是在一些关键业务期间,如每周初、月初和月末,一线作业人员和集团运营业务部门的工作都可能受到一些影响。这主要是由于底层数据库在资源、架构和性能方面存在一些不足。

应用架构

原先采用 MySQL 数据库的主从架构来为平台提供服务(16VC/64GB),其中包括:

  • 主库存储业务数据(450GB),用于支撑应用中的绝大部分的业务功能,峰值 QPS 2500+;
  • 从库除了业务数据外,还有 ETL 转化之后的汇总数据(200GB),峰值 QPS 1000+,支撑:
    • 应用中的 BI 报表功能,集团的大屏实时展示;
    • ETL 数据计算,在业务数据基础上进行加工,并写入到汇总库中;
    • 当主库不可用时,支撑应用的高可用。

 

MySQL 不堪重负

  1. 在业务高峰期,主库的 CPU 使用率达到 90%,应用响应非常慢;
  2. 在业务高峰期,从库的 CPU 使用率也达到 90%,个别 BI 报表无法打开;
  3. 凌晨在从库上运行的 ETL 作业耗时非常久,有时到需要运行到第二天工作时间,严重影响 BI 报表服务。

 

为何引入 TiDB

在引入 TiDB 前,我们研讨了基于 MySQL 当前架构的扩容方案,将实例规格从 16VC/64G 扩展到 32VC/128G,甚至再加一个从节点,然后在应用层进行读写分离设计。

该扩容方案可以解决在并发时资源不足的问题,从而在一定程度上缓解高峰期服务响应慢的情况。然而,它并不能解决 SQL 本身执行速度较慢的问题。例如,在从库执行凌晨的 ETL 作业期间,虽然负载并不高,但是 ETL 运行时间很长。方案上还是存在一定的不足:

  1. 核心工单表 5 亿多行,扩容后,该表的查询和写入 SQL 性能仍然没有提升;
  2. BI 报表查询以及 ETL 转化作业时,涉及大量复杂的 Join/聚合计算,涵盖了多张大表,即使扩容了也还是慢;
  3. 花费成本高,同时改善空间有限:
    1. 3 倍的资源成本,从 32VC/128GB 变成 96VC/384GB;
    2. 改造成本,需要对应用代码进行读写分离的改造,随着未来该系统接入更多项目时,可能还需要投入更多精力进行分库分表的改造工作。

 

最终我们计划选择原生分布式数据库来解决该系统面临的问题,其中 TiDB 分布式数据库这些能力非常吸引我们:

  1. 原生分布式架构,能够彻底解决大数据量下读写性能问题;
  2. HTAP 混合负载,BI 或者 ETL 中包含大量复杂”Join/聚合“的 SQL,性能可以大幅提升;
  3. MySQL 兼容,使得应用架构和代码几乎不用调整便能完成应用的移植。

以下为 TiDB 的集群**配置(合计约 76VC)**

计算规格 数量 配置 备注
ir3.2xlarge.4 3 8VC/32GB/本地 SSD 盘 TiKV
ir3.4xlarge.4 1 16VC/64GB/本地 SSD 盘 TiFlash
c7.2xlarge.4 3 8VC/32GB/200GB(通用 SSD) TiDB
c7.xlarge.2 3 4VC/8GB/200GB(超高 IO) PD
elbv3.basic.1az 1 网络型(TCP/UDP) | 小型 II 负载均衡

OLTP 与 OLAP 负载彻底隔离的 HTAP 架构设计

应用架构无需改动

 

 

为了实现最小成本的系统移植,我们在一套 TiDB 中同时支撑 OLTP(应用基础功能)、OLAP(BI 报表、ETL 作业)两种负载,同时确保两种负载之间互不影响,并且提供了最大的可用性保障。以下是我们针对 TiDB HTAP 架构进行的一些设计。

存储节点规划

我们将 TiKV1 和 TiKV2 规划为 OLTP 区,将 TiKV3 和 TiFlash 规划为 OLAP 区

 

数据 Leader 隔离

默认情况下 TiDB 中数据 Leader 的分布是随机的,而 SQL 请求默认都是发往 Leader 执行,所以默认机制下无法满足我们的隔离要求。所以我们进行了如下设计:

  1. OLTP所用到的业务数据的 leader 固定在 TiKV1/TiKV2 上

策略一: policy_eyas(业务库策略)

预期效果:数据的 Leader 在 zone1 和 zone2 上,zone3 上不会产生 Leader(只有 Follower)

   -- 创建策略
  create placement policy policy_eyas leader_constraints = "[-zone=zone3]"; 
  -- 为业务库指定策略,让业务读写都发生在 TiKV 节点 1,2
  alter database eyas placement policy policy_eyas;

 

  1. 将 OLAP 中 ETL 作业产生的汇总数据的 leader 固定在 TiKV3 上

策略二:policy_bi(汇总库策略)

预期效果:数据的 Leader 只在 zone3 上,zone1 和 zone2 上只有 Follower (没有 Leader)

 -- 创建策略
create placement policy policy_bi leader_constraints="[+zone=zone3]" follower_constraints ='{"+zone=zone1": 1,"+zone=zone2": 1}';
-- 为汇总库指定策略,让汇总库上的读写都发生在 TiKV 节点 3 
alter database bi_eyas placement policy policy_bi;
alter database da_ping placement policy policy_bi;
  1. 为所有数据设置一份TiFlash副本
alter database eyas set tiflash replica 1;
alter database bi_eyas set tiflash replica 1;
alter database da_ping set tiflash replica 1;

目的:加速 BI 报表和 ETL 中复杂查询 SQL 的性能

计算隔离

我们同样也针对计算节点进行了隔离,TiDB1 和 TiDB2 两个计算节点接入负载均衡供应用节点使用,并且限制其只能访问 TiKV 上的数据(原因:应用基础功能无须使用 TiFlash)。

  config:
      isolation-read.engines:
      - tikv
      - tidb

对于 BI 应用和 ETL 平台,我们则是让其直连 TiDB3 计算节点。由于它们都存在大量复杂”Join/聚合“的SQL,我们希望这样的 SQL 可以通过优化器自动决定去 TiKV 或 TiFlash 引擎执行,以获得最大的性能,参数如下:

 config:
      isolation-read.engines:
      - tikv
      - tiflash
      - tidb
      labels.zone: zone3

注意:在 TiDB 数据库中,默认所有的读请求都是发往数据的 Leader,而在 ETL 作业中的输入基本都是查询业务库(非常复杂的 Join/聚合)、BI 报表中也有相当一部分会实时查询业务库(而业务库的数据 Leader 在 TiKV1/TiKV2 上),这样的 SQL 一旦出现将发往 TiKV1/TiKV2 上执行,此时会影响到应用核心功能。

为了避免这一问题,我们为 TiDB3 设置了一个 Label: zone3(与 TiKV3 的 Label 一致),此时便可以实现就近副本的读取(TiDB3 上即使有非常复杂的业务库的查询,也只会在 TiKV3 的 Follower 副本上或 TiFlash 上执行):

 set global tidb_replica_read = 'closest-replicas’;

使用效果:性能大幅提升

应用部分(页面端到端耗时)

  1. 应用核心功能基本优化到 1 秒内,大幅提升了一线的使用体验和作业效率;
  2. BI 报表性能大幅提升,之前打不开的报表均能快速展示,提升运营管理效率。
一级模块 二级模块 之前(秒) 现在(秒)
首页   6.53 0.74
服务台 工单跟踪 1.34 0.078
新建工单 2.13 0.98  
保养管理 制定保养计划 0.73 0.59
选择保养设备 0.78 0.87  
调整保养计划 0.71 0.57  
保养任务 3.08 0.63  
巡检管理 巡检计划 0.57 0.98
巡检任务 1.45 0.34  
BI**报表** 平台使用评价得分 6.3 5.51
平台使用评价得分 7.78 5.8  
人员执行数据 14.28 4.71  
集团首页 38.24 35.91  
平台公司首页 63 24.5  
项目首页 32.17 23.92  
项目月度运行报告 打不开 105.52  
平台使用评价得分 打不开 119  
平台公司月度运行报告 63 60  
平台使用评价得分 67 68.69  
各评价指标排名 107 7.72  
故障类型分析 打不开 6.47  
个人抢单统计表 5.4 4.25  
巡检工时异常统计 打不开 5.36  

注:一张报表包含若干条 SQL,最大的报表包含 200 多条 SQL(串行执行、页面逐一渲染展示)

ETL 作业

ETL 作业性能大幅提升,之前最久的作业执行超过 5 小时,现在的执行时间仅为 48 分钟,性能提升了 80% 以上。

作业名称 之前(时:分:秒) 现在(时:分:秒) 降低
sr_insp_pm_hebing 1:13:19 00:19:44 54分钟
大屏_维保 0:17:11 00:05:40 12分钟
insp_elevator_supervision 0:24:54 00:03:10 21分钟
insp_order 3:34:43 00:31:26 3小时
项目管理 0:48:53 00:06:55 42分钟
实时集团考核 1:00:32 00:21:14 40分钟
实时考核阶段2 0:00:57 00:00:09 48秒
实时计划进度分析 0:13:41 00:00:27 12分钟
table_sr_order 5:02:39 00:48:28 4小时14分钟
Taodaytask 0:31:56 00:04:08 27分钟
今日大屏数据 0:47:12 00:02:34 45分钟

遇到的问题和解决办法

虽然 TiDB 高度兼容 MySQL,几乎不需要改造,但在测试过程中发现了以下两处问题。

SQL 不兼容

5 条 SQL 报错:ON condition doesn't support subqueries yet,原因为 TiDB 在 join 中不支持 on 判断使用子查询,如:

1. select t1.* from sbtest1 t1 join sbtest2 t2 on t1.id=t2.id and t2.id in (select id from sbtest3)
2. select t1.* from sbtest1 t1 join sbtest2 t2 on t1.id=t2.id and exists (select 1 from sbtest3 t3 where t3.id=t1.id)

解决办法:改写成 join 表的形式

特定写法下 SQL 性能退化

像查询列中包含 case when in subquery 这样的写法时,执行时与这个 subquery join 的时候变成了笛卡尔积,性能退化十倍以上。

解决办法:上线版本为 TiDB 6.5.0,当时通过将 case when in subquery 改写成 exists 后解决,目前该问题已经在高版本中已经修复。

总结

TiDB 自今年 3 月上线以来,性能提升非常明显。目前已经平稳运行了超过半年时间,这充分增强了我们深度使用 TiDB 的信心。未来,我们计划利用 TiDB HTAP 架构来支撑更多业务场景的需求,持续创造价值。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部