
閱讀此文,你將得到什么:
ClickHouse安裝的2種方法,以及背后的坑
一步步幫你實現(xiàn)ClickHouse從單機到集群化,以及集群化的原理、配置文件等
集群化的2種方案,孰優(yōu)孰劣
如有疑問,請留言或者聯(lián)系我
組件介紹
- ClickHouse安裝完后,會有幾個重要命令:
- clickhouse-server ClickHouse的Server端,也就是CK數(shù)據(jù)庫的核心程序,相當(dāng)于mysqld命令,提供數(shù)據(jù)庫服務(wù)端
- clickhouse-client ClickHouse自帶的client端,提供命令行的交互操作方式,來連接服務(wù)端,相當(dāng)于mysql命令
Docker安裝
-
官方默認只支持Ubuntu,并且提供了Docker鏡像:
-
Docker安裝很方便,但是有幾個問題:
- 默認監(jiān)聽了IPv6,如果你的服務(wù)器恰好沒有開啟V6,會導(dǎo)致Docker啟動失敗的
- 解決方案:使用Docker命令,cp出默認的配置文件,修改network監(jiān)聽后,拷回Docker,重新啟動即可
- 默認時區(qū)問題并不是東八區(qū),如果沒有修改,一些時間函數(shù)會差8個小時
- clickhouse-client在Docker下,無法正常輸入中文(調(diào)了LANG,無效,如果搞定記得告訴我)
- 數(shù)據(jù)目錄如果有要求,額外在Docker啟動的時候,掛載一下
- 配置文件不方便修改
- 默認監(jiān)聽了IPv6,如果你的服務(wù)器恰好沒有開啟V6,會導(dǎo)致Docker啟動失敗的
-
建議調(diào)整:
- 掛載本地服務(wù)器時區(qū),或者直接修改Docker里的時區(qū)文件
- 拷貝所有配置文件到服務(wù)器目錄,啟動時做映射,方便修改
- 映射一個專用的數(shù)據(jù)目錄
由于Docker方式我并不在線上采用,這里不再舉例。建議僅僅作為筆記本上測試、了解用(不過前期,沒有找到rpm包,Docker的確幫了我們很大的忙)。
RPM包安裝
不出意外的話,99%的服務(wù)器都是CentOS系列
官方?jīng)]有提供rpm包,但是Altinity公司提供了,關(guān)于這個公司的介紹,可以參照我其他文章
如果下載不了,看我的百度網(wǎng)盤,密碼yv72(我這里好久沒更新了,請注意看版本)
CentOS推薦7.3以上,基本沒有依賴包的問題
rpm -ivh * 即可安裝完成
配置文件解析
-
ClickHouse有幾核心的配置文件:
- config.xml 端口配置、本地機器名配置、內(nèi)存設(shè)置等
- metrika.xml 集群配置、ZK配置、分片配置等
- users.xml 權(quán)限、配額設(shè)置
以上文件都可以在官方git下載到
rpm啟動方式
- rpm安裝后,會在服務(wù)器上生成如下幾個文件:
# 默認配置文件位置
root@localhost.localdomain:/ # ls /etc/clickhouse-server
config.xml users.xml
# 上述文件定義了默認數(shù)據(jù)目錄,臨時目錄位置,日志目錄
/var/lib/clickhouse
/var/lib/clickhouse/tmp/
/var/log/clickhouse-server
# 默認啟動腳本,注意,這個名字雖然叫server,其實是個shell腳本
/etc/rc.d/init.d/clickhouse-server
root@localhost.localdomain:/ # file /etc/rc.d/init.d/clickhouse-server
/etc/rc.d/init.d/clickhouse-server: POSIX shell script, ASCII text executable, with very long lines
# 最大文件打開數(shù)
root@localhost.localdomain:/ # cat /etc/security/limits.d/clickhouse.conf
clickhouse soft nofile 262144
clickhouse hard nofile 262144
# 默認crontab目錄(沒啥用)
/etc/cron.d/clickhouse-server
# 剩下就是/usr/bin下的二進制文件,但其實都是軟鏈接到了clickhouse這個二進制文件
root@localhost.localdomain:/usr/bin # ll | grep click -i
-rwxr-xr-x 1 root root 63M Sep 20 16:58 clickhouse
lrwxrwxrwx 1 root root 10 Dec 11 17:14 clickhouse-client -> clickhouse
-rwxr-xr-x 1 root root 3.3M Sep 20 16:58 clickhouse-compressor
lrwxrwxrwx 1 root root 10 Dec 11 17:14 clickhouse-server -> clickhouse
- 知道上述幾個文件的作用后,我們就知道該怎么做了
默認的數(shù)據(jù)目錄明顯不合理,特別是對于部分機器,系統(tǒng)盤和數(shù)據(jù)盤是不同的配置,需要單獨掛載,以我們?yōu)槔?,我們統(tǒng)一使用/data1來放數(shù)據(jù),數(shù)據(jù)目錄以clickhouse命名,考慮到不用單機多實例,不以clickhouse${port}來命名
默認的配置文件,對我們的管理也是個隱患,建議把配置文件、數(shù)據(jù)目錄、臨時目錄、日志文件,統(tǒng)一放到/data1/clickhouse里,即:
root@localhost.localdomain:/data1/clickhouse # tree . -L 1
.
├── config-preprocessed.xml
├── config.xml
├── cores
├── data
├── flags
├── log
├── metadata
├── metrika.xml
├── start_ck.sh
├── status
├── tmp
├── users-preprocessed.xml
└── users.xml
- 關(guān)于如何啟動,我們的做法是:
-
修改默認的shell腳本,修改默認配置文件的位置,即上面的start_ck.sh
[圖片上傳中...(Snip20171212_37.png-4c0f8a-1513094816911-0)]
Snip20171212_36.png
-
- 這里其實是可以直接使用clickhouse-server(二進制那個),并采用-d參數(shù)啟動的,但是實際過程,遇到了很多意外的情況,比如-d后,并不會以daemon方式啟動,后來就不考慮直接命令行方式了
- 修改config.xml里對數(shù)據(jù)目錄的定義
<?xml version="1.0"?>
<yandex>
<!-- 日志 -->
<logger>
<level>trace</level>
<log>/data1/clickhouse/log/server.log</log>
<errorlog>/data1/clickhouse/log/error.log</errorlog>
<size>1000M</size>
<count>10</count>
</logger>
<!-- 端口 -->
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<interserver_http_port>9009</interserver_http_port>
<!-- 本機域名 -->
<interserver_http_host>這里需要用域名,如果后續(xù)用到復(fù)制的話</interserver_http_host>
<!-- 監(jiān)聽IP -->
<listen_host>0.0.0.0</listen_host>
<!-- 最大連接數(shù) -->
<max_connections>64</max_connections>
<!-- 沒搞懂的參數(shù) -->
<keep_alive_timeout>3</keep_alive_timeout>
<!-- 最大并發(fā)查詢數(shù) -->
<max_concurrent_queries>16</max_concurrent_queries>
<!-- 單位是B -->
<uncompressed_cache_size>8589934592</uncompressed_cache_size>
<mark_cache_size>10737418240</mark_cache_size>
<!-- 存儲路徑 -->
<path>/data1/clickhouse/</path>
<tmp_path>/data1/clickhouse/tmp/</tmp_path>
<!-- user配置 -->
<users_config>users.xml</users_config>
<default_profile>default</default_profile>
<log_queries>1</log_queries>
<default_database>default</default_database>
<remote_servers incl="clickhouse_remote_servers" />
<zookeeper incl="zookeeper-servers" optional="true" />
<macros incl="macros" optional="true" />
<!-- 沒搞懂的參數(shù) -->
<builtin_dictionaries_reload_interval>3600</builtin_dictionaries_reload_interval>
<!-- 控制大表的刪除 -->
<max_table_size_to_drop>0</max_table_size_to_drop>
<include_from>/data1/clickhouse/metrika.xml</include_from>
</yandex>
單機
無需多解釋,就是單機部署
按照上述方式安裝rpm包,修改默認的config文件和啟??刂颇_本,啟動即可
我上面的配置文件里,直接包含了集群的配置文件,如果只用了上述文件,是無法正常啟動的
看這個文章的,應(yīng)該都是沖著后面的集群搭建來的吧,所以,忽略這一個吧
分布式集群
CK是如何實現(xiàn)分布式的
CK的分布式,完全依賴配置文件,即每個節(jié)點,都共享同樣的配置文件,這個配置文件里,寫了我跟誰是一個cluster的,我自己的名字是啥
如下面的配置文件里,有3個分片,各自用域名來標(biāo)記,如果需要密碼的話,集群也要寫上明文密碼和用戶名
這樣,就行程了ClickHouse的集群
-
集群怎么用?
- 答案是指定引擎
- CK里的引擎有十幾個,這里只推薦3個:
- MergeTree,是CK里最A(yù)dvanced的引擎,性能超高,單機寫入可以達到50w峰值,查詢性能非常快,有興趣看我其他文章
- ReplicatedMergeTree,基于MergeTree,同時引入ZK,做了復(fù)制,下文會說
- Distributed,分布式引擎,本身不存儲數(shù)據(jù),可認為就是一張View,如果寫入,會把請求丟到集群里的節(jié)點(有算法控制),如果查詢,會幫你做查詢轉(zhuǎn)發(fā)再聚合返回
- metrika.xml
<yandex>
<!-- 集群配置 -->
<clickhouse_remote_servers>
<bip_ck_cluster>
<!-- 數(shù)據(jù)分片1 -->
<shard>
<internal_replication>false</internal_replication>
<replica>
<host>ck31.xxxx.com.cn</host>
<port>9000</port>
<user>default</user>
<password>6lYaUiFi</password>
</replica>
</shard>
<!-- 數(shù)據(jù)分片2 -->
<shard>
<internal_replication>false</internal_replication>
<replica>
<host>ck32.xxxx.sina.com.cn</host>
<port>9000</port>
<user>default</user>
<password>6lYaUiFi</password>
</replica>
</shard>
<!-- 數(shù)據(jù)分片3 -->
<shard>
<internal_replication>false</internal_replication>
<replica>
<host>ck33.xxxxa.com.cn</host>
<port>9000</port>
<user>default</user>
<password>6lYaUiFi</password>
</replica>
</shard>
</bip_ck_cluster>
</clickhouse_remote_servers>
<!-- 本節(jié)點副本名稱(這里無用) -->
<macros>
<replica>ck1</replica>
</macros>
<!-- 監(jiān)聽網(wǎng)絡(luò)(貌似重復(fù)) -->
<networks>
<ip>::/0</ip>
</networks>
<!-- ZK -->
<zookeeper-servers>
<node index="1">
<host>1.xxxx.sina.com.cn</host>
<port>2181</port>
</node>
<node index="2">
<host>2.xxxx.sina.com.cn</host>
<port>2181</port>
</node>
<node index="3">
<host>3.xxxxp.sina.com.cn</host>
<port>2181</port>
</node>
</zookeeper-servers>
<!-- 數(shù)據(jù)壓縮算法 -->
<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>
- user.xml
- 關(guān)于用戶名密碼的問題,在另一篇文章有解釋,這里只貼上配置文件
<?xml version="1.0"?>
<yandex>
<profiles>
<!-- 讀寫用戶設(shè)置 -->
<default>
<max_memory_usage>10000000000</max_memory_usage>
<use_uncompressed_cache>0</use_uncompressed_cache>
<load_balancing>random</load_balancing>
</default>
<!-- 只寫用戶設(shè)置 -->
<readonly>
<max_memory_usage>10000000000</max_memory_usage>
<use_uncompressed_cache>0</use_uncompressed_cache>
<load_balancing>random</load_balancing>
<readonly>1</readonly>
</readonly>
</profiles>
<!-- 配額 -->
<quotas>
<!-- Name of quota. -->
<default>
<interval>
<duration>3600</duration>
<queries>0</queries>
<errors>0</errors>
<result_rows>0</result_rows>
<read_rows>0</read_rows>
<execution_time>0</execution_time>
</interval>
</default>
</quotas>
<users>
<!-- 讀寫用戶 -->
<default>
<password_sha256_hex>967f3bf355dddfabfca1c9f5cab39352b2ec1cd0b05f9e1e6b8f629705fe7d6e</password_sha256_hex>
<networks incl="networks" replace="replace">
<ip>::/0</ip>
</networks>
<profile>default</profile>
<quota>default</quota>
</default>
<!-- 只讀用戶 -->
<ck>
<password_sha256_hex>967f3bf355dddfabfca1c9f5cab39352b2ec1cd0b05f9e1e6b8f629705fe7d6e</password_sha256_hex>
<networks incl="networks" replace="replace">
<ip>::/0</ip>
</networks>
<profile>readonly</profile>
<quota>default</quota>
</ck>
</users>
</yandex>
簡單分布式方案
- MergeTree + Distributed
CREATE TABLE db.tb (date Date, ……) ENGINE = MergeTree(date, (date, hour, datetime), 8192)
CREATE TABLE db.tb_all (date Date, ……) ENGINE = Distributed(bip_ck_cluster, 'ck_test', 'dagger', rand())"
db.tb為本地表,數(shù)據(jù)只是在本地
db.tb_all為分布式表,查詢這個表,引擎自動把整個集群數(shù)據(jù)計算后返回
像不像一臺手動擋的車
分布式+高可用方案1
上述方案,使用過后,會發(fā)現(xiàn)CK的性能真的是超級快,這里我就不在貼圖了,有興趣可以看我那122頁的PPT
但是有個問題,以上面3個節(jié)點為例,每個節(jié)點占1/3,如果宕機1個節(jié)點,直接丟掉1/3的數(shù)據(jù),不能忍啊
于是,就得考慮數(shù)據(jù)的安全性,即副本
MergeTree + Distributed + 集群復(fù)制
-
配置如下:
Snip20170901_27 解釋都在圖里了,提一點,如果IP1掛了,IP2還在,不影響集群查詢
-
這種方案為什么我們沒有用呢?
- 如果IP1臨時宕機,從宕機開始到恢復(fù),期間的增量數(shù)據(jù)是可以補全的,依賴的IP2上的推送機制,會有臨時目錄
- 但是,如果IP1徹底玩完,硬盤壞了,無法恢復(fù),只能重做,引入一個IP5來替換IP1,這時候問題就來了,存量數(shù)據(jù)無法恢復(fù)
- 這個方案之前有過爭議,我堅持上面的觀點,由于時間有限,沒有詳細測試,從CK原理上來講,的確存在上述的問題,所以我們不用
分布式+高可用方案2
- ReplicatedMergeTree + Distributed
- 僅僅是把MergeTree引擎替換為ReplicatedMergeTree引擎
- ReplicatedMergeTree里,共享同一個ZK路徑的表,會相互,注意是,相互同步數(shù)據(jù)
CREATE TABLE db.tb (date Date, ……) ENGINE = ReplicatedMergeTree('/clickhouse/db/tb/name', 'node_name', date, (date, hour, datetime), 8192)
CREATE TABLE db.tb_all (date Date, ……) ENGINE = Distributed(bip_ck_cluster, 'ck_test', 'dagger', rand())"
-
示意圖架構(gòu)就是這樣:
Snip20171212_37.png
- 每個IDC有3個分片,各自占1/3數(shù)據(jù)
- 每個節(jié)點,依賴ZK,各自有2個副本
- 這樣,就不怕宕機啦~
CK分布式的問題
- 寫哪個表
- 可以寫xxx_all,也可以寫xxx本地表
- 前者由于分布式表的邏輯簡單,僅僅是轉(zhuǎn)發(fā)請求,所以在轉(zhuǎn)發(fā)安全性上,會有風(fēng)險,并且rand的方式,可能會造成不均衡
- 我們建議,通過DNS輪訓(xùn),寫本地表,這樣最保險和均衡
- 讀哪個表
- 毫無疑問,是xxx_all表
- 3個節(jié)點,要么都用,要么都不用,不能只用2個或者1個
- 集群配置里,我們用了域名,本想著方便切換,但是CK只有在啟動的時候,才會做解析
- 那故障了怎么切換?
- CK有一個厲害的地方,節(jié)點變動,無需重啟,會自動加載
- 利用上述特性,我們先去掉一個節(jié)點的配置,再加上這個節(jié)點的配置(DNS變更后),即可不重啟就完成fail over
總結(jié)
- ClickHouse的性能令人印象深刻,但是,整個操作,又非常像一臺手動擋的車,如果不是老司機,用著用著可能數(shù)據(jù)都沒了,所以,掌握好原理,是開好這輛“超跑”的關(guān)鍵
- 上述集群中,你是否覺得表管理非常麻煩呢?的確,又要區(qū)分集群,又要區(qū)分副本,建議寫一個腳本來統(tǒng)一建表,我們就是這么搞的


