Clickhouse集群應(yīng)用笆环、分片攒至、復(fù)制

簡(jiǎn)介

通常生產(chǎn)環(huán)境我們會(huì)用集群代替單機(jī),主要是解決兩個(gè)問(wèn)題:

  • 效率
  • 穩(wěn)定

如何提升效率躁劣?一個(gè)大大大任務(wù)迫吐,讓一個(gè)人干需要一年,拆解一下讓12個(gè)人同時(shí)干账忘,可能只需要1個(gè)月志膀。對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō)熙宇,就是數(shù)據(jù)分片。

如何提升穩(wěn)定性梧却?所謂穩(wěn)定就是要保證服務(wù)時(shí)刻都能用奇颠,也常說(shuō)高可用败去。這就像團(tuán)隊(duì)里必須有二把手放航,老大有事不在,老二要能頂上圆裕。對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō)广鳍,就是數(shù)據(jù)備份。

而集群是解決這兩個(gè)問(wèn)題的最佳手段吓妆。話說(shuō)赊时,三個(gè)臭皮匠,賽過(guò)諸葛亮行拢,這就是團(tuán)隊(duì)的力量祖秒。

幾乎所有大數(shù)據(jù)相關(guān)的產(chǎn)品,基本都是以這兩個(gè)問(wèn)題為出發(fā)點(diǎn)舟奠,Clickhouse也不例外竭缝。

不同的是,Hadoop系列的集群是服務(wù)級(jí)別的沼瘫,而Clickhouse的集群是表上的抬纸。例如,一個(gè)hdfs集群耿戚,所有文件都會(huì)切片湿故、備份;而clickhouse集群中膜蛔,建表時(shí)也可以自己決定用不用坛猪。習(xí)慣了其他大數(shù)據(jù)產(chǎn)品的人,剛轉(zhuǎn)到clickhouse會(huì)感覺(jué)這設(shè)計(jì)太反人類皂股,后文會(huì)詳細(xì)介紹墅茉。

安裝

我們使用三臺(tái)機(jī)器演示,三個(gè)機(jī)器分別安裝clickhouse
教程:http://www.reibang.com/p/5f5ee0904bba

數(shù)據(jù)

實(shí)驗(yàn)使用到官方提供的OnTime數(shù)據(jù)集屑墨,先下載下來(lái)躁锁,并按照文檔建表。

教程: https://clickhouse.yandex/docs/en/single/?query=internal_replication#ontime

數(shù)據(jù)分片

這里再說(shuō)明一下卵史,分片是為了提高效率战转。

分片,就像是把雞蛋放到多個(gè)籃子里以躯,降低整體風(fēng)險(xiǎn)槐秧,結(jié)果可能是部分?jǐn)?shù)據(jù)不可用啄踊,雖然一定程度上起到了「高可用」的作用,但分片的目的是為了提速刁标。況且颠通,比較嚴(yán)格的場(chǎng)景下,部分不可用也是不可用膀懈。

clickhouse需要自己動(dòng)手定義分片顿锰。

vim /etc/clickhouse-server/config.xml

編輯config.xml文件,搜索remote_servers:

<remote_servers incl="clickhouse_remote_servers" >
    ...
</remote_servers>

說(shuō)明:remote_servers就是集群配置启搂,可以直接在此處配置硼控,也可以提出來(lái)配置到擴(kuò)展文件中。incl屬性表示可從外部文件中獲取節(jié)點(diǎn)名為clickhouse_remote_servers的配置內(nèi)容胳赌。

我們使用擴(kuò)展文件牢撼,首先,添加外部擴(kuò)展配置文件:

<include_from>/etc/clickhouse-server/metrika.xml</include_from>

然后疑苫,編輯配置文件:

vim /etc/clickhouse-server/metrika.xml

添加內(nèi)容:

<yandex>
<!-- 集群配置 -->
<clickhouse_remote_servers>
    <!-- 3分片1備份 -->
    <cluster_3shards_1replicas>
        <!-- 數(shù)據(jù)分片1  -->
        <shard>
            <replica>
                <host>hadoop1</host>
                <port>9000</port>
            </replica>
        </shard>
        <!-- 數(shù)據(jù)分片2  -->
        <shard>
            <replica>
                <host>hadoop2</host>
                <port> 9000</port>
            </replica>
        </shard>
        <!-- 數(shù)據(jù)分片3  -->
        <shard>
            <replica>
                <host>hadoop3</host>
                <port>9000</port>
            </replica>
        </shard>
    </cluster_3shards_1replicas>
</clickhouse_remote_servers>
</yandex>

說(shuō)明:

  • clickhouse_remote_servers與config.xml中的incl屬性值對(duì)應(yīng)熏版;
  • cluster_3shards_1replicas是集群名,可以隨便取名捍掺;
  • 共設(shè)置3個(gè)分片撼短,每個(gè)分片只有1個(gè)副本;

在其他兩臺(tái)機(jī)器上同樣操作乡小。

打開(kāi)clickhouse-client阔加,查看集群:

hadoop1 :) select * from system.clusters;

SELECT *
FROM system.clusters

┌─cluster───────────────────┬─shard_num─┬─shard_weight─┬─replica_num─┬─host_name─┬─host_address─┬─port─┬─is_local─┬─user────┬─default_database─┐
│ cluster_3shards_1replicas │         1 │            1 │           1 │ hadoop1   │ 192.168.0.6  │ 9000 │        1 │ default │                  │
│ cluster_3shards_1replicas │         2 │            1 │           1 │ hadoop2   │ 192.168.0.16 │ 9000 │        0 │ default │                  │
│ cluster_3shards_1replicas │         3 │            1 │           1 │ hadoop3   │ 192.168.0.11 │ 9000 │        0 │ default │                  │
└───────────────────────────┴───────────┴──────────────┴─────────────┴───────────┴──────────────┴──────┴──────────┴─────────┴──────────────────┘

3 rows in set. Elapsed: 0.003 sec.

可以看到cluster_3shards_1replicas就是我們定義的集群名稱,一共有三個(gè)分片满钟,每個(gè)分片有一份數(shù)據(jù)胜榔。

建數(shù)據(jù)表

在三個(gè)節(jié)點(diǎn)上分別建表:ontime_local

