Windows10系統下使用Docker搭建ClickHouse開發環境

前提

隨著現在業務開展,幾個業務系統的數據量開始急劇膨脹。之前使用了關係型資料庫MySQL進行了一次數據倉庫的建模,發現了數據量上來後,大量的JOIN操作在提高了雲MySQL的配置後依然有點吃不消,加之開發了一個基於關係型資料庫設計的標籤服務,日全量標籤數據(無法避免的笛卡爾積)單表超過5000W。目前採取了基於用戶ID分段配合多進程處理的方式暫時延緩了性能的惡化,但是考慮到不遠將來,還是需要做一個小型的數據平台。Hadoop的那套體系過於龐大,組件過多,硬體和軟體的學習成本比較高,不是一朝一夕可以讓小團隊的所有成員掌握。考慮到這麼多因素的前提下,需要調研ClickHouse這項黑科技,看看使用他能不能突圍困局。

軟體版本

這裡就不對ClickHouse進行簡介,其官方網站//clickhouse.tech有詳細的文檔。一般使用Windows系統進行開發,如果是Windows10則可以直接安裝Docker,利用Hyper-V的特性直接運行ClickHouse的鏡像即可。下面列出開發環境搭建需要的軟體:

軟體 版本 備註
Windows 10 確保使用了Windows10並且開啟了Hyper-V才能使用Docker
Docker Desktop 任意 DockerWindows桌面版
ClickHouse Server 20.3.x 直接拉取latest的鏡像即可
ClickHouse Client 20.3.x 直接拉取latest的鏡像即可
Cmder 最新版 可選,用來代替自帶的不好用控制台

Windows10下可以通過:控制面板 -> 程式 -> 啟用或關閉Windows功能 -> Hyper-V(勾選Hyper-V管理平台和Hyper-V平台,然後重啟生效)開啟Hyper-V特性:

然後在Docker官方站點的//www.docker.com/get-started子頁面可以找到Docker Desktop的下載入口:

安裝完之後Docker Desktop會隨著系統自啟,軟體介面如下:

安裝和使用ClickHouse

注意需要先初步了解ClickHouse的核心目錄,再進行容器安裝啟動。

鏡像拉取和核心目錄

先下載ClickHouse ServerClickHouse Client的鏡像:

docker pull yandex/clickhouse-server
docker pull yandex/clickhouse-client

下載完畢後提示如下:

可以通過docker images驗證一下:

λ  docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
yandex/clickhouse-server   latest              c85f84ea6550        10 days ago         515MB
yandex/clickhouse-client   latest              f94470cc9cd9        10 days ago         488MB

兩個鏡像其實都是包裹在一個微型的Ubuntu系統中,所以啟動後的容器可以使用當作是一個Linux系統這樣操作。ClickHouse Server在容器中的核心目錄部分如下:

  • /etc/clickhouse-server:這個是ClickHouse Server默認的配置文件目錄,包括全局配置config.xml和用戶配置users.xml等等。
  • /var/lib/clickhouse:這個是ClickHouse Server默認的數據存儲目錄。
  • /var/log/clickhouse-server:這個是ClickHouse Server默認的日誌輸出目錄。

為了方便管理配置、查看數據和搜索日誌,可以把上面這三個目錄直接映射到宿主機的具體目錄,筆者在本開發機做了如下的映射:

Docker容器目錄 宿主機目錄
/etc/clickhouse-server E:/Docker/images/clickhouse-server/single/conf
/var/lib/clickhouse E:/Docker/images/clickhouse-server/single/data
/var/log/clickhouse-server E:/Docker/images/clickhouse-server/single/log

ClickHouse Server啟動前需要注意幾點:

  • ClickHouse Server服務本身依賴三個埠,這三個埠的默認值是9000TCP協議)、8123HTTP協議)和9009(集群數據複製),映射到宿主機的時候儘可能一一對應,所以需要確保宿主機的這三個埠沒有被佔用,可以使用Docker的參數-p指定容器和宿主機的埠映射。
  • ClickHouse Server正常使用需要修改容器系統的文件句柄數量配置ulimit nofile,可以使用Docker參數--ulimit nofile=262144:262144指定文件句柄數。
  • 可以運用一個技巧,使用Docker--rm參數創建臨時容器,先獲取到/etc/clickhouse-server目錄下配置文件,通過docker cp 容器目錄 宿主機目錄命令可以拷貝容器的配置文件到宿主機目錄下,容器停止之後會被直接刪除,這樣就能保留宿主機的配置文件模板。

