惊人发现:clickhouse的cpu暴增之谜

news2024/11/15 6:49:07

点/击/蓝/字  关/注/我/们

一、背景

        前段时间,公司的生产环境的clickhouse的cpu突然持续高压,持续时间大约5个小时,特写此文记录,深挖clickhouse的原理,持续学习。

        题主所在的公司的一些历史数据会保存到clickhouse中,现在有业务需要对clickhouse里面的数据进行删除。因为这是一个批量的操作,暂且假设需要删除一批股票的全部的历史k线数据,k线包括分k,日k,周k,月k,季k,年k。

二、经过

        好吧,简单还原一下事情的经过吧,在某天题主18点30发完版后得意洋洋收工下班吃饭中,突然接到运维大佬发信息说clickhouse的cpu打爆了。不可能,绝对不可能,我的程序不可能有~问~题。二话不说,坐上火箭弹射回家远程电脑。一顿操作猛如虎,一看cpu还是100%。各种指标分析:内存,流量,吞吐量。由于当时时段还是业务低峰期,实时吞吐,流量是比较少的,因此这些因素可以排除掉了。脑瓜子嗡嗡的,在阿里云的clickhouse管理后台将正在执行的任务杀掉了,代码回滚,服务重启,cpu还是100%。然后重点怀疑一个删除操作的任务,这个任务是一个逻辑比较简单的,任务流程如下:

第二步:服务A将需要删除的数据推送到kafka中

第三步:服务B消费对应topic中的数据,对clickhouse中的数据进行删除。

        因此上文说的,服务B的代码回滚和重启后,clickhouse的cpu还是打满,不难看出是由于kafka中的消息没消费完,服务B还在不断执行消息kafka的数据,删除clickhouse中的数据。事实也是如此,登录上kowl工具,发现kafka中对应topic一共需要删除将近1w个股票的数据,现在只是服务B只是消费了大概2000个,还剩下8000个股票的历史数据没清除。

tips:

每个股票需要删除的k线,包括分k,日k,周k,月k,季k,年k。因此这个删除逻辑是比较重的,至少对应一个股票来说,删除的数据是比较多的,涉及的范围比较广。

        既然定位到了问题的所在,我们就可以想对应的解决方法,这个任务一般是在周末业务低峰的时候执行的,这次是人为手动执行了一次。因此临时想的解决方法是注释服务B消费kakfa的代码,然后重新发布到生产环境。但是在服务B改造发布完成后,clickhouse的cpu还是高居不下。

三、分析

经过以上步骤,基本可以定位到触发问题的地方。但是有以下几个问题需要思考探讨一下

  • 为什么相应的代码逻辑注释了,clickhouse的cpu还高居不下?

  • clickhouse是有什么隐含的比较耗cpu的操作嘛

tips:

之前题主也知道clickhouse对删除操作支持的不是很好,因此对clickhouse的删除操作都是放在周末,避开业务高峰期的。但是没深入探讨过底层的原理。因此刚才趁着此次机会,学习探讨一下。

        题主观察到阿里云上面的cpu暴增,但是内存使用率,磁盘使用率虽有徒增,并没达到预警值,属于预期的情况。但是运行Merge个数和运行Mutation个数这两个指标一下子吸引了我,这两个指标明显和cpu爆增的时机趋势一致。因此重点关注这两个指标:

  • 运行的Merge个数是指正在运行的Merge的线程数量

  • 运行Mutation个数是指正在运行的mutation的线程的数量

merge和mutation使用的是同一个线程池,默认是16个线程。

既然定位到了clickhouse出问题的地方了,那么我们可以一起来看看merge和mutation操作到底是什么。

3.1 mutation操作

mutation基本概念

        clickhouse将update和delete的操作统称为mutation操作,clickhouse虽然提供了更新和删除的操作,但是mutation的代价比较大,因为ClickHouse使用了LSM的底层存储结构,文件是不可修改、不可变的,新操作只会写到新文件中。因此哪怕只更新一条记录,也需要重新生成一个新的数据片段,会将该记录修改后的内容以及该记录所在的分区中其他未修改的所有记录写入到新的数据片段。因此mutation操作最好是批量操作,涉及的分区数尽量少,这样性能会比较高。

mutation核心源码解读

        ClickHouse的方言把Delete和Update操作也加入到了Alter Table的范畴中,它并不支持裸的Delete或者Update操作。当用户执行一个如上的Mutation操作获得返回时,ClickHouse内核其实只做了两件事情:

1.检查Mutation操作是否合法;

