分布式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