ClickHouse Replicated*MergeTree複製表原理、Distributed分佈式表原理

一、Replicated*MergeTree複製表原理

複製表通過zookeeper實現,其實就是通過zookeeper進行統一命名服務,並不依賴config.xml的remote_servers配置

不過雖然不依賴,但我們配置的時候儘可能還是要把複製表配置的分片副本信息與config.xml的remote_servers裏的分片副本信息一致。因爲使用Distributed分佈式表時,是不會使用zookeeper的信息,而是從config.xml的remote_servers獲取分片以及副本信息(搞不懂爲什麼不和複製表一樣,蛋疼)

 

1、複製表引擎

Replicated*MergeTree('shard_name','replicate_name')

如上,複製表要指定兩個參數。

第一個參數:當前本地複製表實例所屬的分片服務名稱。

分片服務名是zookeeper上的目錄名稱,如果你知道zookeeper實現的統一命名服務,那就好理解了,類似dubbo的服務提供者在zookeeper註冊的服務名。在dubbo中同一個服務名有多個實例提供相同的服務。服務調用者只需要通過服務名就能夠獲取到該服務的所有實例的信息。。

複製表這和dubbo差不多。。分片服務名就是在zookeeper上註冊的服務提供者名稱。多個複製表的該名稱如果一樣,那麼這些複製表都屬於同一個分片服務,只不過表示不同副本而已。同一個分片服務的不同副本之間數據會相互同步,保持一致,具體原理請看第2小節。

 

第二個參數:當前這張表所屬的副本名稱,一般用replica1、replica2表示。。如果第一個參數相同,當前第二個參數需要不同。。用以區分當前副本與其他副本。。

 

使用:

創建本地複製表模板如下:

CREATE TABLE test2.t1_local (`EventTime` Date, `id` UInt32) 
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/table_name', '{replica}')
PARTITION BY EventTime ORDER BY id

如果使用大括號表示會從配置文件中獲取宏定義的變量。。通過<macros/>標籤設置。。這自行百度,很簡單。

我沒使用大括號獲取宏定義變量,而是寫死,其實是一樣的。後期改成宏變量好維護。如下:

CREATE TABLE test2.t1_local (`EventTime` Date, `id` UInt32) 
ENGINE = ReplicatedMergeTree('/snowball/tables/t1_local/shard_2', 'replica_2') 
PARTITION BY EventTime ORDER BY id

根據兩個參數的結合,使用zookeeper的做統一命名服務。用於表示當前本地複製表是哪個分片服務的哪個副本。

當你create創建複製表時,就會把當前複製表的元數據信息註冊到zookeeper上。執行上述create table的sql後,在zookeeper上可以找到相關數據:

然後每個shard下存儲對應副本的元數據信息(這個分片的所有副本分別在哪個機器上之類的信息)。如下:

2、複製表同步原理

ClickHouse會把屬於同一個分片的所有副本數據進行同步。

這就是根據創建複製表時註冊到zookeeper上的信息實現的。

我們知道,其實一個副本就在一個ClickHouse實例上就是一張本地的表,只不過這張表引擎是複製表而已。

比如shard_1分片下有replicat1和replicat1兩個副本。就是在兩個在不同ClickHouse實例上的本地表,表引擎都是ReplicatedMergeTree。

但這兩個複製表的shard分片是一樣的(第一個參數是一樣的),而第二個參數(副本名)不一樣,所以這兩個表互爲副本。

當你往replicat1執行insert語句插入數據時,ReplicatedMergeTree複製表引擎就會啓動同步機制。。我個人猜測同步機制原理是:

(1)當你一個本地複製表執行insert語句插入數據時

(2)該本地複製表引擎會通過對應的分片服務名在zookeeper查詢到該分片的其他副本的元數據

(3)把數據insert到本地複製表之後,再把數據發送到該分片的其他副本上也進行insert。直到都insert成功爲止。

(4)並且在任一副本的複製表上insert,都會通過上述步驟把數據同步到其他副本。

 

 

3、對複製表的使用理解

複製表機制就僅僅只是提供一種副本機制。屬於同一個分片服務的不同複製表之間會相互同步數據。

但在查詢某個副本時,這個副本宕機了還無法把這個查詢自動切換到其他副本查詢。需要重新去另外一個未宕機的副本實例上查詢那個副本對應的本地複製表。雖然不同副本的數據是一樣的,但對用戶來說,某個副本宕機了還需要手動切換查詢的副本實例。

如果要做到在某個副本宕機時自動切換到其他可用副本,那麼就需要結合Distributed分佈式表進行使用了。

 

