当前位置: 首页 > news >正文

ClickHouse 数据库中的 “超时”

一、超时类型

关于Clickhouse数据库超时问题,需要注意三种不同的超时设置:

1.1 distributed_ddl_task_timeout超时问题:

  • 这是分布式DDL查询(带有 on cluster )的执行等待时间,默认值为180秒。
  • 可以通过在DMS上执行命令来设置全局参数:set global on cluster ck_cluster distributed_ddl_task_timeout = 1800;
  • 分布式DDL基于clickhouse-keeper构建任务队列异步执行,执行等待超时并不代表查询失败,只是表示之前发送的任务还在排队等待执行。可以在system.distrubuted_ddl_queue表中查到。
  • 这个超时的出现,一般是有什么异常DDL操作卡住了,导致后面的所有DDL语句都是一种超时状态。解决这个卡住的DDL语句就可以啦。

1.2 max_execution_time超时问题:

  • 这是一般查询的执行超时时间,默认值为3600秒。
  • 用户可以进行查询级别更改,例如:select * from system.numbers settings max_execution_time = 3600;
  • 可以在DMS上执行以下命令来设置全局参数:set global on cluster default max_execution_time = 3600;
  • 该参数在chproxy 代理上也可以设置(用到9090端口)

1.3 socket_timeout超时问题:

  • 这是HTTP协议在监听socket返回结果时的等待时间
  • 该参数不是Clickhouse系统内的参数,而是属于jdbc在HTTP协议上的参数。它会影响到前面的max_execution_time参数设置的效果,因为它决定了客户端在等待结果返回时间上的时间限制
  • 用户在调整 max_execution_time 参数的时候也需要配套调整 socket_timeout 参数,例如:jdbc:clickhouse://127.0.0.1:9090/ceelake?socket_timeout=3600000

所以这也是为什么许多应用超过30s就报超时的原因

二、insert数据超时优化策略

⚠️优化策略需要在确保插入语句没有问题之后才需要考虑,这里需要提前注意下不是因为 select 超时而导致insert 超时

2.1 max_insert_threads

默认值:0

增加并发插入线程----对于大数据量的插入操作,尤其是宽表(列非常多),默认的自动设置可能无法最大化利用系统的资源,导致插入速度较慢。

如果你的机器有多个CPU核心,可以考虑手动增加max_insert_threads的值,以提高插入的并发度。你可以将其设置为与CPU核心数相同,或者略高一些。例如:

SETTINGS max_insert_threads = 16; -- 根据你服务器的核心数调整

这可以增加插入操作的并行度,尤其是在大数据量的插入时,这样每个线程可以处理不同的数据分块,提高整体插入吞吐量。

实例:700多列 3000万数据的insert (大宽表)

2.2 insert_quorum

如果你的ClickHouse集群是分布式的,可以调整insert_quorum来控制写入的节点数量。减少insert_quorum可以减少等待节点确认的时间,从而提升插入速度。比如:

SETTINGS insert_quorum = 2; -- 根据集群规模调整

这个设置会使得插入操作在部分节点完成后就返回成功,从而加速插入过程。

2.3 max_memory_usage

插入大数据量时,内存消耗也很高。你可以通过调整max_memory_usage来限制每个插入操作的内存使用,避免因内存不足导致的瓶颈:

SETTINGS max_memory_usage = 10000000000; -- 设置为合适的内存限制

2.4 批量插入

如果一次性插入的数据量过大,尝试将数据分批插入。ClickHouse在处理大批量数据时,分批插入可以减少资源压力。例如,每次插入100万条数据,而不是一次插入500万条数据。

2.5 适当调整max_insert_block_size

默认值:1048449

可以调整max_insert_block_size来限制每个插入块的大小。虽然默认设置一般适合,但在某些情况下,较小的块大小可能会提高插入性能:

SETTINGS max_insert_block_size = 1048576; -- 例如:1MB大小

插入表时要形成的块的大小(以行数表示)。此设置仅适用于服务器形成块的情况。例如,对于通过HTTP接口的INSERT,服务器解析数据格式并形成指定大小的块。但是,当使用clickhouse客户端时,客户端会自己解析数据,服务器上的“max_insert_block_size”设置不会影响插入块的大小。使用INSERT SELECT时,该设置也没有目的,因为数据是使用SELECT后形成的相同块插入的。

默认值略大于max_block_size。这样做的原因是,某些表引擎(*MergeTree)在磁盘上为每个插入的块形成一个数据部分,这是一个相当大的实体。同样,*MergeTree表在插入过程中对数据进行排序,足够大的块大小允许在RAM中对更多数据进行排序。

2.6 并行批量插入

可以利用并行化工具(如clickhouse-client的并行插入功能,或者通过编写多线程的脚本)来进一步提高插入性能。通过并行插入多个小批次,可以提高吞吐量。

三、select 数据超时优化策略

3.0 语句优化

除了数据本身的问题,例如是否有字段大量使用NLLAble(影响性能), 具体查询语句具体优化;

3.1 单节点join

clickhouse单机join默认采用的是hash join算法,也就是说,先将右表全量读取到内存,然后构建hashmap,然后从左表分批读取数据,到hashmap中去匹配,如果命中,那么就作为join之后的结果输出。

因为右表是要全量加载到内存的,这就要求要足够小。但是实际上右表大于TB级是很常见的事情,这时候就很容易出现OOM。

