StarRocks实战——携程火车票指标平台建设

news2024/11/16 19:52:22

目录

前言

一、早期OLAP架构与痛点

二、指标平台重构整体设计

2.1 指标查询过程

2.1.1 明细类子查询

2.1.2 汇总类子查询

2.1.3 “缓存”

2.2 数据同步

三、Starrocks使用经验分享

3.1 建表经验

3.2 数据查询

3.3 函数问题

四、查询性能大幅提升

五、 后续优化方向


   原文大佬介绍的这篇火车票指标平台建设有借鉴意义,现摘抄下来用作沉淀学习。如有侵权,请告知~

前言

    携程火车票事业群运营着铁友、携程火车票和去哪儿火车票等重要的业务和品牌,目前正在积极地拓展海外市场。火车票的指标平台旨在为业务人员提供便捷的指标查询服务,让业务人员能够快速灵活的获得这些业务和品牌相关的指标数据。

一、早期OLAP架构与痛点

  火车票事业群的业务涵盖了火车票、国际火车票、汽车票(含船票)等产品,错综复杂的业务也产生了多种多样订单和行为数据,通过对这些数据的分析可以揭示当前业务的发展现状,也可以为未来的发展提供方向指引。

  早些时候事业群开发过一套指标平台,根据不同的指标类型使用了3套数据库引擎,分别是ClickHouse,Apache Kylin (以下简称 Kylin)和 Presto,如下图所示:

   在旧版的指标平台中,为了提升查询性能使用了ClickHouse,Kylin和Presto等多种存储和查询引擎,数据层混合使用了明细层和轻度汇总层,由此带来的问题有:

  • 指标数据源混乱,容易造成口径不一致,维护成本大;
  • 学习成本高,BI 同学录入指标不仅需要了解不同存储的区别,还需要掌握不同引擎的数据同步方法
  • 架构不合理,指标平台将查询的中间结果通过jdbc写入mysql后再到服务端用java做汇总计算,处理链路过长,整体性能非常差,导致部分指标查询需要半小时以上的等待时间。

  鉴于这些原因,无论是用户(运营人员)还是指标开发人员,都面临着使用极差的问题,在这种情况下,决定使用基于一种查询速度快和使用简单的分布式数据库来重构指标平台。

二、指标平台重构整体设计

   重构指标平台首先考虑的是将多套存储合并成一套, 虽然ClickHouse 和 Kylin 已经足够强大,但是不足也很明显。比如 ClickHouse 的 join 性能不尽如人意,并发性能差,大量的查询很容易将 CPU打满;Kylin 是一个分析引擎,不支持增删改操作,修改数据需要重新导入,修改 schema 需要重建 Cube(ETL成本很高),其次 Kylin需要预先创建模型加载数据到 Cube 后才可进行查询,使用上需要具备一定的数仓知识。

于是将目光投向 StarRocks,StarRocks 是一款全场景的MPP数据库,相比ClickHouse等具有以下优点:

  • 性能强悍:查询速度快,多张亿级表Join也能秒级响应;
  • 使用简单:兼容 MySQL 协议,用户使用门槛低;
  • 支持高并发:满足大量用户同时查询;
  • 支持多种数据模型:明细、聚合、更新和主键模型,可灵活配置ETL任务
  • 支持物化视图:可以自动路由到命中的物化视图,用户无感知;
  • 支持多种导入方式:StreamLoad、SparkLoad、RoutineLoad,便于实时离线快速导入StarRocks,流批一体。

因此,重构后的结构如下:

   重构后的指标平台只有一个数据库,查询时利用StarRocks内部ETL将明细数据转存到临时表,后续的汇总从临时表查询,避免了反复扫描大表。

2.1 指标查询过程

  当一个指标查询请求发起时,由于指标属性和用户想查看的信息不同,根据查询参数将查询拆解成若干子查询,子查询分为明细和汇总两类。

2.1.1 明细类子查询

1)可累加的指标查询时间范围内的明细数据,以及去年和2019年同期的明细数据,这部分的明细会存储到临时表,后续查询都从这张表扫描,以避免对大表的频繁扫描;该表每天生成T+1 分区,防止增加分区失败导致当天的指标查询无法进行。

-tarpresqls "
ALTER TABLE ${table} ADD PARTITION if not exists p${partition}
VALUES [('${zdt.addDay(1).format("yyyy-MM-dd")}'),('${zdt.addDay(2).format("yyyy-MM-dd")}'));
" \

2)如果指标不可累加或 count(distinct)类,仅存储查询时间范围内的明细,不存储用户计算同环比的明细;

3) 当多个指标同时对相同维度进行查询时,将多个指标的数据Join后以宽表模式存储。

