ClickHouse數據副本引擎

我的gitee地址:https://gitee.com/ddxygq/bigdata-technical-pai ,相關文章都放到這個倉庫裏了。

只有 MergeTree 系列裏的表可支持副本:

  • ReplicatedMergeTree
  • ReplicatedSummingMergeTree
  • ReplicatedReplacingMergeTree
  • ReplicatedAggregatingMergeTree
  • ReplicatedCollapsingMergeTree
  • ReplicatedVersionedCollapsingMergeTree
  • ReplicatedGraphiteMergeTree

副本是表級別的,不是整個服務器級的。所以,服務器裏可以同時有複製表和非複製表。

副本不依賴分片。每個分片有它自己的獨立副本。

對於 INSERT 和 ALTER 語句操作數據的會在壓縮的情況下被複制(更多信息,看 ALTER )。

而 CREATE,DROP,ATTACH,DETACH 和 RENAME 語句只會在單個服務器上執行,不會被複制。

  • CREATE TABLE 在運行此語句的服務器上創建一個新的可複製表。如果此表已存在其他服務器上,則給該表添加新副本。

  • DROP TABLE 刪除運行此查詢的服務器上的副本。

  • RENAME 重命名一個副本。換句話說,可複製表不同的副本可以有不同的名稱。

ClickHouse 使用 Apache ZooKeeper 存儲副本的元信息。請使用 ZooKeeper 3.4.5 或更高版本。

要使用副本,需在 Zookeeper 服務器的配置部分設置相應參數。

<zookeeper>
    <node index="1">
        <host>example1</host>
        <port>2181</port>
    </node>
    <node index="2">
        <host>example2</host>
        <port>2181</port>
    </node>
    <node index="3">
        <host>example3</host>
        <port>2181</port>
    </node>
</zookeeper>

爲了將數據表的元數據存儲到備用 ZooKeeper 集羣而非默認 ZooKeeper 集羣,我們可以通過如下 SQL 的方式創建使用 ReplicatedMergeTree 引擎的數據表:

CREATE TABLE table_name ( ... ) ENGINE = ReplicatedMergeTree('zookeeper_name_configured_in_auxiliary_zookeepers:path', 'replica_name') ...

你可以配置任何現有的 ZooKeeper 集羣,系統會使用裏面的目錄來存取元數據(該目錄在創建可複製表時指定)。

如果配置文件中沒有設置 ZooKeeper ,則無法創建複製表,並且任何現有的複製表都將變爲只讀。

SELECT 查詢並不需要藉助 ZooKeeper ,副本並不影響 SELECT 的性能,查詢複製表與非複製錶速度是一樣的。查詢分佈式表時,ClickHouse的處理方式可通過設置 max_replica_delay_for_distributed_queries 和 fallback_to_stale_replicas_for_distributed_queries 修改。

對於每個 INSERT 語句,會通過幾個事務將十來個記錄添加到 ZooKeeper。(確切地說,這是針對每個插入的數據塊; 每個 INSERT 語句的每 max_insert_block_size = 1048576 行和最後剩餘的都各算作一個塊。)相比非複製表,寫 zk 會導致 INSERT 的延遲略長一些。但只要你按照建議每秒不超過一個 INSERT 地批量插入數據,不會有任何問題。一個 ZooKeeper 集羣能給整個 ClickHouse 集羣支撐協調每秒幾百個 INSERT。數據插入的吞吐量(每秒的行數)可以跟不用複製的數據一樣高。

對於非常大的集羣,你可以把不同的 ZooKeeper 集羣用於不同的分片。然而,即使 Yandex.Metrica 集羣(大約300臺服務器)也證明還不需要這麼做。

複製是多主異步。 INSERT 語句(以及 ALTER )可以發給任意可用的服務器。數據會先插入到執行該語句的服務器上,然後被複制到其他服務器。由於它是異步的,在其他副本上最近插入的數據會有一些延遲。如果部分副本不可用,則數據在其可用時再寫入。副本可用的情況下,則延遲時長是通過網絡傳輸壓縮數據塊所需的時間。爲複製表執行後臺任務的線程數量,可以通過 background_schedule_pool_size 進行設置。

ReplicatedMergeTree 引擎採用一個獨立的線程池進行復制拉取。線程池的大小通過 background_fetches_pool_size 進行限定,它可以在重啓服務器時進行調整。

默認情況下,INSERT 語句僅等待一個副本寫入成功後返回。如果數據只成功寫入一個副本後該副本所在的服務器不再存在,則存儲的數據會丟失。要啓用數據寫入多個副本才確認返回,使用 insert_quorum 選項。

單個數據塊寫入是原子的。 INSERT 的數據按每塊最多 max_insert_block_size = 1048576 行進行分塊,換句話說,如果 INSERT 插入的行少於 1048576,則該 INSERT 是原子的。

