基于zookeeper的高可用clickhouse集群搭建

環(huán)境準(zhǔn)備

準(zhǔn)備了4臺(tái)機(jī)器,Centos7.6年栓,可以通過如下命令查看系統(tǒng)版本


image.png

配置hosts

vim /etc/hosts

編輯hosts文件峻呕,新增機(jī)器hostname與ip的匹配關(guān)系范嘱,每臺(tái)機(jī)器上都要填寫集群的4臺(tái)機(jī)器的配置關(guān)系。

單機(jī)安裝clickhouse

通過https://repo.yandex.ru/clickhouse/rpm/stable/x86_64下載如下文件清單

image.png

使用sudo rpm -ivh xxxx.rpm命令安裝所有文件

sudo rpm -ivh clickhouse-common-static-19.17.6.36-2.x86_64.rpm
sudo rpm -ivh clickhouse-common-static-dbg-19.17.6.36-2.x86_64.rpm
sudo rpm -ivh clickhouse-server-19.17.6.36-2.noarch.rpm
sudo rpm -ivh clickhouse-client-19.17.6.36-2.noarch.rpm

安裝完成后普碎,通過service clickhouse-server start命令啟動(dòng)clickhouse服務(wù)
通過clickhouse-client命令連接到服務(wù)吼肥,使用service clickhouse-server stop命令停止服務(wù)。

安裝成功后,部分重要文件的默認(rèn)路徑如下:
服務(wù)器配置文件:/etc/clickhouse-server/config.xml
用戶配置文件:/etc/clickhouse-server/users.xml
數(shù)據(jù)存放路徑(可修改):/var/lib/clickhouse/
日志存放路徑(可修改):/var/log/clickhouse-server/

需要修改如下的配置信息:

  1. 開放遠(yuǎn)程登錄
    默認(rèn)情況下clickhouse服務(wù)僅支持本地登錄(localhost:9000)潜沦,開放遠(yuǎn)程登錄需要修改/etc/clickhouse-server/config.xml文件萄涯。在命令行客戶端使用命令vim /etc/clickhouse-server/config.xml打開文件,找到listen_host節(jié)點(diǎn)唆鸡,取消注釋涝影,保存后退出。
  1. 修改使用內(nèi)存的上限
    ClickHouse默認(rèn)配置允許使用的內(nèi)容只有不到10G争占,超過該數(shù)值大小的表格將無法進(jìn)行關(guān)聯(lián)燃逻、聚合等操作,可根據(jù)服務(wù)器實(shí)際內(nèi)存大小修改該配置臂痕,打開/etc/clickhouse-server/users.xml文件伯襟,找到max_menory_usage節(jié)點(diǎn),修改后保存退出握童。

  2. 修改或者添加賬戶
    Clickhouse服務(wù)默認(rèn)賬戶為default姆怪,無密碼登錄。如需要修改默認(rèn)賬戶或者添加新賬戶澡绩,請(qǐng)打開/etc/clickhouse-server/users.xml文件稽揭,找到users節(jié)點(diǎn),將其下屬的default節(jié)點(diǎn)注釋掉肥卡,新增test節(jié)點(diǎn)如下圖溪掀,保存后退出。

安裝zookeeper

clickhouse在支持MergeTree引擎的表級(jí)別自動(dòng)備份步鉴,這個(gè)功能是通過zookeeper來實(shí)現(xiàn)的揪胃。副本是表級(jí)別的,不是整個(gè)服務(wù)器級(jí)的氛琢。所以喊递,服務(wù)器里可以同時(shí)有復(fù)制表和非復(fù)制表。副本不依賴分片阳似。每個(gè)分片有它自己的獨(dú)立副本骚勘。
此外,該功能要求zookeeper 3.4.5或更高版本障般。具體安裝過程略调鲸。

clickhouse集群安裝及配置

按照上面按照單機(jī)clickhouse的步驟,在其余3臺(tái)機(jī)器上也分別安裝clickhouse挽荡,然后進(jìn)行集群配置藐石。
集群配置可以在config.xml編輯,但推薦通過 編輯/etc/metrika.xml配置集群定拟,在clickhouse官方文檔中有如下描述

The config can also define “substitutions”. If an element has the incl attribute, the corresponding substitution from the file will be used as the value. By default, the path to the file with substitutions is /etc/metrika.xml. This can be changed in the include_from element in the server config. The substitution values are specified in /yandex/substitution_name elements in this file. If a substitution specified in incl does not exist, it is recorded in the log. To prevent ClickHouse from logging missing substitutions, specify the optional="true"attribute (for example, settings for macros).

