分布式DDL-clickhouse

750 阅读4分钟

分布式DDL背后的原理

分布式DDL的实现依赖于 zookeeper。在zookeeper 之中构造一个队列,队列之中的元素是分布式DDL的内容。在每个分布式DDL任务节点下,还有两个节点,一个active,一个finished。active 存储有哪些服务器未执行完成此分布式DDL,finished节点存储已经执行完此分布式DDL的服务器信息。分布式DDL的执行会分为两个阶段,前一段时间同步之间,如果在指定的时间范围内,此分布式DDL仍然没有执行完成,服务器抛出异常异常,分布式DDL转为后台执行。

任务的同步执行时间为 :distributed_ddl_task_timeout 参数控制

分布式DDL队列

分布式DDL队列 在 zookeeper 之中的存储路径

/clickhouse/task_queue/ddl
      /具体任务
         /active    存储尚未执行完成此任务的节点host
         /finished  存储已经执行完成此任务的节点host

分布式DDL队列的长度

config.xml

<distributed_ddl>
        // 分布式DDL 队列在zookeeper之中的存储路径
        <path>/clickhouse/task_queue/ddl</path>
        // 队列之中的最大的个数
        <max_tasks_in_queue>3</max_tasks_in_queue> 
        // 清理的周期
        <cleanup_delay_period>60</cleanup_delay_period>
        // 每个任务节点的最大的存活时间(已完成的节点)
        <task_max_lifetime>604800</task_max_lifetime>
<distributed_ddl>

分布式DDL队列的清理策略

启动一个清理线程周期性执行清理任务,对已完成的 存活时间超过指定时间的 分布式DDL任务进行清除,或者分布式DDL队列长度超过限制,清除已完成的分布式DDL任务。

<distributed_ddl>
       // 分布式DDL 队列在zookeeper之中的存储路径
       <path>/clickhouse/task_queue/ddl</path>
       // 队列之中的最大的个数
       <max_tasks_in_queue>3</max_tasks_in_queue> 
       // 清理的周期
       <cleanup_delay_period>60</cleanup_delay_period>
       // 每个任务节点的最大的存活时间(已完成的节点)
       <task_max_lifetime>604800</task_max_lifetime>
<distributed_ddl>

分布式DDL队列溢出策略

如果有一个分布式DDL任务卡住了,后续不断有分布式DDL任务过来,队列长度超过限制怎么办

超过限制的队列还是会不断增长,自己的实验测试结果,当队列长度超过限制,执行分布式DDL任务,并不会遇到抛出异常的情况。

分布式DDL的消费

分布式DDL队列的消费机制

每个clickhouse节点后台都会有 一个 消费线程,去消费分布式DDL队列之中的元素,遵循先进先出的规则。如果存在一个分布式DDL任务极度耗时,那么后续的任务只能等待了。当clickhouse执行完成对应的分布式DDL,它会更新分布式DDL任务在zookeeper之中的active fininshed 节点信息。

当分布式DDL的队列之中的任务 超时转换成为后台执行的任务之后,是否还会阻塞现有的任务执行

我的实验结果,还是会阻塞后续的分布式DDL的程序执行的。

#注意 不要使用分布式DDL执行大量耗时的操作,会导致阻塞, 尤其是 optimize table xxx on cluster default final 物化视图的时候,不要使用POPULATE,会出问题的, 同时注意不要执行 alter table xxx on cluster 集群名 ttl dt + xxx 这样的修改ttl的操作。

问题

出现分布式ddl任务超时,是否有指标来进行判断

1: system.errors 表之中 会有TIMEOUT_ERROR错误,但是可能会被其他的超时异常所覆盖。使用 select * from system.query_log where exception_code = 159

分布式DDL出现卡死 影响后续执行 如何解决这个问题?

  • 1:可以手动kill 正在执行的分布式DDL

监控

  • 查询阻塞当前分布式DDL执行的 慢SQL
  • 查看分布式ddl 的堆积任务信息
  • 获得各个节点下 分布式ddl堆积的任务数
  • 查看一段时间内 执行异常的分布式任务信息

注意: system.distributed_ddl_queue 表 之中会存储所有的节点的任务的执行状况,这个是需要注意的,所以就不需要 使用clusterAllReplicas('default', 'system.distributed_ddl_queue')这样的语法了。system.distributed_ddl_queue 表之中的数据不会存储太多的历史数据,clickhouse内部有删除机制。

查询阻塞当前分布式DDL执行的 慢SQL

select 
 *,
(toUnixTimestamp(now()) - toUnixTimestamp(query_create_time)) elapsed, 
from system.distributed_ddl_queue 
where status = 'active' 
order by elapsed desc limit 10

查看分布式ddl 的堆积情况

select
 (toUnixTimestamp(now()) - toUnixTimestamp(query_create_time)) elapsed, // 任务的堆积时间
 *
from 
system.distributed_ddl_queue
where status = 'Inactive'
order by elapsed desc limit 1

获得各个节点下 分布式ddl堆积的任务数

select 
   host,
   max(wait_task_num) as wait_task_num 
from (
select 
  host,
  count(*) as wait_task_num 
from 
system.distributed_ddl_queue
where status = 'Inactive'
) 
group by host

查看一段时间内 执行异常的分布式任务信息

    select 
      host_name,query, cluster, query_start_time, exception_code  
    from system.distributed_ddl_queue
    where 
    status <> 'active'  
    and status <> 'Finished' 
    and status <> 'Inactive'
    and query_start_time >= toDateTime('开始时间')
    and query_start_time <= toDateTime('结束时间')
    order by query_start_time desc