2.保存Mutation命令到存储文件中,唤醒一个异步处理merge和mutation的工作线程;

  1. 检查mutation操作是否合法:主体逻辑在MutationsInterpreter::validate函数,主要是不能修改分区键和order by的字段。

  2. 保存Mutation命令到存储文件中,唤醒一个异步处理merge和mutation的工作线程:主体逻辑在StorageMergeTree::mutate函数中。

核心流程图如下:

样例

对于第一点,举个例子,假如你的创表语句如下:

CREATE TABLE user (  

`user_id` Int64 COMMENT '用户id',

`user_type` Int 32 COMMENT '用户类型',

 `create_time` DateTime COMMENT '创建时间',      

`update_time` DateTime COMMENT '更新时间',     

 )ENGINE = ReplacingMergeTreePARTITION BY toStartOfInterval(create_time, toIntervalYear(1))ORDER BY (user_id, user_type)SETTINGS index_granularity = 8192;

        那么因为用到了create_time作为分区字段,用了user_id和user_type作为排序字段,因此create_time,user_id和user_type这三个字段,在提交sql语句的时候clickhouse会检查sql的合法性,不能对这三个字段进行更新,删除,否则会报错。

mutation过程

        系统每次都只会订正一个Data Part,但是会聚合多个mutation任务批量完成,这点实现非常的棒。因为在用户真实业务场景中一次数据订正逻辑中可能会包含多个Mutation命令,把这多个mutation操作聚合到一起订正效率上就非常高。系统每次选择一个排序键最小的并且需要订正Data Part进行操作,本意上就是把数据从前往后进行依次订正。

核心源码如下:

核心流程如下:

3.2 merge操作

        StorageMergeTree::merge函数是MergeTree异步Merge的核心逻辑,Data Part Merge的工作除了通过后台工作线程自动完成,用户还可以通过Optimize命令来手动触发。自动触发的场景中,系统会根据后台空闲线程的数据来启发式地决定本次Merge最大可处理的数据量大小,max_bytes_to_merge_at_min_space_in_pool: 决定当空闲线程数最大时可处理的数据量上限(默认150GB)max_bytes_to_merge_at_max_space_in_pool: 决定只剩下一个空闲线程时可处理的数据量上限(默认1MB)当用户的写入量非常大的时候,应该适当调整工作线程池的大小和这两个参数。当用户手动触发merge时,系统则是根据disk剩余容量来决定可处理的最大数据量。

        Merge的处理逻辑,首先是通过MergeTreeDataMergerMutator::selectPartsToMerge函数筛选出本次merge要合并的Data Parts,这个筛选过程需要准守三个原则:

  1. 跨数据分区的Data Part之间不能合并;

  2. 合并的Data Parts之间必须是相邻(在上图的有序组织关系中相邻),只能在排序链表中按段合并,不能跳跃;

  3. 合并的Data Parts之间的mutation状态必须是一致的,如果Data Part A 后续还需要完成mutation-23而Data Part B后续不需要完成mutation-23(数据全部是在mutation命令之后写入或者已经完成mutation-23),则A和B不能进行合并;

        所以我们上面的Data Parts组织关系逻辑示意图中,相同颜色的Data Parts是可以合并的。虽然图中三个不同颜色的Data Parts序列都是可以合并的,但是合并工作线程每次只会挑选其中某个序列的一小段进行合并(系统会限定每次合并的Data Parts的数据量)。对于如何从这些序列中挑选出最佳的一段区间,ClickHouse抽象出了IMergeSelector类来实现不同的逻辑。当前主要有两种不同的merge策略:TTL数据淘汰策略和常规策略。

  1. TTL数据淘汰策略:TTL数据淘汰策略启用的条件比较苛刻,只有当某个Data Part中存在数据生命周期超时需要淘汰,并且距离上次使用TTL策略达到一定时间间隔(默认1小时)。TTL策略也非常简单,首先挑选出TTL超时最严重Data Part,把这个Data Part所在的数据分区作为要进行数据合并的分区,最后会把这个TTL超时最严重的Data Part前后连续的所有存在TTL过期的Data Part都纳入到merge的范围中。这个策略简单直接,每次保证优先合并掉最老的存在过期数据的Data Part。

  2. 常规策略:这里的选举策略就比较复杂,基本逻辑是枚举每个可能合并的Data Parts区间,通过启发式规则判断是否满足合并条件,再有启发式规则进行算分,选取分数最好的区间。启发式判断是否满足合并条件的算法在SimpleMergeSelector.cpp::allow函数中,其中的主要思想分为以下几点:系统默认对合并的区间有一个Data Parts数量的限制要求(每5个Data Parts才能合并);如果当前数据分区中的Data Parts出现了膨胀,则适量放宽合并数量限制要求(最低可以两两merge);如果参与合并的Data Parts中有很久之前写入的Data Part,也适量放宽合并数量限制要求,放宽的程度还取决于要合并的数据量。第一条规则是为了提升写入性能,避免在高速写入时两两merge这种低效的合并方式。最后一条规则则是为了保证随着数据分区中的Data Part老化,老龄化的数据分区内数据全部合并到一个Data Part。中间的规则更多是一种保护手段,防止因为写入和频繁mutation的极端情况下,Data Parts出现膨胀。启发式算法的策略则是优先选择IO开销最小的Data Parts区间完成合并,尽快合并掉小数据量的Data Parts是对在线查询最有利的方式,数据量很大的Data Parts已经有了很较好的数据压缩和索引效率,合并操作对查询带来的性价比较低。