簡(jiǎn)單來講就是對(duì)于config.xml中帶有 'incl'標(biāo)識(shí)的屬性于微,可以在另外的配置文件中修改該屬性的值逗嫡,而另外的配置文件的默認(rèn)路徑就是/etc/metrika.xml。
集群采用2個(gè)分片2個(gè)副本的配置方式株依,


image.png

兩個(gè)shard(shardA,shardB),每個(gè)shard 有2個(gè)replica,比如shardA有(A,A1)和shardB有(B,B1)驱证。
具體的配置信息如下:

<yandex>
<clickhouse_remote_servers>
<cluster_2shards_2replicas>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>host1</host>
<port>9000</port>
</replica>
<replica>
<host>host2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>host3</host>
<port>9000</port>
</replica>
<replica>
<host>host4</host>
<port>9000</port>
</replica>
</shard>
</cluster_2shards_2replicas>
</clickhouse_remote_servers>


<!--zookeeper相關(guān)配置-->
<zookeeper-servers>
<node index="1">
<host>host1</host>
<port>2181</port>
</node>
<node index="2">
<host>host2</host>
<port>2181</port>
</node>
<node index="3">
<host>host3</host>
<port>2181</port>
</node>
<node index="4">
<host>host4</host>
<port>2181</port>
</node>
</zookeeper-servers>




<macros>
<layer>01</layer>
<shard>01</shard>
<replica>cluster_116_01_02</replica>
</macros>

<networks>
<ip>::/0</ip>
</networks>

<clickhouse_compression>
<case>
<min_part_size>10000000000</min_part_size>
<min_part_size_ratio>0.01</min_part_size_ratio>
<method>lz4</method>
</case>
</clickhouse_compression>

</yandex>

其中需要注意的是<internal_replication>true</internal_replication>,true代表當(dāng)我們插入數(shù)據(jù)是恋腕,clickhouse只需要負(fù)責(zé)插入兩個(gè)shard中的一個(gè)副本就可以抹锄,另外一個(gè)副本的數(shù)據(jù)由zookeeper負(fù)責(zé)同步,這樣就可以保證當(dāng)其中的某個(gè)副本實(shí)例宕機(jī)時(shí)的數(shù)據(jù)一致性荠藤。
另外在macros的部分是宏配置伙单,這樣在建立ReplicatedMergeTree的表時(shí)就不用在每個(gè)實(shí)例上一一執(zhí)行建表語句,只需要在一個(gè)實(shí)例上執(zhí)行就可以哈肖。

數(shù)據(jù)測(cè)試

按照官方文檔樣例吻育,先下載示例數(shù)據(jù)
官方鏈接

for s in `seq 1987 2018`
do
for m in `seq 1 12`
do
wget https://transtats.bts.gov/PREZIP/On_Time_Reporting_Carrier_On_Time_Performance_1987_present_${s}_${m}.zip
done
done

該樣例數(shù)據(jù)大約有幾十個(gè)G,我只下載了其中一個(gè)月的數(shù)據(jù)作為測(cè)試
建表