2.1.2 汇总类子查询

  这一类 sql 主要在明细的基础上根据用户的需要做相应的计算,相比旧版本在服务内部用java做汇总计算,这里全部借助了StarRocks,主要的汇总功能有:

  • a.指标卡汇总和同环比;
  • b.折线图和维度下钻;

2.1.3 “缓存”

   多维度特别是包含出发/到达城市组合的查询数据量非常大,耗时较长,同时避免相同的查询反复访问大表,我们增加了“缓存”功能,实现原理如下:

  • a.记录初次查询的指标信息,主要包括维度和维度值,时间范围,指标原始计算sql的md5值,以及是否查询成功;
  • b. 新的查询进入后,会在当天的记录中查找是否存在相同的查询。如果存在相同的查询,使用唯一的查询标识(groupkey)将当前查询指向上次已经执行过的查询。这样,可以直接读取上次查询的详细数据和汇总结果,从而提高查询效率。

    因此这里的缓存非真实意义上的缓存,而是直接调用相同查询的结果。

2.2 数据同步

  首先梳理了旧平台的数据源,从300+指标的逻辑sql中提取了公共的dwd和dim表51张,并将这些数据统一同步至StarRocks,而对于一些指标使用的dwd表只出现一次的,依然将dws同步过来。

  对于不同的hive表,使用了不同的StarRocks建表模型和同步方式,有以下几种:

  • a.全量同步:主要针对一些数据量小的表,例如 shareout_trn.dim_ibu_alliance,大小为 608k;
  • b.增量分区同步:每天同步 hive 表中 T-1 的分区,各分区之间独立;
  • c.更新同步:火车票 BU 的一些订单数据由于涉到预售和订单状态的变更,变更的数据时间跨度比较大,将跨度范围内的数据全部更新代价比较高,因此使用更新模型。

   数据导入更新模型直接需要计算T-1 和 T-2 分区有差异的数据,这里将所有字段使用concat_ws('|',***)拼接后取 hash值,之后Join找到hash值不一致的数据。

模型KEY设置:
UNIQUE KEY(`order_id`)
取两天有差异的数据:
select
t1.* 
from
(select … where d='${cur_day}') as t1
left join
(select … where d=’${pre_day}’) as t2
on t1.business_pk_id=t2.business_pk_id
where t1.hash_code!=t2.hash_code or t2.order_id is null
  • d. 每天同步当月数据:如国际后的访问数据量较小,每天一个分区会导致StarRocks 集群有很多小的bucket,分桶数太多会导致元数据压力比较大,数据导入导出时也会受到一些影响,因此按月设置分区,每天同步当月的数据。
时间范围:
startdate='${zdt.format("yyyy-MM-01")}'
endDate='${zdt.add(2,1).format("yyyy-MM-01")}'
表设计:
PARTITION BY RANGE(dt)(Start("2019-01-01") End("2023-03-01") Every(Interval 1 month))
DISTRIBUTED BY HASH(分桶字段) BUCKETS 桶的数量
PROPERTIES (
"dynamic_partition.enable" = "true",
"dynamic_partition.prefix" = "p",
"dynamic_partition.time_unit" = "month",
"dynamic_partition.end" = "1");
datax配置:
-temporary_partitions "tp${partition}" \
-tarpresqls "
ALTER TABLE ${table} DROP TEMPORARY PARTITION if exists tp${partition};
ALTER TABLE ${table} ADD PARTITION if not exists p${partition} VALUES [('${startdate}'),('${endDate}'));
ALTER TABLE ${table} ADD TEMPORARY PARTITION tp${partition} VALUES [('${startdate}'),('${endDate}'));
" \
-tarpostsqls "
ALTER TABLE ${table} REPLACE PARTITION (p${partition}) WITH TEMPORARY PARTITION (tp${partition});"

    此外对于 UBT类数据,数据量及非常大,并且常见用于查询PV,UV 和停留时长等比较固定的场景,于是我们从中抽取出三张表:

  • ubt_for_pv: 每天按维度汇总 count(uid),每天数据大小只有几十 K;
  • ubt_for_duration: 每天按维度汇总 sum(duration),如需要计算平均停留时长除以对应的 pv 即可;
  • ubt_for_uv: 每天按维度去重,尽最大可能减少数据量。

     最后鉴于上游表的迭代可能带来的数据的不稳定,对需要同步的表的数据量做了监控,若发现当天的数据量波动超过3sigma,监控任务自动发出邮件告警,这些 job同步都在15 分钟内完成。

三、Starrocks使用经验分享

   在指标平台重构的过程中也遇到了一些问题,与数据和查询相关的有以下几个:

3.1 建表经验

   首先是buckets设置不合理,多数是设置过多,通常一个桶的数据量在500MB~1GB 为佳,个别表设置的桶数量太少,导致查询时间长;其次是分区不合理,有些表没有设置分区,有些设置的分区后每个分区数据量很小,优化建议是将不常访问的数据按月分区,经常访问的数据按日分区。

