フォーム読み込み中
2023年1月16日掲載
本記事では、Alibaba Cloud Lindormのマルチゾーン(Cross Zone)を使って、それぞれのZoneで稼働するアプリケーションを構築してみました。
Alibaba Cloud LindormはAlibaba Cloudが提供するCloud-Native Multi-Modal Databaseです。このLindormにはCassandraと同じエンジンを搭載しており、CassandraのようにActive-Active Multi Region/Zoneを展開することができます。
※2022/11/29時点で国際サイトのLindormはマルチゾーン(Cross Zone)展開のみサポート
Lindormは複数Zoneに跨ってインスタンスを作成しながら運用することができるので、それぞれのZone配下にアプリケーションを展開したり、障害時は接続先を別のZoneへ切り替えるといった高可用性構成を確保することができます。
今回、Lindormインスタンスを作成し、マルチゾーン展開することで、Active-Activeアプリケーションのマルチゾーンを構築します。そして複数のZone間でデータの一貫性を保ちながら、同時にLindorm CLI、HBase API、Cassandra CQLそれぞれのアクセスでデータを送りつつテーブルの整合性を保つかどうかを確認してみます。
2023/01/16時点で、Lindormマルチゾーン展開はシンガポール、インドネシア、バンコク、深圳、香港、杭州、上海、北京、河北省リージョンにて利用することができます。今回はシンガポールリージョンにてマルチゾーン展開デプロイしながら、Lindorm CLI、HBase API、Cassandra CQLを通じてその中のワイドテーブルエンジンを操作してみます。加えて、異なるZoneの間で同時に異なるデータを処理することによる、テーブルの整合性をチェックします。
Lindormのマルチゾーンアーキテクチャについて説明します。全体像としては次の図の通りになります。
基本的には3つ以上のZoneを使って、マルチゾーン展開をします。
Lindormインスタンスのワイドテーブルを分割したそれぞれのPartitionは、それぞれのZoneに独立したReplicaを持ちます。LindormでSQLやAPIアクセス等でデータのWrite/Read処理が発生する度にWALログ(Write-Ahead Logging、ログ先行書き込み)が発生しますが、このWALログはZone A/B/Cの共通基盤となるLindorm DFSを経由してZone CのDFSに保存されます。そのため、例えばZone Aが障害等なにかにより使えなくなった場合、このZone CのDFSに保存したデータは、Zone B上にてデータを素早く復元します。
Lindorm はマルチゾーン展開する際、分散合意アルゴリズムの一種である Replica consensus protocol を使って異なるZone間でのReplicaデータをリアルタイム同期するため、整合性を保つために最低限2つのReplicaのデータ、すなわち3つ以上のZoneが必要となります。
閑話休題、Lindorm マルチゾーンのインスタンスを作成してみます。
マルチゾーンのLindormインスタンスを作成するために、各ゾーンの下に少なくとも1つのvSwitchを持つVPCインスタンスを構築する必要があります。
「Create VPC」ボタンをクリックして、VPC作成画面に入ります。
作成フォームに必要なVPC名を入力します。
作成フォームに必要なIPv4 CIDRブロックを入力します。
各ゾーンにvSwitchの設定を行い、IPv4 CIDRブロックの設定が正しいことを確認します。
「OK」ボタンをクリックし、操作を実行します。
完了すると、必要なVPCとvSwitchが準備されます。
Lindormコンソールに移動し、マルチゾーンのLindormインスタンスを作成します。
「Create」ボタンをクリックして、作成画面に入ります。
デプロイメント方法として、「Multi-Zone Deployment」を選択します。
前のステップで作成した特定のVPCとvSwitchを選択します。
ワイドテーブル・エンジンとログ・ノードを設定します。
「Buy Now」ボタンをクリックし、注文確認画面に移動します。
利用規約のチェックボックスにチェックを入れます。
「Activate Now」ボタンをクリックして、操作を実行します。
この後、「Creating」のステータスでインスタンスが取得されます。インスタンスの準備が整うまでしばらく時間がかかります。
ステータスが「Running」に変更されたら、次のステップでマルチゾーンLindormインスタンスの操作ができます。
インスタンスの詳細ページで、ノードとゾーンの情報を確認します。
今回は、同じVPC下のECSからLindormインスタンスに接続します。接続方法は「Database Connection」メニューで接続情報を確認することができます。
もし、VPC外からの接続としてパブリックエンドポイントが必要な場合は、「Apply for Public Endpoint」ボタンをクリックしながら接続環境を準備する必要があります。
接続作業を始める前に、接続セキュリティのために、ECSインスタンスのイントラネットアドレスを「Access Control」ページのホワイトリストに追加しておきます。
「Modify Whitelist」ボタンをクリックすると、設定画面が表示されます。
ホワイトリストに予想されるIPアドレスを追加します。ECSインスタンスのイントラネットIPアドレスを使用します。
「OK」ボタンをクリックして、操作を実行します。
接続先のIPアドレスをホワイトリストに登録することで、接続できるようになります。
LindormTableへの接続は、SQLベースであれば、Java、Python、Goなどの複数のプログラミング言語用のLindorm SDKをサポートしています。複数のプログラミング言語用のLindorm SDKを使うことで、LindormTableが提供する全ての機能を利用することができます。
例として、Lindorm CLIを使ってワイドテーブルエンジンに接続し、そこからLindorm Table SQLを実行する方法を説明します。
同じVPC内に用意されたECSインスタンスに接続します。
Lindorm CLIのインストールパッケージをダウンロードし、解凍して利用します。
wget -O lindorm-cli-linux-latest.tar.gz https://tsdbtools.oss-cn-hangzhou.aliyuncs.com/lindorm-cli-linux-latest.tar.gz?spm=a2c63.p38356.0.0.338d5a2egBGtdx&file=lindorm-cli-linux-latest.tar.gz
tar -xvf lindorm-cli-linux-latest.tar.gz
今回は、lindorm-cliという実行ファイルを用意します。以下のコマンドを実行し、Lindormインスタンスに接続します。
jdbc urlとuser infoは自分の好きなように変更してください。jdbc urlは、データベース接続のページから取得できます。ユーザー情報は、デフォルトではroot/rootになっています。
接続に成功した場合、lindorm-cliのバージョンと関連したメッセージが表示されます。
./lindorm-cli -url <jdbc url> -username <Username> -password <Password>
Lindormでは、さまざまなビジネス要件に対応するために、テーブルの一貫性のレベルを設定することができます。LindormTable SQLでは、テーブルの一貫性に2つの有効なパラメータ値があります。
Eventual consistency(結果整合性): ベーステーブルとインデックステーブルのデータはある時点から一貫性を持つようになります。
Strong consistency(強整合性): ベーステーブルとインデックステーブルのデータは、すべての時点において一貫するようにします。
テーブルの一貫性に関する詳細な情報は、公式サイトのHelpドキュメントにあるFeatureを参照してください。
Eventual consistency(結果整合性)とStrong consistency(強整合性)それぞれを持つ2つのテーブルを作成します。そして、それを使ってUPSERT、SELECT、DELETEなどのSQL文を実行します。UPSERTはデータがあればUPDATE、なければINSERTする処理です。
次のSQLはStrong consistency(強整合性)のテーブルに対するSQL文です。
CREATE DATABASE demo;
use demo;
CREATE TABLE demo_table_strong(
chat varchar,
id bigint,
sender varchar,
message varchar,
PRIMARY KEY(chat, id DESC)
) 'CONSISTENCY' = 'strong';
UPSERT
INTO
demo_table_strong(
chat,
id,
sender,
message
)
VALUES(
'sql demo',
20221108001,
'Bob',
'Test from CLI'
);
SELECT
*
FROM
demo_table_strong;
UPSERT
INTO
demo_table_strong(
chat,
id,
sender,
message
)
VALUES(
'sql demo',
20221108001,
'Bob',
'Test from CLI update'
);
SELECT
*
FROM
demo_table_strong;
DELETE
FROM
demo_table_strong
WHERE
chat = 'sql demo'
AND id = 20221108001;
SELECT
*
FROM
demo_table_strong;
DROP TABLE demo_table_strong;
こちらはEventual consistency(結果整合性)のテーブルの場合のSQL文です。
CREATE TABLE demo_table_eventual(
chat varchar,
id bigint,
sender varchar,
message varchar,
PRIMARY KEY(chat, id DESC)
) 'CONSISTENCY' = 'eventual';
UPSERT
INTO
demo_table_eventual(
chat,
id,
sender,
message
)
VALUES(
'sql demo',
20221108001,
'Bob',
'Test from CLI'
);
SELECT
*
FROM
demo_table_eventual;
UPSERT
INTO
demo_table_eventual(
chat,
id,
sender,
message
)
VALUES(
'sql demo',
20221108001,
'Bob',
'Test from CLI update'
);
SELECT
*
FROM
demo_table_eventual;
DELETE
FROM
demo_table_eventual
WHERE
chat = 'sql demo'
AND id = 20221108001;
SELECT
*
FROM
demo_table_eventual;
DROP TABLE demo_table_eventual;
その結果、Eventual consistency(結果整合性)のテーブルとStrong consistency(強整合性)のテーブルそれぞれに同じSQLクエリを実行しても、結果に変化はありません。
今度は、Eventual consistency(結果整合性)のテーブルとStrong consistency(強整合性)のテーブルそれぞれを再作成し、それを使って、DESCRIBE文とEXPLAIN文を実行してみます。DESCRIBE文はテーブル構造を確認するSQLステートメント、EXPLAINはSQL実行計画のために情報を取得するためのSQLステートメントです。
CREATE TABLE demo_table_strong(
chat varchar,
id bigint,
sender varchar,
message varchar,
PRIMARY KEY(chat, id DESC)
) 'CONSISTENCY' = 'strong';
CREATE TABLE demo_table_eventual(
chat varchar,
id bigint,
sender varchar,
message varchar,
PRIMARY KEY(chat, id DESC)
) 'CONSISTENCY' = 'eventual';
UPSERT
INTO
demo_table_strong(
chat,
id,
sender,
message
)
VALUES(
'sql demo',
20221108001,
'Bob',
'Test from CLI'
);
UPSERT
INTO
demo_table_eventual(
chat,
id,
sender,
message
)
VALUES(
'sql demo',
20221108001,
'Bob',
'Test from CLI'
);
DESCRIBE demo_table_strong;
DESCRIBE demo_table_eventual;
EXPLAIN
SELECT
*
FROM
demo_table_strong
WHERE
chat = 'sql demo'
AND id = 20221108001;
EXPLAIN
SELECT
*
FROM
demo_table_eventual
WHERE
chat = 'sql demo'
AND id = 20221108001;
Eventual consistency(結果整合性)のテーブルとStrong consistency(強整合性)のテーブルそれぞれにてDESCRIBE文とEXPLAIN文を実施しましたが、変化は知見できません。
この結果から、Lindormのマルチゾーン展開では、Lindormインスタンスのワイドテーブルの障害識別とフェイルオーバーは、Eventual consistency(結果整合性)のテーブルとStrong consistency(強整合性)のテーブルに関係なく、インスタンスのヘルスステータスによって決定されます。つまり、どちらのゾーンでアプリケーションをマルチ運用してもデータの矛盾といった問題が全くないぐらいです
これはリレーショナルデータベースがHA高可用性構成(DR:Disaster recovery)としたマルチZone構成によるデプロイと比べて、Lindormマルチゾーン展開はそれぞれのZone上におけるデータの整合性や復旧の素早さ(RPOが100ms未満)、およびそれぞれのゾーンからのデータ処理やアクセスが出来るなどといった点から、異なるZone間でそれぞれアプリケーションを展開したい際はLindormが非常に役立ちます。
LindormはApache HBaseと互換性があり、HBase APIでワイドテーブルエンジンに接続する方法には、Alibaba Cloudが提供するApsaraDB for HBase SDKやHBaseue Shellなどを使います。
今回は、サンプルのPythonコードを使って、簡単な検証を行います。HBaseのテーブルは全てStrong consistency(強整合性)で設定するため、HBase APIに関連する設定は不要です。なお、ソースコードはGitHubからダウンロードしてください。
git clone https://github.com/aliyun/aliyun-apsaradb-hbase-demo.git
上記Repoには、HBase APIのPythonスクリプトだけでなく、他の接続方法およびプログラム言語のサンプルコードも含まれています。
次のコマンドで、ターゲットのPythonスクリプトをメインフォルダへ移動します。
cd aliyun-apsaradb-hbase-demo/hbase/thrift2/python/
ApsaraDB for HBase APIをJava以外の言語で使用するには、Thrift2コマンドを実行して、対応する言語のinterface definition language (IDL)ファイルを生成する必要があります。Apache ThriftはFacebookが開発した、異なる言語間でシームレスに動作するインタフェース定義言語とコードジェネレータツールです。ダウンロードしたソースコードには、すでに生成されたIDLファイルが含まれています。独自のコードを使用する場合は、以下の手順で必要なファイルを生成し、プロジェクトにコピーします。
Thrift2 パッケージを作業環境に配置します。今回はapt コマンドを使用して、thrift-compiler をインストールします。
apt install thrift-compiler -y
その後、Hbase.thriftをベースにしたIDLファイルをターゲットのPythonスクリプトのメインフォルダに生成します
thrift --gen python Hbase.thrift
完了すると、gen-pyフォルダの下に以下の生成されたファイルが表示されます。
これらのファイルは、今のプロジェクトにて使用することができます。
この方法は、C++、NodeJS、PHP、Goなど他のプログラミング言語用のIDLファイルを生成するのにも使えます。言語名は好きなように変更することができます。
thrift --gen <language> Hbase.thrift
これで、独自の接続情報を使用してソースコードを更新できます。
URLをコンソールのURLに変更し、必要に応じてユーザー情報も変更します。
vi index.py
Pythonスクリプトを実行し、結果を確認します。
なお、著者はサンプルコードをPython 2.xをベースに作成していますので、もしPython 3.xをお使いの場合は、実行前にコードを修正する必要があります。
python index.py
その結果、HBase APIのPythonスクリプトにより、ワイドカラムテーブル一覧情報が返却されてることがわかります。
Lindormは、Cassandraのエンジンも搭載されており、Cassandraも高い互換性を持ちます。Cassandraクライアントドライバを使用して、C++、Python、Nodejs、Goといった複数の言語でワイドテーブルエンジンに接続することができます。ここではPythonを例にとって説明します。
CassandraのPythonクライアントドライバをpipコマンドでインストールします。
pip install cassandra-driver
Lindorm CQLの説明によれば、テーブルの一貫性には、eventual、timestamp、basic、およびstrongの4つのパラメータ値があります。
今回、整合性のタイプがEventual consistency(結果整合性)とStrong consistency(強整合性)なので、lindorm_cassandra.pyというPythonスクリプトを使ってeventualおよびstrong用のテーブルを用意します。詳細については、ヘルプドキュメントを参照してください。
以下はlindorm_cassandra.pyのサンプルコードです。接続情報やユーザー情報などはご自身の状況に合わせて更新してください。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import logging
import sys
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
cluster = Cluster(
# Set cassandra CQL connection endpoint without the port
contact_points=["ld-xxxxxxx"],
# Set user name and password, default as root
auth_provider=PlainTextAuthProvider("root", "root"))
session = cluster.connect()
print "Connect the Lindorm server successfully!"
# Create the keyspace
session.execute("CREATE KEYSPACE IF NOT EXISTS demo WITH replication = {'class':'SimpleStrategy', 'replication_factor':1};")
print "Create the keyspace successfully!"
# Create the table with consistency type of table as eventual
session.execute("CREATE TABLE IF NOT EXISTS demo.testTableEventual (id int PRIMARY KEY, name text,age int,address text) with extensions = {'CONSISTENCY_TYPE':'eventual'};")
print "Create the table with consistency type of table as eventual successfully!"
# Clear the table data
session.execute("TRUNCATE TABLE demo.testTableEventual;")
print "Clear the table data successfully!"
# Insert the data
session.execute("INSERT INTO demo.testTableEventual (id, name, age, address) VALUES ( 1, 'Bob', 11, 'testing eventual');")
print "Insert the data into the table successfully!"
# Search the data
rows = session.execute("SELECT * FROM demo.testTableEventual;")
print "Query the data from the table successfully!"
# Print the results
for row in rows:
print "# row: {}".format(row)
# Create the table with consistency type of table as eventual
session.execute("CREATE TABLE IF NOT EXISTS demo.testTableStrong (id int PRIMARY KEY, name text,age int,address text) with extensions = {'CONSISTENCY_TYPE':'strong'};")
print "Create the table with consistency type of table as strong successfully!"
# Clear the table data
session.execute("TRUNCATE TABLE demo.testTableStrong;")
print "Clear the table data successfully!"
# Insert the data
session.execute("INSERT INTO demo.testTableStrong (id, name, age, address) VALUES ( 2, 'Bob_new', 22, 'testing strong');")
print "Insert the data into the table successfully!"
# Search the data
rows = session.execute("SELECT * FROM demo.testTableStrong;")
print "Query the data from the table successfully!"
# Print the results
for row in rows:
print "# row: {}".format(row)
# Drop the table
session.execute("DROP TABLE demo.testTableEventual;")
session.execute("DROP TABLE demo.testTableStrong;")
print "Drop the table successfully!"
# Close the session
session.shutdown()
# Close the cluster
cluster.shutdown()
print "Close the connection successfully!"
Pythonスクリプトを実行し、実行結果を確認します。結果としてレコード作成やデータ追加・参照・テーブル削除処理が機能しています。
注意点として、このスクリプトはPython 2.xに基づいています。
Lindorm CLIでLindorm Tableに接続しようとした際にこのエラーが発生した場合、Lindormインスタンスのホワイトリストを確認します。操作ユーザーのIPアドレスをホワイトリストに追加すると、エラーは解消されるはずです。
他のSQLコマンドツールと同じです。エラーが発生したら、エラーメッセージを確認し、SQL文の修正を行う必要があります。
以下は、SQL文のエラーの例です。
予約語やキーワードをテーブル名やカラム名として使用します。
Cassandra Pythonクライアント・ドライバのインストールで以下のエラーが発生した場合は、まずpipコマンドでCythonを手動でインストールすることができます。その後、Cassandra Pythonクライアント・ドライバーのインストール・プロセスが正常に実行されるはずです。
Building wheels for collected packages: cassandra-driver, geomet
Running setup.py bdist_wheel for cassandra-driver ... error
Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-OQBIQ5/cassandra-driver/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d /tmp/tmpwXzN7gpip-wheel- --python-tag cp27:
Couldn't find index page for 'Cython' (maybe misspelled?)
本記事ではLindormでマルチゾーン展開およびActive-Activeアプリケーションのマルチゾーン構築、およびテーブルの整合性についてをご紹介しました。
LindormはHBaseとCassandraのエンジンが搭載されており、HBaseとして最大数千PB数百億レコードと数百万のカラムを持つWide-Columnテーブルで、RedisのようなIn-Memory型Key-Value Databaseと同じ処理速度でデータを処理できるリアルタイムクエリ機能を持ちます。そのうえ、Cassandraとして常時稼働することをコンセプトとしたActive-Activeアーキテクチャにより全てのZoneが持つデータは常に複製されるため、障害が発生しても100ms以内に復旧するため、データが失われることなくサービスを提供し続けることができます。それだけにLindormはHBaseとCassandraのハイブリットデータベースといっても過言ではないぐらい魅力的です。また、Apache HBaseの弱点としてマスターノードがダウンするとクラスタ全体にアクセスできなくなる問題をLindormは完全に排除、およびCassandraの性格上クラスタ全体のリバランスは非サポートに対しLindormはサポートしているという点は非常に大きいです。
CAP定理でApache HBase がCAモデル(一貫性・可用性)、CassandraがAPモデル(可用性・分断耐性)に対し、LindormはCAP全てを達成しているデータベースなので、もしSQL/NoSQL問わず CAP定理によるデータベースの性質で悩んでる方には本記事を参考に頂ければ幸いです。
条件に該当するページがございません