四、归纳总结

        经过以上分析,可知clickhouse对于delete和update的操作支持得不是很好,因此对于需要进行频繁或者大量删除或者更新的操作,在数据库选型的时候就需要兼顾考虑,如果实在是需要进行数据删除或更新的,务必在业务低峰期进行,这也是无奈折中之举。

        好了,由于篇幅有限,这一期的分享就到这里了,如果大家有技术相关的问题,可以点个关注一起交流探讨。

重点~重点~,听说题主开通了公众号:有理唔理,可以关注一下。

参考文章:

https://www.cnblogs.com/ya-qiang/p/13680283.html

https://cloud.tencent.com/developer/article/1911598

https://developer.aliyun.com/article/762090

https://blog.csdn.net/ClickHouseDB/article/details/133657544

https://blanklin030.github.io/2022/02/03/clickhouse-crud/

https://aop.pub/artical/database/clickhouse/mutation-detail/

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

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

相关文章

基于php的公司员工管理系统—计算机毕业设计源码25190

摘 要 公司公司员工管理系统除了具有共享系统的全部功能以外,能通过对数据的分析对决策做出解释是其主要的新特点。其体系结构,将由专用的服务器/客户方式向广域网发展,使更多的系统间能够互相交流数据,带动整个行业、领域知识和效…