3.2 数据查询

   由于指标的查询sql之前是针对不同引擎编写,很多引擎是没有索引的,比如Presto。StarRocks有丰富的索引功能,统一至StarRocks 希望利用索引加速查询,因此过滤条件中最好不要加函数,比如select c1 from t1 where upper(employeeid) = upper(' s1')修改成select c1 from t1 where employeeid in(upper(' s1'), lower(' s1'))。

 另外很多sql没有使用分区,在StarRocks中将会全表扫描造成资源浪费

3.3 函数问题

   StarRocks的split函数结果的下标从1开始,而 sparksql 等引擎对应的是从 0 开始,导致 sql 在 StarRocks执行查询的时候不报错但是结果错误。

select split('a,b,c',',')[0] StarRocks查询结果为空,其他引擎查询结果为‘a’
select split('a,b,c',',')[1] StarRocks查询结果为‘a’,其他引擎查询结果为‘b’

四、查询性能大幅提升

    指标平台的重构主要是为了解决查询性能问题,并且重构后也基本达到了预期。重构之后,复杂查询需要数分钟的时间才能完成,特别对于火车票相关指标,诸如出票票量指标,如果带上出发和到达城市查询,可能需要等待 30 分钟以上,并且查询失败率较高。而在重构后,查询时间大大缩短,复杂查询在 10s 左右,并且 P99 在 2 秒之内,因此整体体验得到显著提升,用户查询次数相比改造前也有了翻倍的增长。

   此外,现在新指标系统还丰富了更多功能,比如同环比和维度下钻计算。得益于StarRocks的并发能力,可以在生成子查询SQL 后并发提交,从而大幅度减少响应时间,使得用户在进行维度下钻时几乎无需等待即可快速获取所需数据。

五、 后续优化方向

1)目前,UV 类的 Count Distinct 查询是基于存储了大量明细数据的方式进行的。然而,对于部分指标,可以尝试使用Bitmap 来减少不必要的明细数据存储空间,并且更重要的是可以提高查询速度。在接下来的工作中,计划尝试这种方案,以进一步优化 UV 类指标的查询性能。

2)对于全量或增量更新的表使用聚合模型,聚合模型会对导入后具有相同维度的数据做预聚合,查询的时候减少扫描数据的行数达到提升查询速度的目的。

3)当前的指标平台计算过程将所需的数据写入临时表,后续改成使用物化视图,在达到同样效果的情况下减少了复杂度

参考文章:

干货 | 提速10倍+,StarRocks 指标平台在携程火车票的实践

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1568099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法——分治(快速排序)

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享分治算法关于排序排序的专题 对于快速排序在我个人主页专栏 <排序> 有详细的介绍,此专题对快排进行了优化操作,并介绍了优化后的快排的几种运用 如果有不足的或者错误的请…

利用Lora调整和部署 LLM

使用 NVIDIA TensorRT-LLM 调整和部署 LoRA LLM 大型语言模型 (LLM) 能够从大量文本中学习并为各种任务和领域生成流畅且连贯的文本&#xff0c;从而彻底改变了自然语言处理 (NLP)。 然而&#xff0c;定制LLM是一项具有挑战性的任务&#xff0c;通常需要完整的培训过程&#xf…

C++ 2024-4-1 作业

#include <iostream> using namespace std;class A { public:int a;A(int a):a(a){cout<<"A的有参构造"<<endl;} }; class B:virtual public A { public:int b;B(int a,int b):A(a),b(b){cout<<"B的有参构造"<<endl;} }; cl…

反截屏控制技术如何防止信息通过手机拍照泄漏?

反截屏控制技术为企业数据安全提供了重要的防护措施。通过以下几点&#xff0c;有效阻止了信息通过拍照等方式的泄漏&#xff1a; 反截屏控制开启&#xff0c;用户启动截屏操作时&#xff0c;允许非涉密内容截屏操作&#xff0c;但所有涉密内容窗口会自动隐藏&#xff0c;防止涉…

openstack云计算(一)————openstack安装教程,创建空白虚拟机,虚拟机的环境准备

1、创建空白虚拟机 需要注意的步骤会截图一下&#xff0c;其它的基本都是下一步&#xff0c;默认的即可 ----------------------------------------------------------- 2、在所建的空白虚拟机上安装CentOS 7操作系统 &#xff08;1&#xff09;、在安装CentOS 7的启动界面中…

Vue依赖注入,详细解析

Prop 逐级透传问题​ 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。想象一下这样的结构&#xff1a;有一些多层级嵌套的组件&#xff0c;形成了一颗巨大的组件树&#xff0c;而某个深层的子组件需要一个较远的祖先组件中的部分数据。…

【JavaWeb】Day32.MySQL概述

