Apache Cassandra


# はじめに

動作確認する必要ができたので構築してみました。

# 環境

3 台の CentOS マシンを使用します。

|ホスト名  |IP アドレス  | |
|---|---|---|
|kwcassandra01  |10.1.0.145  |Seed Node|
|kwcassandra02  |10.1.0.146  | |
|kwcassandra03  |10.1.0.147  | |

OS は CentOS 7.8 です。

```
# cat /etc/*release
CentOS Linux release 7.8.2003 (Core)
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

CentOS Linux release 7.8.2003 (Core)
CentOS Linux release 7.8.2003 (Core)
#
```

SELinux は無効化しています。

```
# getenforce
Disabled
#
```

Firewall も無効化しています。Firewall 環境では 7000、7001、7199 および 9042 を空けとく必要があります ( https://cassandra.apache.org/doc/latest/faq/index.html?highlight=port )。

```
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
# 
```

# インストール

https://cassandra.apache.org/download/ に書かれている手順をベースにインストールします。

Cassandra のリポジトリを登録します。

```
# vi /etc/yum.repos.d/cassandra.repo
# cat /etc/yum.repos.d/cassandra.repo
[cassandra]
name=Apache Cassandra
baseurl=https://www.apache.org/dist/cassandra/redhat/311x/
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://www.apache.org/dist/cassandra/KEYS
#
```

yum コマンドでインストールします。

```
# yum install -y cassandra

...色々出力されますが省略...

Complete!
# 
```

# 構成

Cassandra の構成ファイル /etc/cassandra/conf/cassandra.yaml を編集します。
今回は以下のパラメータを編集しています。

[cluster_name](https://cassandra.apache.org/doc/latest/configuration/cass_yaml_file.html#cluster-name) : Cassandra クラスタの名前を指定します。デフォルトの値 (Test Cluster) でも起動します。

```
# The name of the cluster. This is mainly used to prevent machines in
# one logical cluster from joining another.
cluster_name: 'Cluster'
```

[seed_provider (seeds)](https://cassandra.apache.org/doc/latest/configuration/cass_yaml_file.html#seed-provider) : Seed Node を指定します。今回は kwcassandra01 (10.1.0.145) を Seed Node としています。

```
# any class that implements the SeedProvider interface and has a
# constructor that takes a Map<String, String> of parameters will do.
seed_provider:
    # Addresses of hosts that are deemed contact points.
    # Cassandra nodes use this list of hosts to find each other and learn
    # the topology of the ring.  You must change this if you are running
    # multiple nodes!
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          # seeds is actually a comma-delimited list of addresses.
          # Ex: "<ip1>,<ip2>,<ip3>"
          - seeds: "10.1.0.145"
```

[listen_address](https://cassandra.apache.org/doc/latest/configuration/cass_yaml_file.html#listen-address) : 他のホストから接続を受け付ける IP アドレスを指定します。各ホストの IP アドレスを指定します。

```
# Address or interface to bind to and tell other Cassandra nodes to connect to.
# You _must_ change this if you want multiple nodes to be able to communicate!
#
# Set listen_address OR listen_interface, not both.
#
# Leaving it blank leaves it up to InetAddress.getLocalHost(). This
# will always do the Right Thing _if_ the node is properly configured
# (hostname, name resolution, etc), and the Right Thing is to use the
# address associated with the hostname (it might not be).
#
# Setting listen_address to 0.0.0.0 is always wrong.
#
listen_address: 10.1.0.145
```

[rpc_address](https://cassandra.apache.org/doc/latest/configuration/cass_yaml_file.html#rpc-address) : クライアントからの接続を受け付ける IP アドレスを指定します。各ホストの IP アドレスを指定します。

```
# The address or interface to bind the Thrift RPC service and native transport
# server to.
#
# Set rpc_address OR rpc_interface, not both.
#
# Leaving rpc_address blank has the same effect as on listen_address
# (i.e. it will be based on the configured hostname of the node).
#
# Note that unlike listen_address, you can specify 0.0.0.0, but you must also
# set broadcast_rpc_address to a value other than 0.0.0.0.
#
# For security reasons, you should not expose this port to the internet.  Firewall it if needed.
rpc_address: 10.1.0.145
```

[incremental_backup](https://cassandra.apache.org/doc/latest/configuration/cass_yaml_file.html#incremental-backups) : 増分バックアップを有効化します。必須ではありません。有効化しない場合はフル バックアップのみが実行可能です。

```
# Set to true to have Cassandra create a hard link to each sstable
# flushed or streamed locally in a backups/ subdirectory of the
# keyspace data.  Removing these links is the operator's
# responsibility.
incremental_backups: true
```

# 起動

systemctl コマンドを実行して Cassandra のサービスを起動します。

```
# systemctl start cassandra
#
```

nodetool コマンドを実行して、すべてのサービスが正常に起動しているか確認します。

```
# nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.1.0.145  75.68 KiB  256          66.0%             d030d3bf-28ff-494b-ad9a-098495b2a84c  rack1
UN  10.1.0.147  101.44 KiB  256          67.6%             64faef28-0eb8-45aa-8b3e-7b2e3e959de4  rack1
UN  10.1.0.146  114.46 KiB  256          66.4%             ca3ec0ca-0519-4d28-9871-fc30b6fd270d  rack1

#
```

行の先頭が UN となっていれば、起動しています。

# 接続

cqlsh コマンドを使用して、Cassandra に接続します。

```
# cqlsh 10.1.0.145
Connected to Cluster at 10.1.0.145:9042.
[cqlsh 5.0.1 | Cassandra 3.11.9 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh>
```

キースペース (ksp01) を作成します。

```
cqlsh> create keyspace ksp01 with replication = { 'class': 'SimpleStrategy', 'replication_factor': 2};
cqlsh>
```

作成したキースペースに移動します。

```
cqlsh> use ksp01;
cqlsh:ksp01>
```

表 (table01) を作成します。INSERT 文を発行した時間がわかるようにするため、timeuuid 型の列を使用しています。

```
cqlsh:ksp01> create table table01 (uid timeuuid PRIMARY KEY, data text);
cqlsh:ksp01>
```

表にデータを登録して、問い合わせしてみます。

```
cqlsh:ksp01> insert into table01 (uid, data) values (now(), 'text');
cqlsh:ksp01> select * from table01;

 uid                                  | data
--------------------------------------+------
 a9f05740-2fa2-11eb-88be-9f196c07d178 | text

(1 rows)
cqlsh:ksp01>
```

timeuuid 列の値は toDate 関数や toTimestampe 関数と組み合わせることで実際の時間を表示することができます。

```
cqlsh:ksp01> select toDate(uid), data from table01;

 system.todate(uid) | data
--------------------+------
         2020-11-26 | text

(1 rows)
cqlsh:ksp01> select toTimestamp(uid), data from table01;

 system.totimestamp(uid)         | data
---------------------------------+------
 2020-11-26 04:48:44.724000+0000 | text

(1 rows)
cqlsh:ksp01>
```

以下のようなシェルを回し続けて継続して INSERT 文投げ続けることもできそうです。

```
# while true
> do
> date
> cqlsh --keyspace=ksp01 --execute="insert into table01 (uid, data) values (now(), '`date | md5sum`')" 10.1.0.145
> sleep 1
> done
Thu Nov 26 14:40:35 JST 2020
Thu Nov 26 14:40:37 JST 2020
Thu Nov 26 14:40:38 JST 2020
Thu Nov 26 14:40:40 JST 2020
```

挿入された結果を取得。

```
cqlsh:ksp01> select * from table01;

 uid                                  | data
--------------------------------------+-------------------------------------
 e94ba780-2fa9-11eb-a190-4bea79caaa22 | 2349c6ab9e14f6de1b19be4df6ef0ee6  -
 ec13ef40-2fa9-11eb-a190-4bea79caaa22 | 14b26f81b5f0d7b810b45a29c3270bac  -
 f0b69c50-2fa9-11eb-a190-4bea79caaa22 | 330a3f469914f700b6fe6d1a2a970a46  -
 ecffaed0-2fa9-11eb-a190-4bea79caaa22 | efd473dea0d087c35552afd2f18c576b  -
 f379b3f0-2fa9-11eb-a190-4bea79caaa22 | f930c22b74de27cf7ed32f8131a2024c  -
 eb291a10-2fa9-11eb-a190-4bea79caaa22 | 651a5ce2f8c48e5dbb0fa55aae25423d  -
 eed706e0-2fa9-11eb-a190-4bea79caaa22 | 9fe91349dd809ca47b1d6325e2c3ee95  -
 f1a0fc50-2fa9-11eb-a190-4bea79caaa22 | 9e78984bd8f58e9b243d5ff782bfc764  -
 edec0aa0-2fa9-11eb-a190-4bea79caaa22 | 94342192d22205fbd90f97ec72bc459d  -
 efc9f260-2fa9-11eb-a190-4bea79caaa22 | 301e773477cbe7b44c35abdbae718868  -
 ea3cbe40-2fa9-11eb-a190-4bea79caaa22 | 78dfcacdc5f327e8cbea7a1caf4fb47e  -
 f45d5d30-2fa9-11eb-a190-4bea79caaa22 | e7d19e8ec07986eebfa655bf72fb8cf4  -
 e85fe7f0-2fa9-11eb-a190-4bea79caaa22 | c78c2bc33cbe585692a4ed882fd75e5d  -
 f28d7f30-2fa9-11eb-a190-4bea79caaa22 | fdb39fd95a52482ac07ea2f69e0789a9  -

(14 rows)
cqlsh:ksp01>
```

ORDER BY 使うにはいろいろと条件があるらしいので、最後に INSERT された時間は以下の CQL 文で取得できそうです。

```
cqlsh:ksp01> select max(toTimestamp(uid)) from table01;

 system.max(system.totimestamp(uid))
-------------------------------------
     2020-11-26 05:40:56.067000+0000

(1 rows)

Warnings :
Aggregation query used without partition key

cqlsh:ksp01>
```