Cassandra DB¶
はじめに¶
分散型データベースでNoSQLに分類されるCassandra DBについて調べたことを整理したページです。
Cassandaの概要¶
Apacheプロダクト(オープンソースソフトウェア)として開発・提供されているスケーラビリティの高い分散型のNoSQLデータベースで、単一故障点を排しビッグデータを扱うのに適したデータベースです。大量のデータを高速に書き込み・読み込みに対応しています。
2007年にFacebook社のエンジニア Avinash Lakshman(Amazon Dynamo の作者)とPrashant Malikにより開発、2008年にオープンソース化し、2009年にApacheインキュベータプロジェクトに寄贈、IBM、Twitter、Rackspace社の貢献を受けて2010年にApacheトップレベルプロジェクトに昇格しました。
Cassandra 5.0 2024年
Cassandra 4.1 2022年
Cassandra 4.0 2021年
Cassandra 3.0 2015年
Cassandra 2.0 2013年
Cassandra 1.0 2011年
NoSQLの分類とCassandra¶
NoSQLデータベースには、キーバリュー型、ドキュメント型、カラムファミリー型、グラフ型がありますが、Cassandraはカラムファミリー型に分類されます。
カラムファミリーまたはワイドカラムストアはキーバリューに類似していますが、キーバリューは1つのキーに1つの値を持つのに対して、カラムファミリーは1つのキーに複数のカラム(カラム名と値)を持ちます。
論理的には次のような構造です。
| partition key | 列1 | 列2 | ・・・ | 列N |
|---|---|---|---|---|
| AAAA | 値1 | 値2 | ・・・ | 値N |
| BBBB | 値1 | 値2 | ・・・ | 値N |
実際には、パーティションキー毎に、列の数だけ複数のキーバリューが存在(列名をキー、列の値をバリュー)します。
パーティションキーと列のセットをtableとし、複数のtableを束ねたkey spaceの構成を取ります。
tableの構造は、スキーマ定義を必要とします。(完全にスキーマレスではない模様)
クエリー言語¶
CassandraはNoSQLに属しますが、SQLに類似したCQL(Cassandra Query Language)を使用します。
分散型なので性能向上にはサーバーを増設することで実現します。
クラスタ¶
Cassandraではデータを複製して複数のノードに配置します。これにより、ノードが故障してもデータの欠落は発生しません。
また、クラスタのコントロールをするマスターは存在しません。これにより単一故障点(Single Point Of Failure)を持たない構成を実現しています。
データ量が増えてきた場合、ノードを追加することでスケールアウト(性能向上)が可能で、またノードの追加にあたりノードの停止を不要としています。
さらに、クラスタ(データセンター)を複数構成しクラスタ間を同期することで、DR(Disaster Recovery)対応も可能としています。
分散システムとCAP定理¶
分散システムでは、次のCAP(Consistency、Availability、Partition-tolerance)の3つを同時に満たせないCAP定理があり、Cassandraは、3つのうちAとPを満たす設計です。
- 可用性(Availability):ノードの1つが故障しても他のノードが応答
- 分断耐性(Partition-tolerance):データセンター間が切断しても各データセンターがそれぞれ稼働継続
ただし、データを複製し複数ノードに配置することは、一貫性の欠如が課題となります。Cassandraではデータの読み書き時に複数ノードに複製したデータ間に不一致があっても、多数決(3ノードのうち2ノードが一致している)で、最新の値を返却するとともに、それを修復する仕組み(Read Repair)を持ちます。
整合性(Consistency)については、次の調整が可能です。
- ONE:最初にリターンしたノードのデータを返却
- QUORUM:過半数のリターンノードのデータからタイムスタンプの新しいものを返却
- ALL:すべてのノードがリターンした後、タイムスタンプの新しいものを返却
開発試験でのクラスタ¶
Cassandraは分散型のデータベースでクラスター構成を取りますが、開発・試験用に単一マシンで実行することが可能です。また、ローカルマシンにDockerで複数ノードを実行してクラスタ構成を取ることもできます。
パーティション¶
Cassandraは、ノードへの分散配置の単位をパーティションとし、パーティションキーにより配置ノード(例えば3つ)が決まります。
そのため、均等に分散配置するには、パーティションキーをどのように定義するかデータモデルの設計が重要となります。
パーティションサイズは2GB程度に収まるようにデータモデルを設計するのがミソ。
レプリケーションファクタでデータのレプリカをいくつのノードに分散するかを制御
ファイル構造¶
LSM(Log Structured Merge tree)で、高速化書き込みを実現
クライアントからの書き込み要求を Commit Logファイルに書き込み、メモリ上のmemtableに書き込み、非同期にSSTableファイルにフラッシュ
SSTableファイルは追記を基本とし、新しい世代のSSTableファイルが作られる。データの更新をするとCompactionが発生するため性能に影響
苦手なこと¶
- パーティションをまたがる検索
- データの更新
できないこと¶
- テーブル(カラムファミリー)のJOIN
- ACIDトランザクション
実行環境¶
Cassandra DBは、Javaで記述されています。実行にはJavaランタイムが必要となります。
また、CQLを実行するcqlshはPythonで記述され、実行にはPythonランタイムが必要となります。
CassandraとJava/Pythonのバージョン関係¶
Cassandraのバージョンと、動作に必要となるJava/Pythonの実行環境(ランタイム)バージョンを次に示します。
| Cassandra | Java | Python |
|---|---|---|
| Cassandra 5 | Java 11または17 | Python 3.8~3.11 |
Cassandraの実行方式¶
OS上で直接Cassandraプロセスを実行する方法と、Dockerコンテナとして実行する方法があります。
JavaのバージョンとPythonのバージョンに制約があるので、OS上で直接Cassandraを実行する場合構成が難しい場合があります。
例えば、Debian 13でCassandra 5.0を稼働させようとした場合、Debian 13の公式リポジトリから入手できるJavaはOpenJDK 21または25であり、Cassandra 5.0が要求する11または17を別途インストールする必要があります。さらに厄介なのはDebian 13のPythonは3.13なのでcqlshの動作に必要な 3.8~3.11を満たせず、Linux系OSにおいてOS標準のPythonバージョン以外を入れるのに苦労します。
Dockerコンテナとして実行する場合、OSのカーネル以外はDockerコンテナ側で用意するのでDebianのいずれかのバージョンでも他のLinuxディストリビューションでも動作が容易です。
データベースをDockerコンテナで実行する場合、データを永続化する必要があるので、バインドマウントまたはVolumeのどちらかでホスト上のストレージにコンテナ側の/var/lib/cassandraをマウントします。
DockerコンテナでCassandraを実行¶
単一ノードのCassandraをDockerコンテナで実行します。
インターネット上のDockerリポジトリ(DockerHub)からCassandraの最新イメージを取得
~$ sudo docker pull cassandra:latest
:
~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
cassandra latest a304f309c41d 11 days ago 357MB
~$
取得したイメージを基にDockerでCassandraを実行(データは永続化していないのでコンテナを削除すると消える)
~$ sudo docker container run --name cassandra-solo -d cassandra:latest
:
~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
31e563f48fb9 cassandra:latest "docker-entrypoint.s*" About a minute ago Up About a minute 7000-7001/tcp, 7199/tcp 9042/tcp, 9160/tcp cassandra-solo
実行中のCassandraコンテナにcqlshで接続
~$ docker container exec -it cassandra-solo cqlsh
Connected to Test Cluster at 127.0.0.1:9042
[cqlsh 6.2.0 | Cassandra 5.0.8 | CQL spec 3.4.7 | Native protocol v5]
Use HELP for help.
cqlsh>
キースペースとテーブルを作成
cqlsh> CREATE KEYSPACE my_app WITH replication={'class': 'SimpleStrategy', 'replication_factor': 1};
cqlsh> DESCRIBE keyspaces;
my_app system_auth system_schema system_views
system system_distributed system_traces system_virtaul_schema
cqlsh> USE my_app
cqlsh:my_app> CREATE TABLE user (
user_id varchar PRIMARY KEY,
first_name varchar,
last_name varchar
);
- 実験用なので分散なしのレプリカ数=1でキースペースを作成
テーブルにデータを入れて確認
cqlsh:my_app> INSERT INTO user (user_id, first_name, last_name)
VALUES ('SENDAI', 'MASAMUNE', 'DATE');
sqlsh:my_app> SELECT * FROM user;
user_id | first_name | last_name
--------+------------+------------
SENDAI | MASAMUNE | DATE
(1 rows)
sqlsh:my_app>
実行中のCassandraコンテナを停止
~$ sudo docker container stop cassandra-solo
:
~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
~$
コンテナを破棄
要確認
- docker network create cassandra
資料¶
Running Apache Cassandra Single and Multi-Node Clusters on Docker with Docker Compose