什么是数据库 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。 像我们日常访问的电商网站京东&#xff0c;企业内部的管理系统OA、ERP、CRM这类的系统&#xff0c;以及大家每天都会刷的头条、抖音类的app&#xff0c;那这些大家所…

element-ui breadcrumb 组件源码分享

今日简单分享 breadcrumb 组件的源码实现&#xff0c;主要从以下三个方面&#xff1a; 1、breadcrumb 组件页面结构 2、breadcrumb 组件属性 3、breadcrumb 组件 slot 一、breadcrumb 组件页面结构 二、breadcrumb 组件属性 2.1 separator 属性&#xff0c;分隔符&#xff…

【洛谷 P8695】[蓝桥杯 2019 国 AC] 轨道炮 题解(映射+模拟+暴力枚举+桶排序)

[蓝桥杯 2019 国 AC] 轨道炮 题目描述 小明在玩一款战争游戏。地图上一共有 N N N 个敌方单位&#xff0c;可以看作 2D 平面上的点。其中第 i i i 个单位在 0 0 0 时刻的位置是 ( X i , Y i ) (X_i, Y_i) (Xi​,Yi​)&#xff0c;方向是 D i D_i Di​ (上下左右之一, 用…

零基础如何自学人工智能?推荐优秀的学习路径及方法

人工智能&#xff08;AI&#xff09;是一个广泛且复杂的领域&#xff0c;自学AI可能是一项艰巨的任务&#xff0c;但只要有兴趣和决心&#xff0c;这绝对是可能的。以下是一个零基础自学人工智能的学习路径&#xff0c;旨在帮助那些只有兴趣&#xff0c;但缺乏背景知识的人。 *…

[图解]DDD领域驱动设计伪创新-通用语言05

0 00:00:01,060 --> 00:00:04,370 甚至有的人把这个当成恩典 1 00:00:08,730 --> 00:00:11,500 他认为这个对技术人员有好处 2 00:00:13,010 --> 00:00:14,790 他掌握了主动权 3 00:00:15,730 --> 00:00:16,501 这样的话 4 00:00:16,501 --> 00:00:18,430 你…

【Android Studio】上位机-安卓系统手机-蓝牙调试助手

【Android Studio】上位机-安卓系统手机-蓝牙调试助手 文章目录 前言AS官网一、手机配置二、移植工程三、配置总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 AS官网 AS官网 一、手机配置 Android Studio 下真机调试 二、移植工程 Anro…

有时候在mac上使用IDEA无法访问系统里的文件,比如字体等。

有时候在mac上使用IDEA无法访问系统里的文件&#xff0c;比如字体等。 这里可以打开磁盘访问权限。

网络抓包专题

网络抓包原理 一. 什么是抓包&#xff1f; 在应用的开发调试中&#xff0c;查看软件实际运行时HTTP/HTTPS通信的请求数据和返回数据&#xff0c;从而分析问题的过程就叫做抓包。 通常我们说的抓包主要是分为两种&#xff1a; 使用 Wireshark 抓取传输层的 TCP/UDP 通信包。使…

ideaSSM 校园兼职招聘平台bootstrap开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 idea 开发 SSM 校园兼职招聘平台是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff…

深度学习理论基础(二)深度神经网络DNN

目录 一、基础知识点Ⅰ 参数部分Ⅱ 模型部分 二、深度神经网络模型搭建1. 准备数据集2. 划分数据集3. 搭建模型4. 训练网络5. 测试网络6. 保存与导入模型 神经网络通过学习大量样本的输入与输出特征之间的关系&#xff0c;以拟合出输入与输出之间的方程&#xff0c;学习完成后&…

ndk ffmpeg

报错&#xff1a; 解决办法&#xff1a; 报错 解决办法&#xff1a;

js猜拳游戏

文章目录 1. 演示效果2. 分析思路3. 代码实现3.1. 方式一3.2. 方式二 1. 演示效果 2. 分析思路 获取玩家的出拳(获取按钮的标签体)获取电脑的出拳(随机数)比较二者的出拳&#xff0c;将比较的结果设置到对应的 span 标签中 3. 代码实现 3.1. 方式一 将点击事件进行动态绑定…

Python网络爬虫(四):b站评论

首先来看一下采集的数据格式: 本文不对数据采集的过程做探讨,直接上代码。首先要在程序入口处bvids列表内替换成自己想要采集的视频bvid号,然后将self.cookies替换成自己的(需要字典格式),代码可以同时爬取多个视频的评论,且爬取的评论较为完整,亲测有效: im…

股权激励和期权激励对比辨析

文章目录 概念定义 收益方式 风险评估 应用和分析 股权激励和期权激励&#xff0c;两者的区别是什么&#xff0c;本文就来梳理对比一下。 概念定义 股权激励&#xff0c;是指上市公司以本公司股票为标的&#xff0c;对其董事、高级管理人员及其他员工进行的长期性激励。取得…