ClickHouseインストールと設定周りについて

# はじめに

本記事では、ClickHouseを触ったところの導入のところについて記載します。案外日本語記事が少ないので、そのうち淘汰されるうちの1つとして書くことにしました。Clickhouse、SQL初心者ですので間違っている部分が有ると思いますのでご注意ください。

ClickHouseとは、というところについては以下URLを参照してください。各種のDWH DBと比較して大変高速な輝かしい内容が書いてあります。

[Clickhouse公式 Performance comparison of analytical DBMS](https://clickhouse.yandex/benchmark.html)
[MySQLを捨てClickHouseでレポートAPIのレスポンスを1000倍高速化した話](http://tech.geniee.co.jp/entry/2017/07/20/160100)
[Percona社 ClickHouse: New Open Source Columnar Database](https://www.percona.com/blog/2017/02/13/clickhouse-new-opensource-columnar-database/)

# 環境

- 仮想環境
- OS: CentOS7

# インストール

基本的に、インストールの際は以下ドキュメントの内容を行います。

https://clickhouse.yandex/docs/en/getting_started/index.html

## システム要求について

細かい推奨については以下ページに記載されていますが、基本的に必須要件は少ないです。

https://clickhouse.yandex/docs/en/operations/tips.html

- SSE4.2のCPU命令に対応した、Linuxプラットフォーム
- ハイパースレッディングはONが望ましい
- Intel TurboBoostもONが望ましい
- スワップはオフにする
- ファイルシステムはext4が最もテストされているが、他のFSでも良い
- IPv6を使う場合はroute cacheを増やすこと
- ZooKeeperは3.5以上であること(レプリカを作る際に使用する)

## 依存パッケージインストール

RPMインストールについては下記ドキュメントにある、マニュアルインストールを使いました。

```
yum install -y curl
yum install -y pygpgme yum-utils
```

## リポジトリインストール

/etc/yum.repos.d/altinity_clickhouse.repoに以下内容で保存します。なお普段disabledにしてます。

```
[altinity_clickhouse]
name=altinity_clickhouse
baseurl=https://packagecloud.io/altinity/clickhouse/el/$releasever/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=0
gpgkey=https://packagecloud.io/altinity/clickhouse/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300

[altinity_clickhouse-source]
name=altinity_clickhouse-source
baseurl=https://packagecloud.io/altinity/clickhouse/el/$releasever/SRPMS
repo_gpgcheck=1
gpgcheck=0
enabled=0
gpgkey=https://packagecloud.io/altinity/clickhouse/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
```

## インストール

```
yum install -y --enablerepo=altinity_clickhouse 'clickhouse*'
```

# 設定

## ClickHouseのデフォルトのパス構成について(rpmインストール)

|種別|パス|備考|
|---|---|---|
|データディレクトリ |/var/lib/clickhouse/ |データが入ってる|
|ログディレクトリ |/var/log/clickhouse-server/|ログ clickhouse-server.log , clickhouse-server.err.log stderrとstdoutは書かれません|
|コンフィグディレクトリ|/etc/clickhouse-server/|
|メインコンフィグ|/etc/clickhouse-server/config.xml|mysqlならmy.cnfに該当するファイル|
|ユーザ設定|/etc/clickhouse-server/users.xml|DBのユーザ情報や各ユーザの権限やアクセス制限について記載する|

## コンフィグ /etc/clickhouse/config.xml

コンフィグはXMLで書かれています。設定は多くそれを1つの記事に全て書くと長いので、私の環境でデフォルトから変更せざるを得なかった部分だけ記載します。

デフォルトでは127.0.0.1とIPv6の::1でリッスンしようとしますが、IPv6を切っている場合起動しないので追加します。

```
<listen_host>0.0.0.0</listen_host>
```

その他はデフォルトでも動きます。

なお、コンフィグファイルは自動的にリロードされますが、listen_hostやmacrosなどはどうも自動的に認識されていないように見えます。どの設定までが自動的に適用されるかは分かっていません。ソースコードを読んだ方が良さそうです。

## /etc/clickhouse/users.xml

デフォルトでは、ユーザ名default、パスワードなしでログインできます。clickhouse-clientで接続するときのデフォルトユーザ、接続先データベースはdefault,defaultとなります。

以下のようにユーザは設定されます。以下はdefaultとreadonlyという二人のユーザが存在しています。
パスワードと接続可能なネットワーク、後述するQuotaとProfileを設定します。

```
    <users>
        <default>
            <password_sha256_hex>{{ sha256sumコマンドで取得した文字列 }}</password_sha256_hex>
            <networks incl="networks" replace="replace">
                <ip>::/0</ip>
            </networks>
            <profile>default</profile>
            <quota>default</quota>
        </default>

        <readonly>
            <password></password>
            <networks incl="networks" replace="replace">
                <ip>::1</ip>
                <ip>127.0.0.1</ip>
            </networks>
            <profile>readonly</profile>
            <quota>default</quota>
        </readonly>
    </users>
```

パスワードのpassword_sha256_hexの値は以下のようなコマンドで作成可能です。(passwordファイルにパスワードを平文で書いてある想定)

```
PASSWORD=$(cat password); echo -n "$PASSWORD" | sha256sum | tr -d '-'
```

ランダムパスワードの生成(公式、users.xmlに書いてある)

```
PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
```

Quota設定とProfile設定は外だしになっていて、Quotaでは時間当たりのクエリの回数などの制限を、Profileではユーザが読み取り専用なのか、1セッションで使っていいメモリ、プロセッサ数、何行の読み出しが可能かなどの制約を課すことができます。

## 起動

```
service clickhouse-server start
```

# ネイティブクライアントでの接続

clickhouseはデフォルトでは、以下の待ち受けポートで起動します。

- 8123 HTTP接続のためのポート 外部からdbeaverなどで接続するときに使うのが良い
- 9000 ネイティブクライアント用のポート
- 9009 レプリカ通信のためのhttpポート

下記はユーザdefault、データベースdefault、ホストlocalhost、ポート9000で接続します。

```
$ clickhouse-client
:) show processlist;

SHOW PROCESSLIST

Ok.

0 rows in set. Elapsed: 0.002 sec.

:) show databases;

SHOW DATABASES

┌─name────┐
│ default │
│ system  │
└─────────┘

2 rows in set. Elapsed: 0.001 sec.

:) exit
Happy new year.
```

!?こいつ…日付認識して祝ってきやがる…

# テーブル作成について

Clickhouseはテーブル構造のエンジンが複数あります。

https://clickhouse.yandex/docs/en/table_engines/index.html

ログを格納する用途で、1台構成で使う場合は、以下の運用がおすすめらしいとのことです。

1. [MergeTree](https://clickhouse.yandex/docs/en/table_engines/mergetree.html)テーブルを日付付きで作成
2. [Merge](https://clickhouse.yandex/docs/en/table_engines/merge.html)テーブルで、上記日付付きテーブルを含むパターンを指定してViewを作る

MergeTreeテーブルは例えば以下のように作ります。なお、申し訳ないことに、MergeTree()の引数の細かいところは、本記事を書いた時点ではわかっていません。プライマリーキーとDate型の両方でインデクスを作るのがMergeTreeなので、第一引数に[Date型](https://clickhouse.yandex/docs/en/data_types/date.html)が必要です。DateTime型でないことに注意してください。DateTimeで全部やってきたぜ、っていうデータに対してはDate型のカラムを別途作る必要がありそうです。

```
CREATE TABLE access_log_20171221 (
  log_date Date,
  url String,
  referrer String,
  ip String,
  ua String,
  created_at DateTime
) ENGINE = MergeTree(log_date, (log_date, url, referrer, ip, ua, created_at), 8192)
```

次に、Mergeテーブルを作ります。

```
CREATE TABLE access_logs (
  log_date Date,
  url String,
  referrer String,
  ip String,
  ua String,
  created_at DateTime
) ENGINE = Merge(default,'^access_log_.*');
```

Merge()の第一引数はデータベース名、第二引数はマッチするテーブル名のパターンです。これで、以下のようなごく普通のSQLで各日付付きテーブルを横断的に検索することができます。

```
SELECT log_date, url, referrer, ip, ua, created_at
FROM `default`.access_logs;
```

# データの一括投入について

作ったテーブルに対してデータを一括投入するには、例えばTSVファイルがテーブルのカラム順と合っている前提であれば以下のように格納できます。

```
$ cat /tmp/access_log_20171221 | clickhouse-client --query="INSERT INTO access_log_20171221 FORMAT TabSeparated"
```

投入した後、どれくらいのテーブルデータサイズになったかについては、少なくともOSレベルでは以下のように確認できます。

```
$ du --max-depth=1 -h /var/lib/clickhouse/data/default/
12K     /var/lib/clickhouse/data/default/access_log_20171221
```

本記事はここまで。次はレプリケーションを作るための設定とテーブル定義について記事を作る予定です。