臨時容器拷貝配置

先執行命令docker run --rm -d --name=temp-clickhouse-server yandex/clickhouse-server運行一個臨時容器,成功後通過下面的命令拷貝容器的config.xmlusers.xml文件到宿主機:

  • docker cp temp-clickhouse-server:/etc/clickhouse-server/config.xml E:/Docker/images/clickhouse-server/single/conf/config.xml
  • docker cp temp-clickhouse-server:/etc/clickhouse-server/users.xml E:/Docker/images/clickhouse-server/single/conf/users.xml

這兩個命令執行完畢後,可以看到宿主機的磁碟目錄已經生成了config.xmlusers.xml,接著需要做幾項配置:

  • 創建default帳號的密碼。
  • 創建一個新的root帳號。
  • 開放客戶端監聽的Host,避免後面使用JDBC客戶端或者ClickHouse Client的時候無法連接ClickHouse Server

通過docker exec -it temp-clickhouse-server /bin/bash命令進入臨時容器,然後在臨時容器中執行:

  • PASSWORD=$(base64 < /dev/urandom | head -c8); echo "default"; echo -n "default" | sha256sum | tr -d '-'
  • PASSWORD=$(base64 < /dev/urandom | head -c8); echo "root"; echo -n "root" | sha256sum | tr -d '-'
root@607c5abcc132:/# PASSWORD=$(base64 < /dev/urandom | head -c8); echo "default"; echo -n "default" | sha256sum | tr -d '-'
default
37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f
root@607c5abcc132:/# PASSWORD=$(base64 < /dev/urandom | head -c8); echo "root"; echo -n "root" | sha256sum | tr -d '-'
root
4813494d137e1631bba301d5acab6e7bb7aa74ce1185d456565ef51d737677b2

這樣就得到了default:defaultroot:root兩個帳號密碼的SHA256摘要。修改宿主機上的users.xml文件:

然後修改宿主機上的config.xml文件:

最後通過docker stop temp-clickhouse-server停止和銷毀臨時容器。

運行ClickHouse服務

接著使用下面的命令創建和運行一個ClickHouse Server容器實例(確保config.xmlusers.xml已經存在):

命名和容器命名:docker run -d --name=single-clickhouse-server 
埠映射:-p 8123:8123 -p 9000:9000 -p 9009:9009 
文件句柄數配置:--ulimit nofile=262144:262144 
數據目錄映射:-v E:/Docker/images/clickhouse-server/single/data:/var/lib/clickhouse:rw 
配置目錄映射:-v E:/Docker/images/clickhouse-server/single/conf:/etc/clickhouse-server:rw 
日誌目錄映射:-v E:/Docker/images/clickhouse-server/single/log:/var/log/clickhouse-server:rw 
鏡像:yandex/clickhouse-server

上面的命令合成一行執行docker run -d --name=single-clickhouse-server -p 8123:8123 -p 9000:9000 -p 9009:9009 --ulimit nofile=262144:262144 -v E:/Docker/images/clickhouse-server/single/data:/var/lib/clickhouse:rw -v E:/Docker/images/clickhouse-server/single/conf:/etc/clickhouse-server:rw -v E:/Docker/images/clickhouse-server/single/log:/var/log/clickhouse-server:rw yandex/clickhouse-server

上面的命令執行完後,Docker Desktop會有幾個彈出框確認是否共享宿主機的目錄,直接按share it按鈕即可。

最後使用原生的命令行客戶端ClickHouse Client進行連接,使用命令docker run -it --rm --link single-clickhouse-server:clickhouse-server yandex/clickhouse-client -uroot --password root --host clickhouse-server

λ  docker run -it --rm --link single-clickhouse-server:clickhouse-server yandex/clickhouse-client -uroot --password root --host clickhouse-server
ClickHouse client version 20.10.3.30 (official build).
Connecting to clickhouse-server:9000 as user root.
Connected to ClickHouse server version 20.10.3 revision 54441.