CREATE TABLE `ontime_local` (
  `Year` UInt16,
  `Quarter` UInt8,
  `Month` UInt8,
  `DayofMonth` UInt8,
  `DayOfWeek` UInt8,
  `FlightDate` Date,
  `UniqueCarrier` FixedString(7),
  `AirlineID` Int32,
  `Carrier` FixedString(2),
  `TailNum` String,
  `FlightNum` String,
  `OriginAirportID` Int32,
  `OriginAirportSeqID` Int32,
  `OriginCityMarketID` Int32,
  `Origin` FixedString(5),
  `OriginCityName` String,
  `OriginState` FixedString(2),
  `OriginStateFips` String,
  `OriginStateName` String,
  `OriginWac` Int32,
  `DestAirportID` Int32,
  `DestAirportSeqID` Int32,
  `DestCityMarketID` Int32,
  `Dest` FixedString(5),
  `DestCityName` String,
  `DestState` FixedString(2),
  `DestStateFips` String,
  `DestStateName` String,
  `DestWac` Int32,
  `CRSDepTime` Int32,
  `DepTime` Int32,
  `DepDelay` Int32,
  `DepDelayMinutes` Int32,
  `DepDel15` Int32,
  `DepartureDelayGroups` String,
  `DepTimeBlk` String,
  `TaxiOut` Int32,
  `WheelsOff` Int32,
  `WheelsOn` Int32,
  `TaxiIn` Int32,
  `CRSArrTime` Int32,
  `ArrTime` Int32,
  `ArrDelay` Int32,
  `ArrDelayMinutes` Int32,
  `ArrDel15` Int32,
  `ArrivalDelayGroups` Int32,
  `ArrTimeBlk` String,
  `Cancelled` UInt8,
  `CancellationCode` FixedString(1),
  `Diverted` UInt8,
  `CRSElapsedTime` Int32,
  `ActualElapsedTime` Int32,
  `AirTime` Int32,
  `Flights` Int32,
  `Distance` Int32,
  `DistanceGroup` UInt8,
  `CarrierDelay` Int32,
  `WeatherDelay` Int32,
  `NASDelay` Int32,
  `SecurityDelay` Int32,
  `LateAircraftDelay` Int32,
  `FirstDepTime` String,
  `TotalAddGTime` String,
  `LongestAddGTime` String,
  `DivAirportLandings` String,
  `DivReachedDest` String,
  `DivActualElapsedTime` String,
  `DivArrDelay` String,
  `DivDistance` String,
  `Div1Airport` String,
  `Div1AirportID` Int32,
  `Div1AirportSeqID` Int32,
  `Div1WheelsOn` String,
  `Div1TotalGTime` String,
  `Div1LongestGTime` String,
  `Div1WheelsOff` String,
  `Div1TailNum` String,
  `Div2Airport` String,
  `Div2AirportID` Int32,
  `Div2AirportSeqID` Int32,
  `Div2WheelsOn` String,
  `Div2TotalGTime` String,
  `Div2LongestGTime` String,
  `Div2WheelsOff` String,
  `Div2TailNum` String,
  `Div3Airport` String,
  `Div3AirportID` Int32,
  `Div3AirportSeqID` Int32,
  `Div3WheelsOn` String,
  `Div3TotalGTime` String,
  `Div3LongestGTime` String,
  `Div3WheelsOff` String,
  `Div3TailNum` String,
  `Div4Airport` String,
  `Div4AirportID` Int32,
  `Div4AirportSeqID` Int32,
  `Div4WheelsOn` String,
  `Div4TotalGTime` String,
  `Div4LongestGTime` String,
  `Div4WheelsOff` String,
  `Div4TailNum` String,
  `Div5Airport` String,
  `Div5AirportID` Int32,
  `Div5AirportSeqID` Int32,
  `Div5WheelsOn` String,
  `Div5TotalGTime` String,
  `Div5LongestGTime` String,
  `Div5WheelsOff` String,
  `Div5TailNum` String
) ENGINE = MergeTree(FlightDate, (Year, FlightDate), 8192)

表結(jié)構(gòu)與ontime完全一樣。

建分布表

CREATE TABLE ontime_all AS ontime_local
ENGINE = Distributed(cluster_3shards_1replicas, default, ontime_local, rand())

分布表(Distributed)本身不存儲(chǔ)數(shù)據(jù)湃番,相當(dāng)于路由夭织,需要指定集群名、數(shù)據(jù)庫(kù)名吠撮、數(shù)據(jù)表名尊惰、分片KEY,這里分片用rand()函數(shù)泥兰,表示隨機(jī)分片弄屡。查詢分布表,會(huì)根據(jù)集群配置信息鞋诗,路由到具體的數(shù)據(jù)表膀捷,再把結(jié)果進(jìn)行合并。

ontime_all與ontime在同一個(gè)節(jié)點(diǎn)上削彬,方便插入數(shù)據(jù)全庸。

插入數(shù)據(jù)

INSERT INTO ontime_all SELECT * FROM ontime;

把ontime的數(shù)據(jù)插入到ontime_all秀仲,ontime_all會(huì)隨機(jī)插入到三個(gè)節(jié)點(diǎn)的ontime_local里。

表ontime需要提前建好壶笼,并導(dǎo)入數(shù)據(jù)神僵。

導(dǎo)入完成后,查看總數(shù)據(jù)量:

hadoop1 :) select count(1) from ontime_all;

SELECT count(1)
FROM ontime_all

┌──count(1)─┐
│ 177920306 │
└───────────┘

再看下每個(gè)節(jié)點(diǎn)的數(shù)據(jù):

hadoop1 :) select count(1) from ontime_local;

SELECT count(1)
FROM ontime_local

┌─count(1)─┐
│ 59314494 │
└──────────┘

可以看到覆劈,每個(gè)節(jié)點(diǎn)大概有1/3的數(shù)據(jù)保礼。

性能對(duì)比

對(duì)比一下分片與不分片的性能差異。

不分片:

hadoop1 :) select Carrier, count() as c, round(quantileTDigest(0.99)(DepDelay), 2) as q from ontime group by Carrier order by q desc limit 5;

SELECT
    Carrier,
    count() AS c,
    round(quantileTDigest(0.99)(DepDelay), 2) AS q
FROM ontime
GROUP BY Carrier
ORDER BY q DESC
LIMIT 5

┌─Carrier─┬───────c─┬──────q─┐
│ B6      │ 2991782 │ 191.22 │
│ NK      │  412396 │ 190.97 │
│ EV      │ 6222018 │ 187.17 │
│ XE      │ 2145095 │ 179.55 │
│ VX      │  371390 │  178.3 │
└─────────┴─────────┴────────┘

5 rows in set. Elapsed: 1.951 sec. Processed 177.92 million rows, 1.07 GB (91.18 million rows/s., 547.11 MB/s.)

用時(shí)1.951秒墩崩。

分片:

hadoop1 :) select Carrier, count() as c, round(quantileTDigest(0.99)(DepDelay), 2) as q from ontime_all group by Carrier order by q desc limit 5;

SELECT
    Carrier,
    count() AS c,
    round(quantileTDigest(0.99)(DepDelay), 2) AS q
FROM ontime_all
GROUP BY Carrier
ORDER BY q DESC
LIMIT 5

┌─Carrier─┬───────c─┬──────q─┐
│ B6      │ 2991782 │  191.2 │
│ NK      │  412396 │ 191.06 │
│ EV      │ 6222018 │ 187.22 │
│ XE      │ 2145095 │ 179.42 │
│ VX      │  371390 │ 178.33 │
└─────────┴─────────┴────────┘

5 rows in set. Elapsed: 0.960 sec. Processed 177.92 million rows, 1.07 GB (185.37 million rows/s., 1.11 GB/s.)

用時(shí)0.96秒氓英,速度大約提升2倍侯勉。

現(xiàn)在鹦筹,停掉一個(gè)節(jié)點(diǎn),會(huì)是神馬情況址貌?

Received exception from server (version 18.10.3):
Code: 279. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::NetException. DB::NetException: All connection tries failed. Log:

Code: 32, e.displayText() = DB::Exception: Attempt to read after eof, e.what() = DB::Exception
Code: 210, e.displayText() = DB::NetException: Connection refused: (hadoop2:9000, 192.168.0.16), e.what() = DB::NetException
Code: 210, e.displayText() = DB::NetException: Connection refused: (hadoop2:9000, 192.168.0.16), e.what() = DB::NetException

報(bào)錯(cuò)了铐拐,看來(lái)clickhouse的處理很嚴(yán)格,如果一個(gè)分片不可用练对,就整個(gè)分布式表都不可用了遍蟋。

當(dāng)然,此時(shí)如果查本地表ontime_local還是可以的螟凭。

那么虚青,如何解決整個(gè)問(wèn)題呢?這就是前文所說(shuō)的穩(wěn)定性問(wèn)題了螺男,解決方案是:數(shù)據(jù)備份棒厘!

數(shù)據(jù)備份

說(shuō)明一點(diǎn),數(shù)據(jù)備份與分片沒(méi)有必然聯(lián)系下隧,這是兩個(gè)方面的問(wèn)題奢人。但在clickhouse中,replica是掛在shard上的淆院,因此要用多副本何乎,必須先定義shard。

最簡(jiǎn)單的情況:1個(gè)分片多個(gè)副本土辩。

添加集群

像之前一樣支救,再配置一個(gè)集群,叫做cluster_1shards_2replicas拷淘,表示1分片2副本各墨,配置信息如下:

<yandex>
        <!-- 1分片2備份 -->
        <cluster_1shards_2replicas>
            <shard>
                <internal_replication>false</internal_replication>
                <replica>
                    <host>hadoop1</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>hadoop2</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_1shards_2replicas>
</yandex>

注意,如果配置文件沒(méi)有問(wèn)題辕棚,是不用重啟clickhouse-server的欲主,會(huì)自動(dòng)加載邓厕!

建數(shù)據(jù)表

CREATE TABLE `ontime_local_2` (
  ...
) ENGINE = MergeTree(FlightDate, (Year, FlightDate), 8192)