为了解决这个问题,有一种解决思路是将右表构建成大宽表,将维度拍平,使行尽量少,这样右表只需要加载少量的列进内存,从而缓解这一情况。

一个典型的落地实施案例就是clickhouse_sinker存储Prometheus指标的方案。它将指标分拆成两张表,一张metric表,用来存储时序指标值,一张metric_series表,用来存储具体的指标。两张表通过series_id进行关联。

在metric表中,每个时间点的每个值,都对应着一个series_id,我们通过这个series_id,反查metric_series表,就可以找到这个series_id对应的指标以及label。

3.2 分布式join

clickhouse的分布式join有两种玩法,一种是带global,一种是不带global。

普通join

汇总节点将左表替换为本地表

将左表的本地表分发到每个节点

在每个节点执行本地join

将结果汇总回汇总节点

这种做法有一个非常严重的问题。在第三步,每个节点执行分布式join的时候,如果右表也是分布式表,那么集群中的每个节点都要去执行分布式查询,那也就是说,如果集群有N个节点,右表查询就会在集群中执行N*N次,这就是查询放大现象。(对这个感兴趣的可以看看文档。。。。 ,具体讲述了查询放大的现象)

正是因为这种问题的存在,在比较新的clickhouse版本中,分布式join如果不加global,已经会从语法层面报错了。这说明官方已经禁止了这种写法的存在。

global join

汇总节点将右表改成子查询,先在汇总节点将右表的数据结果集查询出来

将右表的结果集广播给各个节点,与各个节点的左表本地表进行join查询

各个节点将查询结果发送给汇总节点

由于右表的结果已经在汇总节点计算出来了,那么也就不需要在其他节点重复计算,从而避免了读放大的问题。

但global join 的问题是它需要将整个子查询的结果集发送给各个节点,如果右表的结果集特别大,那么整个过程耗费的网络带宽也将是非常恐怖的。

正确姿势

  • 大表在左,小表在右
  • 数据预分布,实现colocate join。也就是将涉及到join的表按照相同的join key分片,使需要join的数据尽量都能在本地完成。也就是前文提到的shardingkey的用处。
  • 改大宽表

并发查询

并发查询也是clickhouse的一个比较薄弱的领域。

因为对于clickhouse的查询来说,一个大的查询SQL往往会把整个服务器的资源吃满,如果并发查询比较多的话,那么不可避免地造成资源竞争,最终的结果就是谁也快不了,甚至还会出现OOM的情况。

官方默认的最大并发数是100, 这个100是每个节点的最大并发数,而不是整个集群的。它包含了查询的并发和写入的并发。

我们很容易碰到这样的场景:在界面上点击一个查询耗时比较久,等得不耐烦,就多点了几下。事实上,clickhouse并不会因为你在界面上多点了一下鼠标,就取消之前的SQL运行,反而会产生多个SQL在并发执行,如果这种耗时比较久的SQL越积CPU打满,造成的结果就是恶性循环,其他SQL也会越来越慢,最终导致并发的SQL超过了设置的最大并发数,再也无法执行任何查询语句,甚至写入都会受到影响。

我们一般建议将最大查询并发数,设置为最大并发数的90%,预留出10%的并发数量供数据写入使用。这样即使查询并发数打满了,仍然不会影响到数据的写入。

我们可以通过配置来实现这一策略:

<clickhouse><max_concurrent_queries>100</max_concurrent_queries><max_concurrent_select_queries>90</max_concurrent_select_queries>
</clickhouse>

相关文章:

  • 游戏引擎学习第227天
  • Java微服务线程隔离技术对比:线程池隔离 vs 信号量隔离
  • union all 关联查询
  • OpenAI发布GPT-4.1:开发者专属模型的深度解析 [特殊字符]
  • 无服务器架构(Serverless)在Web开发与云原生中的应用研究
  • 外接键盘与笔记本命令键键位不同解决方案(MacOS)
  • 蓝桥杯 1.路径之谜
  • 利用quartus的DDS函数信号发生器设计
  • jdk 安装
  • 一、小白如何用Pygame制作一款跑酷类游戏(成品展示+添加背景图和道路移动效果)
  • 嵌入式面试题:C 语言基础重点总结
  • Flutter 图标和按钮组件
  • 基于RV1126开发板下的WIFI的AP模式配置
  • 【vue3】vue3+express实现图片/pdf等资源文件的下载
  • 埃文科技助力山西公共数据运营新发展
  • 关于 人工智能(AI)发展简史 的详细梳理,按时间阶段划分,涵盖关键里程碑、技术突破、重要人物及挑战
  • QuickAPI 全生命周期管理:从开发到退役的闭环实践​
  • 告别繁琐,拥抱简洁:初识 Pytest 与环境搭建 (Pytest系列之一)
  • vue3 elementPlus中el-tree-select封装和自定义模糊搜索
  • 大数据学习(108)-子查询
  • 北京顺义:做好潮白河大桥事故善后处置,举一反三排查风险
  • 展讯:漫游者秦龙和巫鸿的三本书
  • 生态环境部谈拿手持式仪器到海边测辐射:不能测量水中放射性核素含量
  • 融入长三角一体化发展,苏南名城镇江的优势和机遇何在
  • 观察|动力电池步入“多核时代”,宁德时代新技术密集开箱有何启示
  • 外卖江湖战火重燃,骑手、商家、消费者在“摇摆”什么?