プロジェクト

全般

プロフィール

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


18日前に更新