表名為ontime_local_2,在三臺(tái)機(jī)器分別執(zhí)行扁瓢。

建分布表

CREATE TABLE ontime_all_2 AS ontime_local_2
ENGINE = Distributed(cluster_1shards_2replicas, default, ontime_local_2, rand())

表名是ontime_all_2详恼,使用cluster_1shards_2replicas集群,數(shù)據(jù)為ontime_local_2引几。

導(dǎo)入數(shù)據(jù)

INSERT INTO ontime_all_2 SELECT * FROM ontime

查詢

hadoop1 :) select count(1) from ontime_all_2;

SELECT count(1)
FROM ontime_all_2

┌──count(1)─┐
│ 177920306 │
└───────────┘

查詢ontime_local_2昧互,兩個(gè)節(jié)點(diǎn)都有全量數(shù)據(jù)。

關(guān)掉一個(gè)服務(wù)器伟桅,仍能查詢?nèi)繑?shù)據(jù)敞掘,數(shù)據(jù)副本已經(jīng)生效。

一致性

既然有多副本楣铁,就有個(gè)一致性的問(wèn)題:加入寫(xiě)入數(shù)據(jù)時(shí)玖雁,掛掉一臺(tái)機(jī)器,會(huì)怎樣盖腕?

我們來(lái)模擬一下:

  1. 停掉hadoop2服務(wù)
service clickhouse-server stop
  1. 通過(guò)ontime_all_2插入幾條數(shù)據(jù)
hadoop1 :) insert into ontime_all_2 select * from ontime limit 10;
  1. 啟動(dòng)hadoop2服務(wù)
service clickhouse-server start
  1. 查詢驗(yàn)證
    查看兩個(gè)機(jī)器的ontime_local_2赫冬、以及ontime_all_2,發(fā)現(xiàn)都是總數(shù)據(jù)量都增加了10條溃列,說(shuō)明這種情況下劲厌,集群節(jié)點(diǎn)之間能夠自動(dòng)同步

再模擬一個(gè)復(fù)雜點(diǎn)的:

  1. 停掉hadoop2;
  2. 通過(guò)ontime_all_2插入10條數(shù)據(jù)听隐;
  3. 查詢ontime_all_2补鼻,此時(shí)數(shù)據(jù)增加了10條;
  4. 停掉hadoop1雅任;
  5. 啟動(dòng)hadoop2风范,此時(shí),整個(gè)集群不可用椿访;
  6. 查詢ontime_all_2乌企,此時(shí),集群恢復(fù)可用成玫,但數(shù)據(jù)少了10條加酵;
  7. 啟動(dòng)hadoop1,查詢ontime_all_2哭当、ontime_local_2猪腕,數(shù)據(jù)自動(dòng)同步;

上邊都是通過(guò)ontime_all_2表插入數(shù)據(jù)的钦勘,如果通過(guò)ontime_local_2表插入數(shù)據(jù)陋葡,還能同步嗎?

  1. hadoop1上往ontime_local_2插入10條數(shù)據(jù)彻采;
  2. 查詢hadoop2腐缤,ontime_local_2數(shù)據(jù)沒(méi)有同步

綜上捌归,通過(guò)分布表寫(xiě)入數(shù)據(jù),會(huì)自動(dòng)同步數(shù)據(jù)岭粤;而通過(guò)數(shù)據(jù)表寫(xiě)入數(shù)據(jù)惜索,不會(huì)同步;正常情況沒(méi)什么大問(wèn)題剃浇。

更復(fù)雜的情況沒(méi)有模擬出來(lái)巾兆,但是可能會(huì)存在數(shù)據(jù)不一致的問(wèn)題,官方文檔描述如下:

Each shard can have the 'internal_replication' parameter defined in the config file.

If this parameter is set to 'true', the write operation selects the first healthy replica and writes data to it. Use this alternative if the Distributed table "looks at" replicated tables. In other words, if the table where data will be written is going to replicate them itself.

If it is set to 'false' (the default), data is written to all replicas. In essence, this means that the Distributed table replicates data itself. This is worse than using replicated tables, because the consistency of replicas is not checked, and over time they will contain slightly different data.