數據塊會去重。對於被多次寫的相同數據塊(大小相同且具有相同順序的相同行的數據塊),該塊僅會寫入一次。這樣設計的原因是萬一在網絡故障時客戶端應用程序不知道數據是否成功寫入DB,此時可以簡單地重複 INSERT 。把相同的數據發送給多個副本 INSERT 並不會有問題。因爲這些 INSERT 是完全相同的(會被去重)。去重參數參看服務器設置 merge_tree 。(注意:Replicated*MergeTree 纔會去重,不需要 zookeeper 的不帶 MergeTree 不會去重)

在複製期間,只有要插入的源數據通過網絡傳輸。進一步的數據轉換(合併)會在所有副本上以相同的方式進行處理執行。這樣可以最大限度地減少網絡使用,這意味着即使副本在不同的數據中心,數據同步也能工作良好。(能在不同數據中心中的同步數據是副本機制的主要目標。)

你可以給數據做任意多的副本。Yandex.Metrica 在生產中使用雙副本。某一些情況下,給每臺服務器都使用 RAID-5 或 RAID-6 和 RAID-10。是一種相對可靠和方便的解決方案。

系統會監視副本數據同步情況,並能在發生故障後恢復。故障轉移是自動的(對於小的數據差異)或半自動的(當數據差異很大時,這可能意味是有配置錯誤)。

創建複製表

在表引擎名稱上加上 Replicated 前綴。例如:ReplicatedMergeTree。

Replicated*MergeTree 參數

  • zoo_path — ZooKeeper 中該表的路徑。

  • replica_name — ZooKeeper 中的該表的副本名稱。

  • other_parameters — 關於引擎的一系列參數,這個引擎即是用來創建複製的引擎,例如,ReplacingMergeTree 。

示例:

CREATE TABLE table_name
(
    EventDate DateTime,
    CounterID UInt32,
    UserID UInt32
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/table_name', '{replica}')
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID)

如上例所示,這些參數可以包含宏替換的佔位符,即大括號的部分。它們會被替換爲配置文件裏 ‘macros’ 那部分配置的值。示例:

<macros>
    <layer>05</layer>
    <shard>02</shard>
    <replica>example05-02-1</replica>
</macros>

ZooKeeper 中該表的路徑對每個可複製表都要是唯一的。不同分片上的表要有不同的路徑。 這種情況下,路徑包含下面這些部分:

/clickhouse/tables/ 是公共前綴,我們推薦使用這個。

{layer}-{shard} 是分片標識部分。在此示例中,由於 Yandex.Metrica 集羣使用了兩級分片,所以它是由兩部分組成的。但對於大多數情況來說,你只需保留 {shard} 佔位符即可,它會替換展開爲分片標識。

table_name 是該表在 ZooKeeper 中的名稱。使其與 ClickHouse 中的表名相同比較好。 這裏它被明確定義,跟 ClickHouse 表名不一樣,它並不會被 RENAME 語句修改。 HINT:你也可以在 table_name 前面添加一個數據庫名稱。例如: db_name.table_name 。

兩個內置的佔位符 {database} 和 {table} 也可使用,它們可以展開成數據表名稱和數據庫名稱(只有當這些宏指令在 macros 部分已經定義時纔可以)。因此 ZooKeeper 路徑可以指定爲 '/clickhouse/tables/{layer}-{shard}/{database}/{table}' 。

當使用這些內置佔位符時,請當心數據表重命名。 ZooKeeper 中的路徑無法變更,而當數據表被重命名時,宏命令將展開爲另一個路徑,數據表將指向一個 ZooKeeper 上並不存在的路徑,並因此轉變爲只讀模式。

副本名稱用於標識同一個表分片的不同副本。你可以使用服務器名稱,如上例所示。同個分片中不同副本的副本名稱要唯一。

你也可以顯式指定這些參數,而不是使用宏替換。對於測試和配置小型集羣這可能會很方便。但是,這種情況下,則不能使用分佈式 DDL 語句(ON CLUSTER)。

使用大型集羣時,我們建議使用宏替換,因爲它可以降低出錯的可能性。

你可以在服務器的配置文件中指定 Replicated 數據表引擎的默認參數。例如:

<default_replica_path>/clickhouse/tables/{shard}/{database}/{table}</default_replica_path>
<default_replica_name>{replica}</default_replica_name>

這樣,你可以在建表時省略參數:

CREATE TABLE table_name (
    x UInt32
) ENGINE = ReplicatedMergeTree
ORDER BY x;

它等價於:

CREATE TABLE table_name (
    x UInt32
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/table_name', '{replica}')
ORDER BY x;

在每個副本服務器上運行 CREATE TABLE 查詢。將創建新的複製表,或給現有表添加新副本。

如果其他副本上已包含了某些數據,在表上添加新副本,則在運行語句後,數據會從其他副本複製到新副本。換句話說,新副本會與其他副本同步。

要刪除副本,使用 DROP TABLE。但它只刪除那個 – 位於運行該語句的服務器上的副本。

故障恢復

如果服務器啓動時 ZooKeeper 不可用,則複製表會切換爲只讀模式。系統會定期嘗試去連接 ZooKeeper。

如果在 INSERT 期間 ZooKeeper 不可用,或者在與 ZooKeeper 交互時發生錯誤,則拋出異常。

連接到 ZooKeeper 後,系統會檢查本地文件系統中的數據集是否與預期的數據集( ZooKeeper 存儲此信息)一致。如果存在輕微的不一致,系統會通過與副本同步數據來解決。

如果系統檢測到損壞的數據片段(文件大小錯誤)或無法識別的片段(寫入文件系統但未記錄在 ZooKeeper 中的部分),則會把它們移動到 ‘detached’ 子目錄(不會刪除)。而副本中其他任何缺少的但正常數據片段都會被複制同步。

注意,ClickHouse 不會執行任何破壞性操作,例如自動刪除大量數據。

當服務器啓動(或與 ZooKeeper 建立新會話)時,它只檢查所有文件的數量和大小。 如果文件大小一致但中間某處已有字節被修改過,不會立即被檢測到,只有在嘗試讀取 SELECT 查詢的數據時纔會檢測到。該查詢會引發校驗和不匹配或壓縮塊大小不一致的異常。這種情況下,數據片段會添加到驗證隊列中,並在必要時從其他副本中複製。

如果本地數據集與預期數據的差異太大,則會觸發安全機制。服務器在日誌中記錄此內容並拒絕啓動。這種情況很可能是配置錯誤,例如,一個分片上的副本意外配置爲別的分片上的副本。然而,此機制的閾值設置得相當低,在正常故障恢復期間可能會出現這種情況。在這種情況下,數據恢復則是半自動模式,通過用戶主動操作觸發。

要觸發啓動恢復,可在 ZooKeeper 中創建節點 /path_to_table/replica_name/flags/force_restore_data,節點值可以是任何內容,或運行命令來恢復所有的可複製表:

sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data

然後重啓服務器。啓動時,服務器會刪除這些標誌並開始恢復。

在數據完全丟失後的恢復

如果其中一個服務器的所有數據和元數據都消失了,請按照以下步驟進行恢復:

  • 在服務器上安裝 ClickHouse。在包含分片標識符和副本的配置文件中正確定義宏配置,如果有用到的話,
  • 如果服務器上有非複製表則必須手動複製,可以從副本服務器上(在 /var/lib/clickhouse/data/db_name/table_name/ 目錄中)複製它們的數據。
  • 從副本服務器上中複製位於 /var/lib/clickhouse/metadata/ 中的表定義信息。如果在表定義信息中顯式指定了分片或副本標識符,請更正它以使其對應於該副本。(另外,啓動服務器,然後會在 /var/lib/clickhouse/metadata/ 中的.sql文件中生成所有的 ATTACH TABLE 語句。)
  • 要開始恢復,ZooKeeper 中創建節點 /path_to_table/replica_name/flags/force_restore_data,節點內容不限,或運行命令來恢復所有複製的表:sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data

然後啓動服務器(如果它已運行則重啓)。數據會從副本中下載。

另一種恢復方式是從 ZooKeeper(/path_to_table/replica_name)中刪除有數據丟的副本的所有元信息,然後再按照«創建可複製表»中的描述重新創建副本。

恢復期間的網絡帶寬沒有限制。特別注意這一點,尤其是要一次恢復很多副本。

MergeTree 轉換爲 ReplicatedMergeTree

我們使用 MergeTree 來表示 MergeTree系列 中的所有表引擎,ReplicatedMergeTree 同理。

如果你有一個手動同步的 MergeTree 表,您可以將其轉換爲可複製表。如果你已經在 MergeTree 表中收集了大量數據,並且現在要啓用複製,則可以執行這些操作。

如果各個副本上的數據不一致,則首先對其進行同步,或者除保留的一個副本外,刪除其他所有副本上的數據。

重命名現有的 MergeTree 表,然後使用舊名稱創建 ReplicatedMergeTree 表。 將數據從舊錶移動到新表(/var/lib/clickhouse/data/db_name/table_name/)目錄內的 ‘detached’ 目錄中。 然後在其中一個副本上運行ALTER TABLE ATTACH PARTITION,將這些數據片段添加到工作集中。

ReplicatedMergeTree 轉換爲 MergeTree

使用其他名稱創建 MergeTree 表。將具有ReplicatedMergeTree表數據的目錄中的所有數據移動到新表的數據目錄中。然後刪除ReplicatedMergeTree表並重新啓動服務器。

如果你想在不啓動服務器的情況下清除 ReplicatedMergeTree 表:

  • 刪除元數據目錄中的相應 .sql 文件(/var/lib/clickhouse/metadata/)。

  • 刪除 ZooKeeper 中的相應路徑(/path_to_table/replica_name)。

之後,你可以啓動服務器,創建一個 MergeTree 表,將數據移動到其目錄,然後重新啓動服務器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章