復(fù)制的注意點(diǎn)
目前只有合并樹(shù)系列的表 具有復(fù)制的功能。
復(fù)制的實(shí)現(xiàn)原理
clickhouse的復(fù)制 是基于 zookeeper來(lái)實(shí)現(xiàn)的。zookeeper 在clickhouse 復(fù)制的實(shí)現(xiàn)之中 扮演了 元數(shù)據(jù)存儲(chǔ)、日志框架、分布式協(xié)調(diào)服務(wù) 三重角色。
每個(gè)clickhouse 節(jié)點(diǎn)都會(huì)監(jiān)視 zookeeper /clickhouse/tables/分片號(hào)/數(shù)據(jù)庫(kù)名/表名/log 節(jié)點(diǎn)下的信息。當(dāng)向一個(gè)節(jié)點(diǎn)的可復(fù)制表寫(xiě)入數(shù)據(jù)時(shí),節(jié)點(diǎn)會(huì)向 /clickhouse/tables/分片號(hào)/數(shù)據(jù)庫(kù)名/表名/log 目錄下添加任務(wù)節(jié)點(diǎn)。另一個(gè)副本節(jié)點(diǎn)監(jiān)控到變化,執(zhí)行fetch操作(在zookeeper之中的數(shù)據(jù)變化,這里忽略),從對(duì)應(yīng)的節(jié)點(diǎn)拉取數(shù)據(jù)。
fetch
fetch 的定義
復(fù)制表的一個(gè)副本從另一個(gè)副本 通過(guò)http協(xié)議 克隆數(shù)據(jù),這個(gè)過(guò)程被稱(chēng)為fetch。
fetch 的實(shí)現(xiàn)
每個(gè)clickhouse 節(jié)點(diǎn) 專(zhuān)門(mén)維護(hù)一個(gè)線(xiàn)程池 用以執(zhí)行fetch操作。fetch的實(shí)質(zhì) 是通過(guò)http協(xié)議下載數(shù)據(jù)。
決定 fetch 線(xiàn)程池大小的參數(shù)
background_fetches_pool_size
clickhouse 節(jié)點(diǎn) 暴露的用于執(zhí)行fetch的端口是哪個(gè)
config.xml 文件之中的配置參數(shù)
<interserver_http_port>9009</interserver_http_port>
通過(guò)http fetch的時(shí)候,接收方的超時(shí)時(shí)間
replicated_fetches_http_receive_timeout 參數(shù)決定,是合并樹(shù)表級(jí)別的配置參數(shù)。
通過(guò)http fetch的時(shí)候,發(fā)送方的超時(shí)時(shí)間
replicated_fetches_http_send_timeout
每個(gè)節(jié)點(diǎn)的fetch 并發(fā)度限制
replicated_max_parallel_fetches_for_host
限制 fetch 收 發(fā) 消耗的網(wǎng)絡(luò)帶寬大小
max_replicated_sends_network_bandwidth_for_server: 服務(wù)器級(jí)別的設(shè)置(限制所有表的總量)
max_replicated_fetches_network_bandwidth_for_server:服務(wù)器級(jí)別的設(shè)置(限制所有表的總量)
max_replicated_fetches_network_bandwidth : 表級(jí)別的設(shè)置
max_replicated_sends_network_bandwidth : 表級(jí)別的設(shè)置
fetch 操作會(huì)占據(jù)的資源
帶寬 cpu 內(nèi)存。 主要需要注意的是帶寬。
replica 在 zookeeper 的清理機(jī)制
- max_replicated_logs_to_keep:當(dāng)一個(gè)副本節(jié)點(diǎn)掛掉的時(shí)候,zookeeper的log隊(duì)列最多保持多少個(gè)任務(wù)節(jié)點(diǎn)。
- min_replicated_logs_to_keep:在log隊(duì)列之中最少保持多少個(gè)任務(wù)節(jié)點(diǎn)。即使任務(wù)節(jié)點(diǎn)已經(jīng)被執(zhí)行,但是還是需要保持配置數(shù)量的節(jié)點(diǎn)數(shù)。
- cleanup_delay_period:合并樹(shù)級(jí)別的配置參數(shù),決定了后臺(tái)執(zhí)行復(fù)制表隊(duì)列的清理周期。
如果發(fā)現(xiàn)隊(duì)列之中的節(jié)點(diǎn)數(shù)過(guò)多的話(huà),可以稍稍調(diào)小一下參數(shù),默認(rèn)的取值為30s。
復(fù)制表下的合并
1:execute_merges_on_single_replica_time_threshold 參數(shù)決定副本開(kāi)始合并的時(shí)間。假設(shè)有兩個(gè)副本,一個(gè)副本開(kāi)始合并,那么另一個(gè)副本是需要fetch 合并后的數(shù)據(jù)呢,還是自己也執(zhí)行合并。所以就取決于參數(shù) execute_merges_on_single_replica_time_threshold的值。取值為0,表示每個(gè)副本自己觸發(fā)合并。當(dāng)取值為某一個(gè)整數(shù)時(shí),副本A開(kāi)始執(zhí)行合并,副本B等待一段時(shí)間,如果副本A的合并執(zhí)行完成,那么副本B通過(guò)fetch獲取數(shù)據(jù),否則副本B自己本地開(kāi)始執(zhí)行合并。
2:當(dāng)log entry的創(chuàng)建時(shí)間 超過(guò) prefer_fetch_merged_part_time_threshold,
并且執(zhí)行合并的數(shù)據(jù)量的大小 超過(guò) prefer_fetch_merged_part_size_threshold,
那么執(zhí)行fetch 來(lái)加速合并。
可復(fù)制表的寫(xiě)入
復(fù)制的相關(guān)配置參數(shù)
復(fù)制表下的合并參數(shù)
- execute_merges_on_single_replica_time_threshold:默認(rèn)的取值為0,表示各個(gè)節(jié)點(diǎn)在自己本地進(jìn)行合并。含義是,使某個(gè)副本首先開(kāi)始合并,如果在指定的時(shí)間內(nèi)完成合并,通過(guò)fetch來(lái)獲得合并后的數(shù)據(jù)。作用:用來(lái)緩解合并對(duì)cpu造成的壓力
- prefer_fetch_merged_part_time_threshold:當(dāng)log entry的創(chuàng)建時(shí)間 超過(guò) prefer_fetch_merged_part_time_threshold,并且執(zhí)行合并的數(shù)據(jù)量的大小 超過(guò) prefer_fetch_merged_part_size_threshold,那么執(zhí)行fetch 來(lái)加速合并
復(fù)制表下的寫(xiě)入?yún)?shù)
- insert_quorum
- insert_quorum_timeout
- insert_quorum_parallel
復(fù)制表下的查詢(xún)參數(shù)
- max_replica_delay_for_distributed_queries:當(dāng)執(zhí)行查詢(xún)的時(shí)候,會(huì)選擇某個(gè)副本進(jìn)行數(shù)據(jù)查詢(xún),這是一個(gè)選擇的標(biāo)志,落后多久的副本仍然可以作為查詢(xún)的數(shù)據(jù)來(lái)源。
- fallback_to_stale_replicas_for_distributed_queries:當(dāng)更新的副本不可用的時(shí)候,強(qiáng)制使用過(guò)時(shí)的副本進(jìn)行查詢(xún),保證查詢(xún)可行
- select_sequential_consistency:一致性查詢(xún),只有insert_quorum_parallel被禁用的時(shí)候,才會(huì)生效。
復(fù)制表相關(guān)的系統(tǒng)表
system.replicas
system.replicated_fetches
system.replication_queue
復(fù)制的監(jiān)控
各節(jié)點(diǎn)配置的 fetch 任務(wù)隊(duì)列長(zhǎng)度
select
hostName() as hostName,
value
from clusterAllReplicas('default', 'system.settings')
where name = 'background_fetches_pool_size'
order by hostName;
各節(jié)點(diǎn)正在執(zhí)行的fetch任務(wù)數(shù)
select
hostName,
count(*) as num
from (
select
hostName() as hostName,
database,
table
from
clusterAllReplicas('集群名', 'system.replicated_fetches')
) group by
hostName
各節(jié)點(diǎn)正在執(zhí)行的fetch任務(wù)的信息,根據(jù)耗時(shí)時(shí)間進(jìn)行排序
select
hostName() as hostName,
result_part_name,
source_replica_path,
source_replica_hostname,
source_replica_port,
database,
table,
elapsed,
progress,
total_size_bytes_compressed, --fetch所要讀取的所有的數(shù)據(jù)量
bytes_read_compressed, -- 已經(jīng)讀取的數(shù)據(jù)量
thread_id,
to_detached
from
clusterAllReplicas('default', 'system.replicated_fetches')
order by elapsed desc
節(jié)點(diǎn)后臺(tái)等待執(zhí)行的fetch 任務(wù)數(shù)
select
hostName() as hostName,
count(*) as num
from
clusterAllReplicas('default', 'system.replication_queue')
where
type = 'GET_PART'
and is_currently_executing = 0
order by hostName
節(jié)點(diǎn)后臺(tái)等待執(zhí)行的fetch 任務(wù)詳細(xì)信息,根據(jù)等待時(shí)間倒序排序
select
hostName() as hostName,
toUnixTimestamp(now()) - toUnixTimestamp(create_time) as task_wait_time,
source_replica, --來(lái)源副本名
replica_name, -- 目標(biāo)副本名
position, --任務(wù)位置
node_name, --任務(wù)節(jié)點(diǎn)名
database, -- 數(shù)據(jù)庫(kù)名
table, -- 表名
new_part_name, -- 生成的副本的名字
create_time, --任務(wù)創(chuàng)建時(shí)間
num_postponed, -- 推遲次數(shù)
postpone_reason, -- 推遲原因
last_postpone_time --上次推遲時(shí)間
from
clusterAllReplicas('default', 'system.replication_queue')
where
type = 'GET_PART'
and is_currently_executing = 0
order by task_wait_time desc
重試次數(shù)大于 指定限制的 fetch 任務(wù)數(shù)
select
hostName,
count(*) as num
from (
select
hostName() as hostName,
replica_name
from
clusterAllReplicas('集群名', 'system.replication_queue')
where
num_tries > 設(shè)置的重試次數(shù)
and type = 'GET_PART'
)
where hostName in (${hostName})
group by
hostName
重試次數(shù)大于 指定限制的 fetch 任務(wù)的詳情
select
*
from (
select
hostName() as hostName,
num_tries,
last_exception,
last_attempt_time,
source_replica,
replica_name,
database,
table,
new_part_name,
node_name,
position,
create_time
from
clusterAllReplicas('集群名', 'system.replication_queue')
where
num_tries > 重試次數(shù)
and type = 'GET_PART'
)
where
order by num_tries,create_time desc
limit 30
后臺(tái)part fetch 失敗的次數(shù)
select * from system,events where event = 'ReplicatedPartFailedFetches'
查看fetch 的繁忙程度
通過(guò)查看任務(wù)還未執(zhí)行的延時(shí)時(shí)間,如果出現(xiàn)有的任務(wù)很久之前已經(jīng)提交了,但是很久未被執(zhí)行,可以來(lái)反應(yīng)
select
hostName() as hostName,
toUnixTimestamp(now()) - toUnixTimestamp(create_time) as task_delay,
*
from
clusterAllReplicas('集群名', ' system.replication_queue ')
where is_currently_executing = 0
and type = 'GET_PART'
order by
task_delay desc limit 10