CREATE TABLE `ontime` (
  `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
PARTITION BY Year
ORDER BY (Carrier, FlightDate)
SETTINGS index_granularity = 8192;

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

for i in *.zip; do echo $i; unzip -cq $i '*.csv' | sed 's/\.00//g' | clickhouse-client --host=example-perftest01j --query="INSERT INTO ontime FORMAT CSVWithNames"; done

建立ReplicatedMergeTree表

CREATE TABLE IF NOT EXISTS dwhtl.ontime_replica ON CLUSTER cluster_2shards_2replicas (
`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 = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/ontime_replica', '{replica}')
PARTITION BY FlightDate
ORDER BY (Year,FlightDate) 
SETTINGS index_granularity = 8192;

復(fù)制表引擎:ReplicatedMergeTree('shard_name','replicate_name')
如上淤井,復(fù)制表要指定兩個(gè)參數(shù)布疼。

  1. 當(dāng)前本地復(fù)制表實(shí)例所屬的分片服務(wù)名稱。
    分片服務(wù)名是zookeeper上的目錄名稱币狠,如果你知道zookeeper實(shí)現(xiàn)的統(tǒng)一命名服務(wù)游两,那就好理解了,類似dubbo的服務(wù)提供者在zookeeper注冊(cè)的服務(wù)名总寻。在dubbo中同一個(gè)服務(wù)名有多個(gè)實(shí)例提供相同的服務(wù)器罐。服務(wù)調(diào)用者只需要通過服務(wù)名就能夠獲取到該服務(wù)的所有實(shí)例的信息梢为。復(fù)制表這和dubbo差不多渐行。分片服務(wù)名就是在zookeeper上注冊(cè)的服務(wù)提供者名稱。多個(gè)復(fù)制表的該名稱如果一樣铸董,那么這些復(fù)制表都屬于同一個(gè)分片服務(wù)祟印,只不過表示不同副本而已。同一個(gè)分片服務(wù)的不同副本之間數(shù)據(jù)會(huì)相互同步粟害,保持一致蕴忆。
  2. 當(dāng)前這張表所屬的副本名稱。如果第一個(gè)參數(shù)相同悲幅,當(dāng)前第二個(gè)參數(shù)需要不同套鹅。

復(fù)制表機(jī)制就僅僅只是提供一種副本機(jī)制。屬于同一個(gè)分片服務(wù)的不同復(fù)制表之間會(huì)相互同步數(shù)據(jù)汰具。但在查詢某個(gè)副本時(shí)卓鹿,這個(gè)副本宕機(jī)了還無法把這個(gè)查詢自動(dòng)切換到其他副本查詢。需要重新去另外一個(gè)未宕機(jī)的副本實(shí)例上查詢那個(gè)副本對(duì)應(yīng)的本地復(fù)制表留荔。雖然不同副本的數(shù)據(jù)是一樣的吟孙,但對(duì)用戶來說,某個(gè)副本宕機(jī)了還需要手動(dòng)切換查詢的副本實(shí)例。
如果要做到在某個(gè)副本宕機(jī)時(shí)自動(dòng)切換到其他可用副本杰妓,那么就需要結(jié)合Distributed分布式表進(jìn)行使用了

建立Distributed分布式表(可以理解為視圖)

 CREATE TABLE ontime_all AS ontime_replica
ENGINE = Distributed(cluster_2shards_2replicas, dwhtl, ontime_replica, rand())

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

insert into ontime_all select * from ontime

在每個(gè)節(jié)點(diǎn)上登錄clickhouse查詢驗(yàn)證數(shù)據(jù)藻治。
然后關(guān)閉其中一個(gè)節(jié)點(diǎn)后,ontime仍可查詢并且數(shù)據(jù)記錄完整巷挥。
向OnTime表再插入1000條數(shù)據(jù)桩卵,然后再啟動(dòng)剛才關(guān)閉的節(jié)點(diǎn),驗(yàn)證zookeeper的自動(dòng)同步功能

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末倍宾,一起剝皮案震驚了整個(gè)濱河市吸占,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凿宾,老刑警劉巖矾屯,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異初厚,居然都是意外死亡件蚕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門产禾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來排作,“玉大人,你說我怎么就攤上這事亚情⊥荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵楞件,是天一觀的道長(zhǎng)衫生。 經(jīng)常有香客問我,道長(zhǎng)土浸,這世上最難降的妖魔是什么罪针? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮黄伊,結(jié)果婚禮上泪酱,老公的妹妹穿的比我還像新娘。我一直安慰自己还最,他們只是感情好墓阀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拓轻,像睡著了一般斯撮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悦即,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天吮成,我揣著相機(jī)與錄音橱乱,去河邊找鬼。 笑死粱甫,一個(gè)胖子當(dāng)著我的面吹牛泳叠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茶宵,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼危纫,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了乌庶?” 一聲冷哼從身側(cè)響起种蝶,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞒大,沒想到半個(gè)月后螃征,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡透敌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年盯滚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酗电。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魄藕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撵术,到底是詐尸還是另有隱情背率,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布嫩与,位于F島的核電站寝姿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蕴纳。R本人自食惡果不足惜会油,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一个粱、第九天 我趴在偏房一處隱蔽的房頂上張望古毛。 院中可真熱鬧,春花似錦都许、人聲如沸稻薇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)塞椎。三九已至,卻和暖如春睛低,著一層夾襖步出監(jiān)牢的瞬間案狠,已是汗流浹背服傍。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骂铁,地道東北人吹零。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拉庵,于是被迫代替她去往敵國(guó)和親灿椅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355