干货 | 性能提升400%,ClickHouse在携程酒店数仓的实践
作者简介
小琴,携程高级数据经理,负责酒店BI、数仓工作,专注于大数据应用领域多年。
一、背景
随着时间推移和业务的快速发展,携程酒店数据累积越来越多。目前流量日数据在3T左右,再加上各种订单、价、量、态等数据更是庞大。现有Hive(Spark引擎)执行速度虽然相对较快,但在国际化发展背景下,一些海外业务由于时差问题,数据需要比国内提前数小时完成,性能提升迫在眉睫。2020年初,我们开始研究ClickHouse在数据仓库领域应用。
本文将从技术方案选型、集成开发环境封装、ClickHouse代码优化技巧、异常问题处理、服务器故障处理五个方面分享ClickHouse实践,希望给关注同样问题的同学有所启发。
二、技术预研与技术方案选型
1)公司内部有无ClickHouse集群使用环境。经过了解知晓,原ClickHouse验证集群正准备下线,无可用环境;
2)办公电脑通过Vmware搭建ClickHouse集群,部分同学基于单机练习ClickHouse语法以及验证各项ClickHouse特性,部分专攻ClickHouse集群搭建及各项配置、集成开发环境的封装等底层功能。
3)2020年3月,Vmware搭建ClickHouse集群基本完成各项验证,同时4台物理服务器(配置:内存-256G,CPU-40core,硬盘-3.5T)到位。为保证对生产平稳过渡(不给生产DB造成额外压力),我们从Hive ODS层同步数据至ClickHouse ODS层,技术方案如下图1(橙色部分是ClickHouse实现部分):
图1
三、集成开发环境封装
1)数据同步工具封装
我们发现消耗在数据同步上的时间太多,是数据计算时间的十几倍。于是开始研究ClickHouse数据导入方式,其中一种如下:
cat filename.orc | clickhouse-client -- query="INSERTINTO some_table FORMAT ORC"
在此基础上通过缓存、批处理等机制封装成新的orc2ck.sh同步工具,使同步速度比原先工具的性能提高500%以上。
2)集成开发工具封装
为了提高开发效率,减少代码冗余,我们封装了ClickHouse代码执行工具ck.sh,执行环境如下图2(橙色部分是应用代码部分,红色框部分是封装工具及参数)。
图2
四、ClickHouse代码优化技巧
1)小表置于join右侧降低内存消耗
2)用in替代join提高执行速度
3)减少数据扫描提高执行速度
通过增加过滤逻辑可以减少数据扫描,达到提高执行速度及降低内存消耗的目的。
五、异常问题处理
Code: 252, e.displayText() = DB::Exception: Too many parts (301) . Merges are processing significantly slower than inserts.
解决这个问题需要先分析Merge过程,如下图所示:
Merge过程是异步的,插入速度过快会导致以上错误,一般建议速度100w/s。
Code: 241, e.displayText() = DB::Exception: Memory limit (for query) exceeded
这种错误是请求内存高于系统分配内存导致,解决这类问题可以从两方面入手:
- 在服务器内存充裕的情况下增加内存配额,一般通过max_memory_usage来实现;
- 在服务器内存不充裕的情况下,建议将超出部分内容分配到系统硬盘上,但会降低执行速度;一般通过max_bytes_before_external_group_by 、max_bytes_before_external_sort参数来实现。
如果以上方法仍然无法解决问题,需要检查代码是否合理,从代码角度去优化(参考代码优化技巧部分)。
六、服务器故障处理
故障背景:故障演练导致ClickHouse服务器被强行重启,ClickHouse服务无法正常启动。
解决办法:根据ClickHouse错误日志 (clickhouse-server.err.log) 定位问题,发现ClickHouse服务启动时无法加载表的元数据,处理方式有两种:
1)删除或移走该表对应数据文件(本次故障使用了该方式,下图为错误日志)。
2)重建该表元数据(此方式更为合理)。
七、小结
截止2020年上半年,携程酒店订单主题以及P1体系报表已经全部实现完毕,大部分性能提升在200%以上,整体性能提升平均在400%左右,基本解决大部分应用场景的问题,后期我们将整合更多主题入仓,充分发挥ClickHouse的性能优势,进一步提升效率。此外,我们也在研究Flink+ClickHouse技术,推进实时数仓建设。
- TensorFlow强化学习入门(2)——基于策略的Agents
- 用ABAP 生成二维码 QR Code
- CDS view注解解析 - @Environment.systemField
- Document flow API in SAP CRM and C4C
- Python基础知识4:文件操作
- Python基础知识6:格式化字符、颜色
- 给自定义控件(Web Control)添加事件的几种方法。前两种方法可以不实现IPostBackEventHandler
- 【开源】QuickPager ASP.NET2.0分页控件 v2.0.0.2版本。
- 【开源】我的分页控件正式命名为QuickPager ASP.NET2.0分页控件
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——分页控件的源码 (二)
- 高级时钟约束
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——分页控件的源码(一) 主体
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——支持多种数据库。让分页更加简单。
- IO约束(下)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 测试开发基础 mvn test | 利用 Maven Surefire Plugin 做测试用例基础执行管理
- 腾讯云Elasticsearch集群规划及性能优化实践
- 【赵渝强老师】在MongoDB中使用MapReduce方式计算聚合
- 2020-09-13:判断一个正整数是a的b次方,a和b是整数,并且大于等于2,如何求解?
- ASP.NET Core 性能优化最佳实践
- 如何在Vue中使用云开发的云函数,实现邮件发送
- 乐观锁与悲观锁
- 为什么配置文件加密了数据库配置信息,Spring Boot仍能成功连接数据库
- SpringBoot开发微信公众号
- 猿实战10——动态表单之实现类目属性绑定
- 猿实战11——类目属性绑定之el-tree的使用
- 猿实战12——类目属性之动态绑定
- 一个maskrcnn的目标检测和实例分割的小例子
- Nginx系列:Nginx自带后端健康检查
- 消息队列之推还是拉,RocketMQ 和 Kafka是如何做的?