二、Distributed分佈式表

    分佈式表其實是一種視圖,

    分佈式引擎,本身不存儲數據,但可以在多個服務器上進行分佈式查詢。讀是自動並行的。讀取時,遠程服務器表的索引(如果存在)會被使用。

1、首先要了解config.xml的remote_servers配置集羣信息

因爲分佈式表是根據上面的配置信息獲取到自定義的集羣名、分片、副本等信息的。這些信息不會存到zookeeper。

分佈式表根據上面配置的信息才能知道查找和插入分佈式表時,實際插入的數據是往哪些分片、副本插入。。已經副本宕機時自動切換到新的可用副本。

我的測試環境配置如下

<remote_servers>
      <cluster_all>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <default_database>test1</default_database>
                    <host>node1</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <default_database>test2</default_database>
                    <host>node2</host>
                    <port>9000</port>
                </replica>
            </shard>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                   <default_database>test1</default_database>
                    <host>node2</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <default_database>test2</default_database>
                    <host>node3</host>
                    <port>9000</port>
                </replica>
            </shard>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <default_database>test1</default_database>
                    <host>node3</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <default_database>test2</default_database>
                    <host>node1</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_all>
</remote_server>

 

      Distributed(cluster_name, database, table, [sharding_key])

      參數解析:

      (1)cluster_name:集羣名。

      (2)database:數據庫名。可以爲空,但爲空時,查找某個分片的某個副本對應本地表時會使用上面配置中的default_databases的數據庫名。

        爲什麼這樣呢?因爲機器不夠。我這裏是三個分片,每個分片兩個副本。總共六個副本,那麼就要創建六個本地表。但我只有三臺機器。這就意味着每個機器上都得存在兩個副本,要創建兩個本地表,然後Distributed第(3)個參數指定的本地表名也只能指定一個名字,意味着創建的兩個本地表名必須相同。。

在同一個ClickHouse實例的同一個數據庫上,肯定無法做到create table兩個同名的本地表。。所以在機器有限的情況下,有兩種方式解決:

<1>一臺機器一個ClickHouse實例,把這兩個本地表創建在同一個ClickHouse實例的兩個不同數據庫上。

<2>一臺機器兩個ClickHouse實例,把這兩個本地表創建在不同ClickHouse實例的同一個數據庫中。

因爲同一機器上搭建多個ClickHouse實例太複雜,所以選擇第一種方式。

這又會出現另一個問題,Distributed引擎的第(2)個參數沒辦法傳遞多個數據庫名稱,這樣分佈式表就無法確定副本對應的本地表在哪個數據庫。這個解決方式如下:

在配置文件中配置每個副本的default_databases,創建分佈式表時Distributed引擎的第(2)個參數傳入空串,這樣當Distributed引擎查找副本時(查看下面ps),發現傳入的數據庫名稱是空串空串,就會根據配置文件的副本的default_databases找到相應的數據庫。

ps:Distributed引擎查找副本使用default_databases值的幾種情況:

<1>正常查詢副本時

<2>副本宕機,查找並切換其他副本

)    

 

如果機器足夠,就沒必要這樣了。。。比如上面六個副本,那麼用六臺機器,每臺機器一個ClickHouse實例,每個ClickHouse實例的同一個數據庫中創建一個本地表,這樣就行了。

      (3)table:本地表的表名。。去理解本地表和分佈式表的關係

      (4)sharding_key:數據分片鍵。
 

 

2、internal_replication的配置

可以參考:http://cxy7.com/articles/2019/06/07/1559910377679.html

<1>如果底層是非複製表,那麼這個值設爲false(默認)。表示insert分佈式表時,會在分片的所有副本都寫入一份。

<2>如果底層是複製表,那麼這個值配置爲true。表示分佈式表不會往所有副本都寫入。。僅寫入到一個副本。

 

internal_replication這個參數是控制寫入數據到分佈式表時,分佈式表會控制這個寫入是否的寫入到所有副本中。。與複製表的同步是不一樣的。爲什麼<2>中要設置爲true,這就是爲了避免和複製表的同步複製機制出現衝突,導致數據重複或者不一致。。

因爲如果既是複製表、internal_replication又爲false,那麼寫入到分佈式表時會寫入到同一分片的所有副本,而此時複製表的機制也會把不同副本之間的數據進行同步。。而且分佈式表寫入到所有副本並不是原子性的,也就是說,寫入到所有副本時,寫入某個副本失敗了,那這個副本就寫入失敗了,不會矯正。。複製表的同步是會保證同步的。

 

 

 

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