如何解决前端跨域问题:从CORS到JSONP

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介如何解决前端跨域问题:从CORS到JSONP1. 引言2. 什么是跨域问题?2.1 同源策略(Same-Origin Policy)2.2 跨域请求的场景 3. 解决跨域问题的常见方法3.1 使用CORS(Cross-Orig…

实在智能联合案例入选中国信通院2024年度高质量数字化转型案例集

为推动数字化转型相关产业发展,培育数据要素市场,为数字化双方提供行业实践标杆参考,中国信通院铸基计划于2024年4月初启动高质量数字化转型典型案例征集工作,旨在遴选一批具有产业引领与推广应用效应的企业数字化转型典型案例。实…

【MySQL】Explain执行计划(十七)

🚗MySQL学习十七站~ 🚩本文已收录至专栏:MySQL通关路 ❤️每章节附章节思维导图,文末附全文思维导图,感谢各位点赞收藏支持~ ⭐学习汇总贴,超详细思维导图:【MySQL】学习汇总(完整思维导图) 一.…

[python]面向对象示例:学生管理系统

python面向对象 python基础知识整理 主要界面 建议跟着框架自行完成功能需求,最下面有完整带注释版本,学生信息会存到当前目录下data.txt文本中,没有则会自行创建 涉及到的知识点 面向对象列表, 字典for, if, input…文件操作 需求分析 开始 -> 循环调用主程序 ->不…

盲盒小程序开发,探索市场发展优势

随着潮玩市场的火热,盲盒已经成为了一种集娱乐、社交、消费为一体的模式,越来越多的消费者被盲盒所吸引,盲盒市场也迎来了巨大的发展空间,带来了各种商业机遇,同时为创业者提供新的创业渠道。本文将探讨盲盒小程序的开…

deepin-wine8-stable为某个windows应用设置环境变量

1 环境说明 deepin v23wine 8.16 2 操作步骤 2.1 在终端指定应用打开注册表编辑 WINEPREFIX~/.deepinwine/com.allroundautomations/ deepin-wine8-stable regeditWINEPREFIX:windows应用在wine容器中的路径,一般为~/.deepinwine/你的应用名称包regedit:注册表编…

类型组TYPE-POOL

文章目录 创建类型组使用类型组运行结果 创建类型组 使用类型组 *&---------------------------------------------------------------------* *& Report Z_TEST_TYPEPOOL *&---------------------------------------------------------------------* *& *&…

ClimODE——使用神经网络ODE 进行天气预报

概述 论文地址:https://arxiv.org/abs/2404.10024 源码地址:https://github.com/Aalto-QuML/ClimODE.git 这项研究提出了用于天气预报的神经 ODE 系统 ClimODE,该系统的设计特点是通过局部卷积运算获取局部依赖关系,通过全局关注…

Pycharm虚拟环境中使用pip命令报错ModuleNotFoundError解决办法

Pycharm虚拟环境中输入pip 相关命令时报错ModuleNotFoundError,记录一下。 软件版本: windows:win11 Python:3.11.4 PyCharm:转业版 2024.1.3 报错如下: 在虚拟环境中输入pip 相关命令时报错"ModuleNotFoundError: No module named pip._internal…

基于yolov8的绝缘子缺陷检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的绝缘子缺陷检测系统是一种利用先进深度学习技术的高效解决方案,旨在提升电力行业中输电线路的维护和监控水平。YOLOv8作为YOLO系列算法的最新版本,具备更高的检测速度和精度,特别适用于实时物体检测任务。 该系统…

【Spring Boot-IDEA创建spring boot项目方法】

1. 使用Spring Initializr 的 Web页面创建项目 2. 使用 IDEA 直接创建项目,其中有两种不同的搭建路径 3. 使用 IDEA 创建Maven项目并改造为springBoot 最常使用的两种方法其实就是一种,这里介绍在ieda中如何搭建 SpringBoot项目。 1.new Project--> 2…

kafka快速上手

一、kafka介绍 Kafka 是一个分布式流媒体平台,类似于消息队列或企业消息传递系统。 kafka官网:http://kafka.apach e.org/ 二、kafka入门 生产者发送消息,多个消费者只能有一个消费者接收到消息生产者发送消息,多个消费者都可以接收到消息 …

HarmonyOS开发实战( Beta5版)多线程能力场景化示例最佳实践

在介绍Worker和TaskPool的详细使用方法前,我们先简单介绍并发模型的相关概念,以便于大家的理解。 并发模型概述 并发的意思是多个任务同时执行。并发模型分为两大类:基于内存共享的并发模型和基于消息传递的并发模型。 在基于内存共享的并…

手撕Python之序列类型

1.列表---list 索引的使用 当我们有一个数据的时候,我们怎么将这个数据存储到程序呢? 我们定义一个变量,将数据存储在变量中 那么如果有100个数据呢?要定义100个变量吗? 我们是可以用列表这个东西进行多个数据的存…

单元测试 Mock不Mock?

文章目录 前言单元测试没必要?Mock不Mock?什么是Mock?Mock的意义何在? 如何Mock?应该Mock什么?Mock 编写示例 总结 前言 前段时间,我们团队就单元测试是否采用 Mock 进行了一番交流,各有各的说法。本文就单元测试 Mock不Mock…

11 Java 方法引用、异常处理、Java接口之函数式编程(接口知识补充Function<T,R>、BiFunction<T, U, R>和自定义泛型接口)

文章目录 前言一、Java接口之函数式编程 --- 接口知识补充1 Function<T,R>泛型接口2 BiFunction<T, U, R>泛型接口3 自定义泛型函数式编程接口4 使用lambda表达式、方法引用进行函数式编程 二、方法引用1 方法引用初体验&#xff08;以Array.sort()方法为例&#x…

当了中层才发现:领导根本不在意,你干了多少活

在职场的棋盘上&#xff0c;每个人都是一枚棋子&#xff0c;而中层领导则像是那些走在前线的骑士——既要冲锋陷阵&#xff0c;又要运筹帷幄。但你有没有想过&#xff0c;领导真的在意你加班到深夜&#xff0c;或是周末还在回复邮件吗&#xff1f; 当你从基层一步步爬到中层&a…

Unity(2022.3.41LTS) - UI详细介绍-Slider(滑动条)

目录 零.简介 一、基本功能与用途 二、组件介绍 零.简介 在 Unity 中&#xff0c;Slider&#xff08;滑动条&#xff09;是一个可以滑动的 UI 组件. 一、基本功能与用途 数值调节&#xff1a;主要功能是让用户在一个特定的数值范围内进行选择。例如&#xff0c;可以用于调…