f5abc88ff7e4 :) select 1;

SELECT 1

┌─1─┐
│ 1 │
└───┘

1 rows in set. Elapsed: 0.004 sec.

下次如果電腦重啟ClickHouse Server的容器沒有啟動,只需要使用命令docker (re)start single-clickhouse-server拉起容器實例即可。

使用JDBC連接ClickHouse服務

ClickHouseJDBC驅動目前有三個:

  • clickhouse-jdbc(官方):地址是//github.com/ClickHouse/clickhouse-jdbc,目前版本是基於Apache Http Client實現。
  • ClickHouse-Native-JDBC(第三方):地址是//github.com/housepower/ClickHouse-Native-JDBC,基於Socket實現。
  • clickhouse4j(第三方):地址是//github.com/blynkkk/clickhouse4j,比官方驅動輕量級。

說實話有點尷尬,官方的驅動包竟然沒有對接TCP私有協議棧,而是使用了HTTP協議進行交互,這裡不知道性能會下降多少,但是基於”官方更好”的思維這裡還是選用官方的驅動包進行Demo演示。引入clickhouse-jdbc依賴:

<dependency>
    <groupId>ru.yandex.clickhouse</groupId>
    <artifactId>clickhouse-jdbc</artifactId>
    <version>0.2.4</version>
</dependency>

編寫一個測試類:

public class ClickHouseTest {

    @Test
    public void testCh() throws Exception {
        ClickHouseProperties props = new ClickHouseProperties();
        props.setUser("root");
        props.setPassword("root");
        // 不創建資料庫的時候會有有個全局default資料庫
        ClickHouseDataSource dataSource = new ClickHouseDataSource("jdbc:clickhouse://localhost:8123/default", props);
        ClickHouseConnection connection = dataSource.getConnection();
        ClickHouseStatement statement = connection.createStatement();
        // 創建一張表,表引擎為Memory,這類表在服務重啟後會自動刪除
        boolean execute = statement.execute("CREATE TABLE IF NOT EXISTS t_test(id UInt64,name String) ENGINE  = Memory");
        if (execute) {
            System.out.println("創建表default.t_test成功");
        } else {
            System.out.println("表default.t_test已經存在");
        }
        ResultSet rs = statement.executeQuery("SHOW TABLES");
        List<String> tables = Lists.newArrayList();
        while (rs.next()) {
            tables.add(rs.getString(1));
        }
        System.out.println("default資料庫中的表:" + tables);
        PreparedStatement ps = connection.prepareStatement("INSERT INTO t_test(*) VALUES (?,?),(?,?)");
        ps.setLong(1, 1L);
        ps.setString(2, "throwable");
        ps.setLong(3, 2L);
        ps.setString(4, "doge");
        ps.execute();
        statement = connection.createStatement();
        rs = statement.executeQuery("SELECT * FROM t_test");
        while (rs.next()) {
            System.out.println(String.format("查詢結果,id:%s,name:%s", rs.getLong("id"), rs.getString("name")));
        }
    }
}

執行結果如下:

表default.t_test已經存在   # <--- 這裡估計是驅動包的實現有BUG,首次創建成功返回結果為false
default資料庫中的表:[t_test]
查詢結果,id:1,name:throwable
查詢結果,id:2,name:doge

小結

ClickHouse開發環境初步搭建完畢,後面會開始學習ClickHouse的基本語法、各類引擎的特性和使用場景以及集群搭建(分片和多副本)等等。

參考資料:

  • //clickhouse.tech

提醒

這個是筆者在某次直接斷電後發現Docker中的ClickHouse服務雖然重啟成功,但是錯誤日誌瘋狂輸出File not found,導致所有客戶端無法連接服務。初步判斷為元數據和實際存儲的數據因為”斷電”後造成不一致導致的。所以建議在開發環境中關機前要先進入容器調用service clickhouse-server stop,然後在宿主機調用docker stop 容器名|容器ID停止容器再進行關機,否則需要遞歸刪除數據目錄下的store目錄中的所有文件才能正常重啟ClickHouse Server和使用(這個是十分粗暴的辦法,有比較大幾率會直接導致數據丟失,一定要謹慎操作)。

(本文完 c-2-d e-a-20201108 開始搞小數據)

個人部落格

Tags: