Clickhouse入門

我們先獲取一些開(kāi)源數(shù)據(jù)樣本集,我們將使用美國(guó)1987到2015年的民用航班數(shù)據(jù),很難稱這個(gè)樣本為大數(shù)據(jù)(只包含1億6千6百萬(wàn)行數(shù)據(jù),未壓縮時(shí)有63GB),但我們能用它很快地開(kāi)干。數(shù)據(jù)可以從這里下載,你也可以從原地址下載,戳這里.

首先,我們將在單臺(tái)服務(wù)器上部署Clickhouse,之后,我們?cè)賮?lái)搞搞如何部署到支持分片和復(fù)制的集群上。

在Ubuntu和Debian上,Clickhouse可以通過(guò)安裝。在其他Linux發(fā)行版上你得自己從源碼編譯安裝。

clickhouse-client這個(gè)包內(nèi)含名為clickhouse-client的應(yīng)用程序——一個(gè)交互式Clickhouse客戶端。clickhouse-server-base包含一個(gè)名為clickhouse-server的二進(jìn)制文件。clickhouse-server-commom包含clickhouse-server的配置文件。

服務(wù)端配置文件在/etc/clickhouse-server/下。在開(kāi)干之前要注意配置文件中的path元素,path決定了數(shù)據(jù)存放的路徑??紤]到包更新的問(wèn)題,直接編輯config.xml文件不是很方便,建議重寫config.d目錄下配置文件中的配置元素。另外,你也可能希望在開(kāi)干前設(shè)置訪問(wèn)權(quán)限。

clickhouse-server服務(wù)不會(huì)在安裝和升級(jí)之后自動(dòng)啟動(dòng)。啟動(dòng)服務(wù)如下:

sudo service clickhouse-server start

服務(wù)器日志文件默認(rèn)存放在/var/log/clickhouse-server/下。服務(wù)器在記錄下“Ready for connections”后便可等待處理客戶端連接請(qǐng)求。

使用clickhouse-client來(lái)連接服務(wù)器。

下面是clickhouse-client的一些用法小提示:

交互模式:

clickhouse-client
clickhouse-client --host=... --port=... --user=... --password=...

開(kāi)啟多行查詢模式:

clickhouse-client -m
clickhouse-client --multiline

在批處理模式下執(zhí)行查詢:

clickhouse-client --query='SELECT 1'
echo 'SELECT 1' | clickhouse-client

從指定格式的文件中插入數(shù)據(jù):

clickhouse-client --query='INSERT INTO table VALUES' < data.txt
clickhouse-client --query='INSERT INTO table FORMAT TabSeparated' < data.tsv

給樣本數(shù)據(jù)庫(kù)創(chuàng)建表

創(chuàng)建表的語(yǔ)句:

$ clickhouse-client --multiline
ClickHouse client version 0.0.53720.
Connecting to localhost:9000.
Connected to ClickHouse server version 0.0.53720.

:) 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(FlightDate, (Year, FlightDate), 8192);

現(xiàn)在我們有了一個(gè)MergeTree類型的表。推薦在生產(chǎn)環(huán)境中使用MergeTree類型的表。這種類型的表有一個(gè)用于增量排序的主鍵,允許通過(guò)主鍵快速執(zhí)行查詢。

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

xz -v -c -d < ontime.csv.xz | clickhouse-client --query="INSERT INTO ontime FORMAT CSV"

Clickhouse的INSERT語(yǔ)句允許以任何支持的格式導(dǎo)入數(shù)據(jù)。數(shù)據(jù)導(dǎo)入只需要O(1)的RAM消耗。INSERT語(yǔ)句可以接受任何大小數(shù)據(jù)量作為輸入。強(qiáng)烈建議不要以太小的數(shù)據(jù)塊插入數(shù)據(jù)。注意,以大小為max_insert_block_size(默認(rèn)為1048576行)的塊進(jìn)行插入是一個(gè)原子操作(即數(shù)據(jù)塊要么完全插入,要么完全不插入)。要是在插入操作的時(shí)候斷開(kāi)了連接,你可能不清楚數(shù)據(jù)塊是否成功插入了。為了實(shí)現(xiàn)妥妥地一次性完工,Clickhouse支持復(fù)制表的冪等性。這意味著你可以重試插入相同的數(shù)據(jù)塊(可能在不同的副本上),但實(shí)際上這個(gè)數(shù)據(jù)塊只插入了一次。由于本指南中是從本地導(dǎo)入數(shù)據(jù),所以暫時(shí)不care數(shù)據(jù)塊生成和一次準(zhǔn)確性問(wèn)題。

用INSERT語(yǔ)句向MergeTree類型表中插數(shù)據(jù)的操作是非阻塞的,SELECT操作也是非阻塞式的,你可以在插入操作后即刻執(zhí)行SELECT查詢。

我們的示例數(shù)據(jù)集有點(diǎn)不太理想,有兩點(diǎn)原因:

第一個(gè)原因是示例中的字符串(String)數(shù)據(jù)用枚舉(Enum)或者數(shù)值類型是最合適的。

當(dāng)要插入的數(shù)據(jù)的可能類別已知并且比較短?。ū热绮僮飨到y(tǒng)的名稱、瀏覽器廠商等信息)時(shí),我們建議使用枚舉或數(shù)值類型可以提高性能。如果數(shù)據(jù)形式不確定(比如搜索查詢、URL等),那就還是用字符串類型吧。

第二個(gè)原因是數(shù)據(jù)集包含了年、季度、月、本月第幾日、本周第幾日等等冗余字段。實(shí)際上,一個(gè)航班日期(Flightdate)就夠了。這么做可能是為了給那些處理日期函數(shù)不得勁兒的數(shù)據(jù)庫(kù)系統(tǒng)提高查詢性能而已。

Clickhouse中處理DateTime字段的函數(shù)是經(jīng)過(guò)優(yōu)化的,所以這種冗余是不需要的。反正有了Clickhouse這種列式數(shù)據(jù)庫(kù),媽媽再也不用擔(dān)心表內(nèi)列數(shù)太多了,想要多少就要多少,大幾百列都是小case。(料理數(shù)據(jù)的家庭主婦們用過(guò)之后都說(shuō):得勁兒?。?/p>

查詢樣本數(shù)據(jù)集

下面是一些對(duì)測(cè)試數(shù)據(jù)的查詢示例。

  • 2015年最受歡迎的目的地
SELECT
    OriginCityName,
    DestCityName,
    count(*) AS flights,
    bar(flights, 0, 20000, 40)
FROM ontime WHERE Year = 2015 GROUP BY OriginCityName, DestCityName ORDER BY flights DESC LIMIT 20
1
1
  • 最受歡迎的出發(fā)城市
SELECT OriginCityName, count(*) AS flights
FROM ontime GROUP BY OriginCityName ORDER BY flights DESC LIMIT 20
2
  • 目的地最多的出發(fā)城市
SELECT OriginCityName, uniq(Dest) AS u
FROM ontime GROUP BY OriginCityName ORDER BY u DESC LIMIT 20
3
  • 周內(nèi)各天的航班延誤
SELECT DayOfWeek, count() AS c, avg(DepDelay >  60) AS delays
FROM ontime GROUP BY DayOfWeek ORDER BY DayOfWeek
4
4
  • 最常延誤1小時(shí)及以上的出發(fā)城市
SELECT OriginCityName, count() AS c, avg(DepDelay >  60) AS delays
FROM ontime
GROUP BY OriginCityName
HAVING c >  100000
ORDER BY delays DESC
LIMIT 20
5
  • 最長(zhǎng)飛行時(shí)間
SELECT OriginCityName, DestCityName, count(*) AS flights, avg(AirTime) AS duration
FROM ontime
GROUP BY OriginCityName, DestCityName
ORDER BY duration DESC
LIMIT 20
6
  • 按航空公司進(jìn)行劃分的到達(dá)時(shí)間延遲分布
SELECT Carrier, count() AS c, round(quantileTDigest(0.99)(DepDelay), 2) AS q
FROM ontime GROUP BY Carrier ORDER BY q DESC
7
  • 停止航班運(yùn)營(yíng)的航空公司
SELECT Carrier, min(Year), max(Year), count()
FROM ontime GROUP BY Carrier HAVING max(Year) < 2015 ORDER BY count() DESC
8
  • 2015年最具趨向目的地城市
SELECT
    DestCityName,
    sum(Year = 2014) AS c2014,
    sum(Year = 2015) AS c2015,
    c2015 / c2014 AS diff
FROM ontime
WHERE Year IN (2014, 2015)
GROUP BY DestCityName
HAVING c2014 >  10000 AND c2015 >  1000 AND diff >  1
ORDER BY diff DESC
9
  • 最受歡迎的季節(jié)性旅游目的地城市
SELECT
    DestCityName,
    any(total),
    avg(abs(monthly * 12 - total) / total) AS avg_month_diff
FROM
(
    SELECT DestCityName, count() AS total
    FROM ontime GROUP BY DestCityName HAVING total > 100000
)
ALL INNER JOIN
(
    SELECT DestCityName, Month, count() AS monthly
    FROM ontime GROUP BY DestCityName, Month HAVING monthly > 10000
)
USING DestCityName
GROUP BY DestCityName
ORDER BY avg_month_diff DESC
LIMIT 20
10

Clickhouse的集群部署

Clickhouse集群是一個(gè)同質(zhì)化(homogenous)集群,構(gòu)建步驟如下:

  1. 在集群每一臺(tái)機(jī)器上都安裝上Clickhouse服務(wù)器
  2. 設(shè)置集群配置文件
  3. 在每個(gè)實(shí)例上創(chuàng)建本地表(local tables)
  4. 創(chuàng)建一個(gè)分布式表

分布式表實(shí)際上是Clickhouse集群本地表的一種“視圖”。對(duì)分布式表的SELECT查詢,會(huì)利用集群所有分片資源進(jìn)行執(zhí)行。你可以配置多個(gè)集群,并創(chuàng)建多個(gè)分布式表,給不同的集群提供視圖。

如下是有三個(gè)分片組成一個(gè)集群的配置文件,每個(gè)分片單獨(dú)存儲(chǔ)一個(gè)數(shù)據(jù)副本

<remote_servers>
    <perftest_3shards_1replicas>
        <shard>
            <replica>
                <host>example-perftest01j.yandex.ru</host>
                <port>9000</port>
            </replica>
        </shard>
        <shard>
            <replica>
                <host>example-perftest02j.yandex.ru</host>
                <port>9000</port>
            </replica>
        </shard>
        <shard>
            <replica>
                <host>example-perftest03j.yandex.ru</host>
                <port>9000</port>
            </replica>
        </shard>
    </perftest_3shards_1replicas>
</remote_servers>

創(chuàng)建一個(gè)本地表:

CREATE TABLE ontime_local (...) ENGINE = MergeTree(FlightDate, (Year, FlightDate), 8192);

創(chuàng)建一個(gè)分布式表,提供到集群本地表的視圖:

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

你可以在集群的所有機(jī)器上創(chuàng)建分布式表。這將允許在任何機(jī)器上運(yùn)行分布式查詢。除了分布式表外,還可以使用“remote”表函數(shù)。

我們來(lái)運(yùn)行INSERT SELECT語(yǔ)句,往分布式表中插入數(shù)據(jù),將表擴(kuò)展到多個(gè)服務(wù)器。

INSERT INTO ontime_all SELECT * FROM ontime;

值得注意的是,上面介紹的方法不適合那些大表分片。請(qǐng)使用內(nèi)置的分片特性

如你所料,重量級(jí)查詢?cè)?臺(tái)服務(wù)器上的執(zhí)行速度比在1臺(tái)機(jī)器上快N倍:


See here

這個(gè)例子中我們使用了包含3個(gè)分片的集群,每個(gè)分片包含了一個(gè)副本。

在生產(chǎn)環(huán)境中為了提供數(shù)據(jù)恢復(fù)能力,我們建議每個(gè)分片最好有2-3個(gè)副本分布到多個(gè)數(shù)據(jù)中心之間。Clickhouse支持無(wú)限數(shù)量的副本。

下面是一個(gè)分片包含三個(gè)副本的集群配置:

<remote_servers>
    ...
    <perftest_1shards_3replicas>
        <shard>
            <replica>
                <host>example-perftest01j.yandex.ru</host>
                <port>9000</port>
             </replica>
             <replica>
                <host>example-perftest02j.yandex.ru</host>
                <port>9000</port>
             </replica>
             <replica>
                <host>example-perftest03j.yandex.ru</host>
                <port>9000</port>
             </replica>
        </shard>
    </perftest_1shards_3replicas>
</remote_servers>

要實(shí)現(xiàn)數(shù)據(jù)復(fù)制,ZooKeeper必不可少。Clickhouse會(huì)照顧到所有副本數(shù)據(jù)的一致性,在運(yùn)行故障發(fā)生后能自動(dòng)恢復(fù)程序。建議吧ZooKeeper集群部署到獨(dú)立的服務(wù)器上。

簡(jiǎn)單起見(jiàn),你可能自己寫程序代碼將數(shù)據(jù)寫到所有副本中來(lái)完成數(shù)據(jù)復(fù)制,那么這就不需要ZooKeeper了。這種做法我們不推薦,因?yàn)檫@種情況下Clickhouse不能保證所有副本的數(shù)據(jù)一致性??茨銌「阍伊宋也回?fù)責(zé)!

在配置文件中設(shè)置ZooKeeper的位置:

<zookeeper-servers>
    <node>
        <host>zoo01.yandex.ru</host>
        <port>2181</port>
    </node>
    <node>
        <host>zoo02.yandex.ru</host>
        <port>2181</port>
    </node>
    <node>
        <host>zoo03.yandex.ru</host>
        <port>2181</port>
    </node>
</zookeeper-servers>

我們還需要設(shè)置確定分片和副本的宏,這在創(chuàng)建表的時(shí)候會(huì)用到。

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

如果復(fù)制表在創(chuàng)建的時(shí)候沒(méi)有副本,首個(gè)新的副本將會(huì)被實(shí)例化。如果已經(jīng)有過(guò)副本,新的副本將從已存在的副本中克隆。你可以先創(chuàng)建所有復(fù)制表,再向其中插入數(shù)據(jù);也可以創(chuàng)建若干副本,再在數(shù)據(jù)插入期間或之后加入其它副本。

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

這里我們使用的是ReplicatedMergeTree表類型。在參數(shù)中我們指定Zookeeper的路徑,其中包含了分片和副本標(biāo)示符。

INSERT INTO ontime_replica SELECT * FROM ontime;

復(fù)制發(fā)生在多主(multi-master)模式下,數(shù)據(jù)可以加載到任何副本中,它將自動(dòng)與其他實(shí)例同步。復(fù)制過(guò)程是異步的,因此在給定的時(shí)刻,并非所有副本都可能包含最近插入的數(shù)據(jù)。為了允許數(shù)據(jù)插入,至少創(chuàng)建一個(gè)副本。一旦其他副本再次可用,將會(huì)同步數(shù)據(jù)并修復(fù)一致性。請(qǐng)注意,這種方案仍存在使剛剛添加的數(shù)據(jù)丟失的可能性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 分布式系統(tǒng)面臨的第一個(gè)問(wèn)題就是數(shù)據(jù)分布,即將數(shù)據(jù)均勻地分布到多個(gè)存儲(chǔ)節(jié)點(diǎn)。另外,為了保證可靠性和可用性,需要將數(shù)據(jù)...
    olostin閱讀 4,906評(píng)論 2 26
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • 《高性能MySQL》&《MySQL技術(shù)內(nèi)幕 InnoDB存儲(chǔ)引擎》筆記 第一章 MySQL架構(gòu)與歷史 MySQL的...
    xiaogmail閱讀 13,095評(píng)論 0 39
  • 漫漫人生路,是你陪我前行,因?yàn)橛心悖?使我一路上勇敢的跨過(guò)人生中的坎坷,披荊斬棘,一路前行。 你是...
    育才中學(xué)初二六班魯杭閱讀 394評(píng)論 0 2
  • 還記得我們剛踏進(jìn)學(xué)校那會(huì)嗎? 那時(shí)候我們就像迷路的小羔羊 身上滿滿的都是稚氣 眼里是前所未有的迷茫和害怕 每個(gè)人心...
    江瀟然閱讀 342評(píng)論 0 1

友情鏈接更多精彩內(nèi)容