翻譯下:

分片可以設(shè)置internal_replication屬性虎囚,這個(gè)屬性是true或者false角塑,默認(rèn)是false。

如果設(shè)置為true淘讥,則往本地表寫(xiě)入數(shù)據(jù)時(shí)圃伶,總是寫(xiě)入到完整健康的副本里,然后由表自身完成復(fù)制适揉,這就要求本地表是能自我復(fù)制的留攒。

如果設(shè)置為false,則寫(xiě)入數(shù)據(jù)時(shí)嫉嘀,是寫(xiě)入到所有副本中。這時(shí)魄揉,是無(wú)法保證一致性的剪侮。

舉個(gè)栗子,一條數(shù)據(jù)要insert到ontime_all_2中洛退,假設(shè)經(jīng)過(guò)rand()實(shí)際是要寫(xiě)入到hadoop1的ontime_local表中瓣俯,此時(shí)ontime_local配置了兩個(gè)副本。
如果internal_replication是false兵怯,那么就會(huì)分別往兩個(gè)副本中插入這條數(shù)據(jù)彩匕。注意!C角驼仪!分別插入,可能一個(gè)成功袜漩,一個(gè)失敗绪爸,插入結(jié)果不檢驗(yàn)!這就導(dǎo)致了不一致性宙攻;
而如果internal_replication是true奠货,則只往1個(gè)副本里寫(xiě)數(shù)據(jù),其他副本則是由ontime_local自己進(jìn)行同步座掘,這樣就解決了寫(xiě)入一致性問(wèn)題递惋。

雖然沒(méi)有模擬出數(shù)據(jù)不一致的情況柔滔,實(shí)際中可能會(huì)遇到,所以官方建議使用表自動(dòng)同步的方式萍虽,也就是internal_replication為true廊遍。

具體怎么用,下邊具體介紹贩挣。

自動(dòng)數(shù)據(jù)備份

自動(dòng)數(shù)據(jù)備份喉前,是表的行為,ReplicatedXXX的表支持自動(dòng)同步王财。

Replicated前綴只用于MergeTree系列(MergeTree是最常用的引擎)卵迂,即clickhouse支持以下幾種自動(dòng)備份的引擎:

ReplicatedMergeTree
ReplicatedSummingMergeTree
ReplicatedReplacingMergeTree
ReplicatedAggregatingMergeTree
ReplicatedCollapsingMergeTree
ReplicatedGraphiteMergeTree

再?gòu)?qiáng)調(diào)一遍,Replicated表自動(dòng)同步與之前的集群自動(dòng)同步不同绒净,是表的行為见咒,與clickhouse_remote_servers配置沒(méi)有關(guān)系,只要有zookeeper配置就行了挂疆。

為了說(shuō)明這個(gè)問(wèn)題改览,先不配置clickhouse_remote_servers,只添加zookeeper配置:

<yandex>
    ...
    <zookeeper-servers>
        <node index="1">
            <host>hadoop1</host>
            <port>2181</port>
        </node>
        <node index="2">
            <host>hadoop2</host>
            <port>2181</port>
        </node>
        <node index="3">
            <host>hadoop3</host>
            <port>2181</port>
        </node>
    </zookeeper-servers>
    ...
</yandex>

建數(shù)據(jù)表

hadoop1:
CREATE TABLE `ontime_replica` (
  ...
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/ontime', 'replica1', FlightDate, (Year, FlightDate), 8192);

hadoop2:
CREATE TABLE `ontime_replica` (
  ...
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/ontime', 'replica2', FlightDate, (Year, FlightDate), 8192);

hadoop3:
CREATE TABLE `ontime_replica` (
  ...
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/ontime', 'replica3', FlightDate, (Year, FlightDate), 8192);

查看zk信息:

[zk: localhost:2181(CONNECTED) 0] ls /clickhouse/tables/ontime/replicas
[replica2, replica3, replica1]

可以看到缤言,zk中已經(jīng)有了對(duì)應(yīng)的路徑和副本信息宝当。

插入數(shù)據(jù)

hadoop1:
INSERT INTO ontime_replica SELECT * FROM ontime

注意!只在一個(gè)機(jī)器上執(zhí)行插入操作胆萧。

查看數(shù)據(jù)

分別在三個(gè)機(jī)器上查詢ontime_replica庆揩,都有數(shù)據(jù),且數(shù)據(jù)完全一樣跌穗。

可以看到订晌,這種方式與之前方式的區(qū)別,直接寫(xiě)入一個(gè)節(jié)點(diǎn)蚌吸,其他節(jié)點(diǎn)自動(dòng)同步锈拨,完全是表的行為;而之前的方式必須創(chuàng)建Distributed表羹唠,并通過(guò)Distributed表寫(xiě)入數(shù)據(jù)才能同步(目前我們還沒(méi)有給ontime_replica創(chuàng)建對(duì)應(yīng)的Distributed表)奕枢。

配置集群

...
        <!-- 1分片3備份:使用表備份-->
        <cluster_1shards_3replicas>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>hadoop1</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>hadoop2</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>hadoop3</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_1shards_3replicas>
...

集群名字為cluster_1shards_3replicas,1個(gè)分片肉迫,3個(gè)副本验辞;與之前不同,這次設(shè)置internal_replication為true喊衫,表示要用表自我復(fù)制功能跌造,而不用集群的復(fù)制功能。

建分布表

CREATE TABLE ontime_replica_all AS ontime_replica
ENGINE = Distributed(cluster_1shards_3replicas, default, ontime_replica, rand())

表名為ontime_replica_all,使用cluster_1shards_3replicas集群壳贪,數(shù)據(jù)表為ontime_replica陵珍。

查詢分布表:

hadoop1 :) select count(1) from ontime_replica_all;

SELECT count(1)
FROM ontime_replica_all

┌──count(1)─┐
│ 177920306 │
└───────────┘

分布表寫(xiě)入

前邊說(shuō)了,一個(gè)節(jié)點(diǎn)ontime_replica寫(xiě)入數(shù)據(jù)時(shí)违施,其他節(jié)點(diǎn)自動(dòng)同步互纯;那如果通過(guò)分布表ontime_replica_all寫(xiě)入數(shù)據(jù)會(huì)如何呢?

其實(shí)磕蒲,前文已經(jīng)提到過(guò)留潦,internal_replication為true,則通過(guò)分布表寫(xiě)入數(shù)據(jù)時(shí)辣往,會(huì)自動(dòng)找到“最健康”的副本寫(xiě)入兔院,然后其他副本通過(guò)表自身的復(fù)制功能同步數(shù)據(jù),最終達(dá)到數(shù)據(jù)一致站削。

分片 + 備份

分片坊萝,是為了突破單機(jī)上限(存儲(chǔ)、計(jì)算等上限)许起,備份是為了高可用十偶。

只分片,提升了性能园细,但是一個(gè)分片掛掉惦积,整個(gè)服務(wù)不可用;只備份珊肃,確實(shí)高可用了荣刑,但是整體還是受限于單機(jī)瓶頸(備份1000份與備份2份沒(méi)什么區(qū)別,除了更浪費(fèi)機(jī)器)伦乔。

所以,生產(chǎn)中這兩方面需要同時(shí)滿足董习。

其實(shí)烈和,只要把之前的分片和備份整合起來(lái)就行了,例如皿淋,3分片2備份的配置如下:

...
        <!-- 3分片2備份:使用表備份 -->
        <cluster_3shards_2replicas>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>hadoop1</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>hadoop2</host>
                    <port>9000</port>
                </replica>
            </shard>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>hadoop3</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>hadoop4</host>
                    <port>9000</port>
                </replica>
            </shard>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>hadoop5</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>hadoop6</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_3shards_2replicas>
...

這里一共需要建6個(gè)數(shù)據(jù)表:

CREATE TABLE `ontime_replica` (
  ...
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/ontime/{shard}', '{replica}', FlightDate, (Year, FlightDate), 8192);

其中招刹,{shard}和{replica}是macros配置(相當(dāng)于環(huán)境變量),修改配置文件:

vi /etc/clickhose-server/metrika.xml

添加內(nèi)容:

...
    <macros>
        <shard>01</shard>
        <replica>01</replica>
    </macros>
...

每臺(tái)機(jī)器的shard和replica值根據(jù)具體情況設(shè)置窝趣,例如疯暑,這里是3分片2副本,則配置如下:

hadoop1: shard=01, replica=01
hadoop2: shard=01, replica=02
hadoop3: shard=02, replica=01
hadoop4: shard=02, replica=02
hadoop5: shard=03, replica=01
hadoop6: shard=03, replica=02

使用macros只是為了建表方便(每個(gè)機(jī)器可以使用同樣的建表語(yǔ)句)哑舒,不是必須的妇拯,只要ReplicatedMergeTree指定zk路徑和replica值即可。

由于資源有限,這里不實(shí)驗(yàn)了越锈。

需要提醒一下仗嗦,每個(gè)clickhouse-server實(shí)例只能放一個(gè)分片的一個(gè)備份,也就是3分片2備份需要6臺(tái)機(jī)器(6個(gè)不同的clickhouse-server)甘凭。

之前為了節(jié)省資源稀拐,打算循環(huán)使用,把shard1的兩個(gè)副本放到hadoop1丹弱、hadoop2兩個(gè)機(jī)器上德撬,shard2的兩個(gè)副本放到hadoop2、hadoop3上躲胳,shard3的兩個(gè)副本放到hadoop3蜓洪、hadoop1上,結(jié)果是不行的。

原因是shard+replica對(duì)應(yīng)一個(gè)數(shù)據(jù)表粥鞋,Distributed查詢規(guī)則是每個(gè)shard里找一個(gè)replica啡邑,把結(jié)果合并。

假如按照以上設(shè)置刚操,可能一個(gè)查詢解析結(jié)果為:
取shard1的replica1,對(duì)應(yīng)hadoop1的ontime_replica再芋;
取shard2的replica2菊霜,對(duì)應(yīng)hadoop3的ontime_replica;
取shard3的replica2济赎,對(duì)應(yīng)hadoop1的ontime_replica鉴逞;

最后,得到的結(jié)果是hadoop1的ontime_replica查詢兩次+hadoop3的ontime_replica查詢一次司训,結(jié)果是不正確的构捡。

由于之前用elasticsearch集群,可以用3臺(tái)服務(wù)器來(lái)創(chuàng)建5分片2備份的索引壳猜,所以想當(dāng)然的認(rèn)為clickhouse也可以勾徽,結(jié)果坑了兩天。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末统扳,一起剝皮案震驚了整個(gè)濱河市喘帚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌咒钟,老刑警劉巖吹由,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異朱嘴,居然都是意外死亡倾鲫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)级乍,“玉大人舌劳,你說(shuō)我怎么就攤上這事∶等伲” “怎么了甚淡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)捅厂。 經(jīng)常有香客問(wèn)我贯卦,道長(zhǎng),這世上最難降的妖魔是什么焙贷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任撵割,我火速辦了婚禮,結(jié)果婚禮上辙芍,老公的妹妹穿的比我還像新娘啡彬。我一直安慰自己,他們只是感情好故硅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布庶灿。 她就那樣靜靜地躺著,像睡著了一般吃衅。 火紅的嫁衣襯著肌膚如雪往踢。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天徘层,我揣著相機(jī)與錄音峻呕,去河邊找鬼。 笑死趣效,一個(gè)胖子當(dāng)著我的面吹牛瘦癌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跷敬,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼佩憾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了干花?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤楞黄,失蹤者是張志新(化名)和其女友劉穎池凄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鬼廓,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肿仑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尤慰。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馏锡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伟端,到底是詐尸還是另有隱情杯道,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布责蝠,位于F島的核電站党巾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏霜医。R本人自食惡果不足惜齿拂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肴敛。 院中可真熱鬧署海,春花似錦、人聲如沸医男。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)昨登。三九已至趾代,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丰辣,已是汗流浹背撒强。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笙什,地道東北人飘哨。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像琐凭,于是被迫代替她去往敵國(guó)和親芽隆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容