Cassandra Cluster
公開日:2024-10-07
はじめに
- Cassandra入門にて基本的なCassandraの概要を掴みつつ、CQLでの操作を学んだ。今回はクラスタを複数台構築し、データの分散保存と冗長化を確認する。
Cassadraクラスタの前提知識
-
スニッチ .. Cassandraのクラスタにおいて、ノード間のネットワークトポロジーを把握し、データのレプリケーションや通信の最適化を行うためのメカニズム。Cassandraクラスタは分散型システムであり、複数のノードが協力して動作するが、ノード間の通信は効率的に行われる必要がある。スニッチは、そのネットワークのトポロジー(ノード間の物理的および論理的な配置)を理解し、レプリカの配置を決定したり、最適な通信経路を選択する。
- GossipingPropertyFileSnitchが推奨されている。
- 最も一般的に使われるスニッチ。ノードごとのトポロジー情報をcassandra-rackdc.propertiesファイルで管理する。Gossipプロトコルを使用して、ノード同士がトポロジー情報を交換。これにより、動的なクラスタの変更(ノードの追加や削除)にも柔軟に対応できる。
-
シードノード .. Cassandraクラスタ内で新しいノードがクラスタに参加する際や、クラスタが再起動する際に、クラスタの情報(他のノードのリストや状態)を提供する役割を果たす特別なノード。Cassandraでは、シードノードがクラスタの他のノードと通信するためのエントリーポイントとして機能し、Gossipプロトコルを通じてクラスタの全体像を他のノードに知らせる。
-
トークンリング .. データをクラスタ内のノード間で効率的に分散するための概念。ノードに複数のトークンを持たせることで、リング全体にデータをより細かく分散し、ノード間で負荷を均等に分散する。
-
論理データセンター .. Cassandraクラスタ内でノードをグループ化するための単位
-
論理ラック .. 論理データセンター内でノードをグループ化するための単位
Cassandraクラスタの構築
-
クラスタ数は1、論理データセンターは2つ、ノード数は3で構築する。
DC1 - node1(rack1) - node2(rack2) - node3(rack3) DC2 - node1(rack1) - node2(rack2) - node3(rack3)
-
docker-compose.ymlを作成し、cassandraのコンテナを6つ起動することでIaCを意識する。
-
docker-compose.ymlの作成
- 1つのノードに対するメモリ不足によるエラーが発生したため、MAX_HEAP_SIZEとHEAP_NEWSIZEを512M, 100Mに設定
- また、WSL2/Desktop for Windowsを使用しており、WSLに割り振るメモリを16GBに設定している。
version: '3' services: cassandra-dc1-node1: image: cassandra:latest container_name: cassandra-dc1-node1 environment: - CASSANDRA_CLUSTER_NAME=my_cassandra_cluster - CASSANDRA_DC=dc1 - CASSANDRA_RACK=rack1 - CASSANDRA_NUM_TOKENS=256 - CASSANDRA_SEEDS=cassandra-dc1-node1,cassandra-dc2-node1 - CASSANDRA_LISTEN_ADDRESS=cassandra-dc1-node1 - CASSANDRA_BROADCAST_ADDRESS=cassandra-dc1-node1 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=512M - HEAP_NEWSIZE=100M networks: - cassandra_network volumes: - cassandra-data-dc1-node1:/var/lib/cassandra ports: - '9042:9042' cassandra-dc1-node2: image: cassandra:latest container_name: cassandra-dc1-node2 environment: - CASSANDRA_CLUSTER_NAME=my_cassandra_cluster - CASSANDRA_DC=dc1 - CASSANDRA_RACK=rack2 - CASSANDRA_NUM_TOKENS=256 - CASSANDRA_SEEDS=cassandra-dc1-node1,cassandra-dc2-node1 - CASSANDRA_LISTEN_ADDRESS=cassandra-dc1-node2 - CASSANDRA_BROADCAST_ADDRESS=cassandra-dc1-node2 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=512M - HEAP_NEWSIZE=100M networks: - cassandra_network volumes: - cassandra-data-dc1-node2:/var/lib/cassandra cassandra-dc1-node3: image: cassandra:latest container_name: cassandra-dc1-node3 environment: - CASSANDRA_CLUSTER_NAME=my_cassandra_cluster - CASSANDRA_DC=dc1 - CASSANDRA_RACK=rack3 - CASSANDRA_NUM_TOKENS=256 - CASSANDRA_SEEDS=cassandra-dc1-node1,cassandra-dc2-node1 - CASSANDRA_LISTEN_ADDRESS=cassandra-dc1-node3 - CASSANDRA_BROADCAST_ADDRESS=cassandra-dc1-node3 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=512M - HEAP_NEWSIZE=100M networks: - cassandra_network volumes: - cassandra-data-dc1-node3:/var/lib/cassandra cassandra-dc2-node1: image: cassandra:latest container_name: cassandra-dc2-node1 environment: - CASSANDRA_CLUSTER_NAME=my_cassandra_cluster - CASSANDRA_DC=dc2 - CASSANDRA_RACK=rack1 - CASSANDRA_NUM_TOKENS=256 - CASSANDRA_SEEDS=cassandra-dc1-node1,cassandra-dc2-node1 - CASSANDRA_LISTEN_ADDRESS=cassandra-dc2-node1 - CASSANDRA_BROADCAST_ADDRESS=cassandra-dc2-node1 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=512M - HEAP_NEWSIZE=100M networks: - cassandra_network volumes: - cassandra-data-dc2-node1:/var/lib/cassandra cassandra-dc2-node2: image: cassandra:latest container_name: cassandra-dc2-node2 environment: - CASSANDRA_CLUSTER_NAME=my_cassandra_cluster - CASSANDRA_DC=dc2 - CASSANDRA_RACK=rack2 - CASSANDRA_NUM_TOKENS=256 - CASSANDRA_SEEDS=cassandra-dc1-node1,cassandra-dc2-node1 - CASSANDRA_LISTEN_ADDRESS=cassandra-dc2-node2 - CASSANDRA_BROADCAST_ADDRESS=cassandra-dc2-node2 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=512M - HEAP_NEWSIZE=100M networks: - cassandra_network volumes: - cassandra-data-dc2-node2:/var/lib/cassandra cassandra-dc2-node3: image: cassandra:latest container_name: cassandra-dc2-node3 environment: - CASSANDRA_CLUSTER_NAME=my_cassandra_cluster - CASSANDRA_DC=dc2 - CASSANDRA_RACK=rack3 - CASSANDRA_NUM_TOKENS=256 - CASSANDRA_SEEDS=cassandra-dc1-node1,cassandra-dc2-node1 - CASSANDRA_LISTEN_ADDRESS=cassandra-dc2-node3 - CASSANDRA_BROADCAST_ADDRESS=cassandra-dc2-node3 - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=512M - HEAP_NEWSIZE=100M networks: - cassandra_network volumes: - cassandra-data-dc2-node3:/var/lib/cassandra cqlsh: image: nuvo/docker-cqlsh:latest container_name: cqlsh networks: - cassandra_network entrypoint: ['cqlsh', 'cassandra-dc1-node1', '9042', '--cqlversion=3.4.7'] depends_on: - cassandra-dc1-node1 - cassandra-dc1-node2 - cassandra-dc1-node3 - cassandra-dc2-node1 - cassandra-dc2-node2 - cassandra-dc2-node3 stdin_open: true tty: true networks: cassandra_network: driver: bridge volumes: cassandra-data-dc1-node1: cassandra-data-dc1-node2: cassandra-data-dc1-node3: cassandra-data-dc2-node1: cassandra-data-dc2-node2: cassandra-data-dc2-node3:
-
docker-compose起動
docker-compose up -d
-
docker-composeで起動したコンテナのIPアドレスを確認する
docker network inspect cassandra-cluster_cassandra_network [ { "Name": "cassandra-cluster_cassandra_network", "Id": "c404e3e245c35e65051cc8560de07ed92e5cf45fa9ca1025dcc22c315590b699", "Created": "2024-10-07T05:44:46.746318283Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.21.0.0/16", "Gateway": "172.21.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "1fc552c9f1887398a01e30ccc4a01c5b8d53fb89238785516f06477402678737": { "Name": "cassandra-dc2-node1", "EndpointID": "84335e9129dce97ba413816db9b9a416df02f332ac2345068310fa89813ada94", "MacAddress": "02:42:ac:15:00:05", "IPv4Address": "172.21.0.5/16", "IPv6Address": "" }, "32707314dfd11d575a54b8c737f1512c60553fddd030de3db3d9dca1a2c820c1": { "Name": "cassandra-dc1-node3", "EndpointID": "6f5290269817066e21ae85f091f492ad96bb765dd9c38002c7ad092893773bf5", "MacAddress": "02:42:ac:15:00:04", "IPv4Address": "172.21.0.4/16", "IPv6Address": "" }, "37d04f066973816f8258a64214a27c73b282c4c3e0086d07fb38d7b088aa342f": { "Name": "cassandra-dc2-node3", "EndpointID": "9a99817d692330a6299f7f7687c4eacdac9621bb037902f4c34abe02ea4e3f12", "MacAddress": "02:42:ac:15:00:06", "IPv4Address": "172.21.0.6/16", "IPv6Address": "" }, "5c2c4c5ae43436dd2fa8795816209f878d2fece77895b45e36601fe501b2eea7": { "Name": "cassandra-dc1-node2", "EndpointID": "1cae7cb81378b08c127ba29801761777fc0dce5e24769e995c0bdfbf1c906679", "MacAddress": "02:42:ac:15:00:02", "IPv4Address": "172.21.0.2/16", "IPv6Address": "" }, "9a67fcfbb0d290860bfd7881107ea65f995f089dee6672271dd4208590db7e42": { "Name": "cassandra-dc2-node2", "EndpointID": "8882d8cf6663f462d24ebce0d658fd5feccae31e90be69aa0bf466018b2221fb", "MacAddress": "02:42:ac:15:00:03", "IPv4Address": "172.21.0.3/16", "IPv6Address": "" }, "c0d5406f42bbcede551e0a032ee275487592be1d8630ea9785de7aad96d6ae2f": { "Name": "cassandra-dc1-node1", "EndpointID": "bb9be0fe4f7dc6dbd54b4e121e734c08bf5fe70a7f065fe06beb784124324755", "MacAddress": "02:42:ac:15:00:07", "IPv4Address": "172.21.0.7/16", "IPv6Address": "" } }, "Options": {}, "Labels": { "com.docker.compose.network": "cassandra_network", "com.docker.compose.project": "cassandra-cluster", "com.docker.compose.version": "2.17.3" } } ]
-
cqlshに接続
- cassandraのnodeに接続せずに、cqlshコンテナを起動し、cqlshに接続する。
docker-compose run cqlsh
-
keyspaceの作成
- 論理データセンターとして、dc1、dc2を作成して、それぞれ3つのノードにデータがレプリケートされる。
CREATE KEYSPACE store WITH REPLICATION = {'class': 'NetworkTopologyStrategy', 'dc1': 3, 'dc2': 3};
-
テーブルの作成とデータの挿入
CREATE TABLE store.cart ( user_id UUID, -- ユーザーID product_id UUID, -- 商品ID product_name text, -- 商品名 price decimal, -- 価格 quantity int, -- 数量 added_at timestamp, -- カートに追加された日時 PRIMARY KEY (user_id, product_id) -- パーティションキー: user_id, クラスタリングキー: product_id ); -- ユーザー1がSmartphoneをカートに追加 INSERT INTO store.cart (user_id, product_id, product_name, price, quantity, added_at) VALUES (uuid(), uuid(), 'Smartphone', 699.99, 1, toTimestamp(now())); -- ユーザー1がLaptopをカートに追加 INSERT INTO store.cart (user_id, product_id, product_name, price, quantity, added_at) VALUES (uuid(), uuid(), 'Laptop', 999.99, 1, toTimestamp(now())); -- ユーザー2がHeadphonesをカートに追加 INSERT INTO store.cart (user_id, product_id, product_name, price, quantity, added_at) VALUES (uuid(), uuid(), 'Headphones', 199.99, 2, toTimestamp(now()));
-
nodetoolによる確認
- nodetoolはCassandraクラスタの管理ツールで、クラスタやノードのステータス、負荷分散、データの配置などを確認できる
- 下記結果より、各DCの各ノードが正常に稼働していることが確認できる。
# cassandra-dc1-node1に接続 docker exec -it cassandra-dc1-node1 bash # nodetool status root@c0d5406f42bb:/# nodetool status Datacenter: dc1 =============== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.21.0.4 682.97 KiB 256 100.0% c025e663-1629-4fb3-b3b4-675fc71ad856 rack3 UN 172.21.0.7 629 KiB 256 100.0% 1b2aafbf-8db7-495f-b356-bf197b70810f rack1 UN 172.21.0.2 772.07 KiB 256 100.0% 891c3c75-0ba9-40f1-bc42-0f089d8ed7fb rack2 Datacenter: dc2 =============== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.21.0.5 783.76 KiB 256 100.0% fd5c3032-b995-45bd-bbe7-a2b01376ea2c rack1 UN 172.21.0.3 803.01 KiB 256 100.0% ec64789a-21ce-448f-a2ea-082e7b630d68 rack2 UN 172.21.0.6 681.32 KiB 256 100.0% 4d5f499a-ddb8-4822-9a28-17cab66d462f rack3 # getendpointsコマンドでどのノードに配置されているのか確認 # 全てのノードにレプリケーションされていることが確認できる root@c0d5406f42bb:/# nodetool getendpoints store cart 6a70d4b7-9338-4603-9aa7-71cefcfdc13b 172.21.0.3 172.21.0.4 172.21.0.5 172.21.0.7 172.21.0.6 172.21.0.2
-
ノードの停止して起動確認
- cassandra-dc1-node3を停止させる
- Status,StateがDNになっていることが確認できる
root@c0d5406f42bb:/# nodetool status Datacenter: dc1 =============== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack DN 172.21.0.4 296.69 KiB 256 100.0% c025e663-1629-4fb3-b3b4-675fc71ad856 rack3 UN 172.21.0.7 259.09 KiB 256 100.0% 1b2aafbf-8db7-495f-b356-bf197b70810f rack1 UN 172.21.0.2 772.07 KiB 256 100.0% 891c3c75-0ba9-40f1-bc42-0f089d8ed7fb rack2 Datacenter: dc2 =============== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.21.0.5 783.76 KiB 256 100.0% fd5c3032-b995-45bd-bbe7-a2b01376ea2c rack1 UN 172.21.0.3 803.01 KiB 256 100.0% ec64789a-21ce-448f-a2ea-082e7b630d68 rack2 UN 172.21.0.6 681.32 KiB 256 100.0% 4d5f499a-ddb8-4822-9a28-17cab66d462f rack3
- cassandra-dc1-node3を起動させる
- Status,StateがUNになっていることが確認できる
root@c0d5406f42bb:/# nodetool status Datacenter: dc1 =============== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.21.0.4 462.9 KiB 256 100.0% c025e663-1629-4fb3-b3b4-675fc71ad856 rack3 UN 172.21.0.7 259.09 KiB 256 100.0% 1b2aafbf-8db7-495f-b356-bf197b70810f rack1 UN 172.21.0.2 772.07 KiB 256 100.0% 891c3c75-0ba9-40f1-bc42-0f089d8ed7fb rack2 Datacenter: dc2 =============== Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.21.0.5 783.76 KiB 256 100.0% fd5c3032-b995-45bd-bbe7-a2b01376ea2c rack1 UN 172.21.0.3 803.01 KiB 256 100.0% ec64789a-21ce-448f-a2ea-082e7b630d68 rack2 UN 172.21.0.6 681.32 KiB 256 100.0% 4d5f499a-ddb8-4822-9a28-17cab66d462f rack3
-
Cassandraクラスタの停止と削除
docker-compose down
まとめ
- Cassandraクラスタを構築し、データの分散保存と冗長化を確認しました。
- Cassandraクラスタは、スニッチ、シードノード、トークンリング、論理データセンター、論理ラックなどの概念を理解して、事前に設計することが重要と考えます。