HBaseとCassandraのハイブリット機能を持つLindormでActive-Activeマルチゾーンアプリケーションを構築してみる

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それぞれのアクセスでデータを送りつつテーブルの整合性を保つかどうかを確認してみます。

目次

1.全体構成図

2023/01/16時点で、Lindormマルチゾーン展開はシンガポール、インドネシア、バンコク、深圳、香港、杭州、上海、北京、河北省リージョンにて利用することができます。今回はシンガポールリージョンにてマルチゾーン展開デプロイしながら、Lindorm CLI、HBase API、Cassandra CQLを通じてその中のワイドテーブルエンジンを操作してみます。加えて、異なるZoneの間で同時に異なるデータを処理することによる、テーブルの整合性をチェックします。

2.Lindormマルチゾーンのアーキテクチャについて

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 マルチゾーンのインスタンスを作成してみます。

3.VPCとvSwitchの作成

マルチゾーンのLindormインスタンスを作成するために、各ゾーンの下に少なくとも1つのvSwitchを持つVPCインスタンスを構築する必要があります。

  1. Create VPC」ボタンをクリックして、VPC作成画面に入ります。

  2. 作成フォームに必要なVPC名を入力します。

  3. 作成フォームに必要なIPv4 CIDRブロックを入力します。

  4. 各ゾーンにvSwitchの設定を行い、IPv4 CIDRブロックの設定が正しいことを確認します。

  5. OK」ボタンをクリックし、操作を実行します。

完了すると、必要なVPCとvSwitchが準備されます。

4.マルチゾーンのLindormインスタンスを作成

Lindormコンソールに移動し、マルチゾーンのLindormインスタンスを作成します。

  1. Create」ボタンをクリックして、作成画面に入ります。

  2. デプロイメント方法として、「Multi-Zone Deployment」を選択します。

  3. 前のステップで作成した特定のVPCとvSwitchを選択します。

  4. ワイドテーブル・エンジンとログ・ノードを設定します。

  5. Buy Now」ボタンをクリックし、注文確認画面に移動します。

  6. 利用規約のチェックボックスにチェックを入れます。

  7. Activate Now」ボタンをクリックして、操作を実行します。

この後、「Creating」のステータスでインスタンスが取得されます。インスタンスの準備が整うまでしばらく時間がかかります。

ステータスが「Running」に変更されたら、次のステップでマルチゾーンLindormインスタンスの操作ができます。

インスタンスの詳細ページで、ノードとゾーンの情報を確認します。

5.Lindormインスタンスを設定

今回は、同じVPC下のECSからLindormインスタンスに接続します。接続方法は「Database Connection」メニューで接続情報を確認することができます。
もし、VPC外からの接続としてパブリックエンドポイントが必要な場合は、「Apply for Public Endpoint」ボタンをクリックしながら接続環境を準備する必要があります。

6.ホワイトリストの設定

接続作業を始める前に、接続セキュリティのために、ECSインスタンスのイントラネットアドレスを「Access Control」ページのホワイトリストに追加しておきます。

  1. Modify Whitelist」ボタンをクリックすると、設定画面が表示されます。

  2. ホワイトリストに予想されるIPアドレスを追加します。ECSインスタンスのイントラネットIPアドレスを使用します。

  3. OK」ボタンをクリックして、操作を実行します。

接続先のIPアドレスをホワイトリストに登録することで、接続できるようになります。

7.LindormTable SQLを使用してワイドテーブル・エンジンに接続

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が非常に役立ちます。

関連記事リンク

8.HBase APIを使用してワイドテーブル・エンジンに接続

LindormはApache HBaseと互換性があり、HBase APIでワイドテーブルエンジンに接続する方法には、Alibaba Cloudが提供するApsaraDB for HBase SDKHBaseue 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スクリプトにより、ワイドカラムテーブル一覧情報が返却されてることがわかります。

9.Cassandra Pythonクライアント・ドライバを使用して、CQL上でLindormTableに接続

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に基づいています。

10.補足事項

10-1. Lindorm CLIで "context deadline exceeded "エラーを修正する方法

Lindorm CLIでLindorm Tableに接続しようとした際にこのエラーが発生した場合、Lindormインスタンスのホワイトリストを確認します。操作ユーザーのIPアドレスをホワイトリストに追加すると、エラーは解消されるはずです。

10-2. Lindorm CLIでSQLエラーを修正するには?

他のSQLコマンドツールと同じです。エラーが発生したら、エラーメッセージを確認し、SQL文の修正を行う必要があります。

以下は、SQL文のエラーの例です。

  • 予約語やキーワードをテーブル名やカラム名として使用します。

  • ステートメントで間違ったデータ型を使用します。

10-3. Cassandra Pythonクライアント・ドライバのインストールで発生するエラーを修正するには?

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?)

11.さいごに

本記事では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定理によるデータベースの性質で悩んでる方には本記事を参考に頂ければ幸いです。

関連サービス

Alibaba Cloud

Alibaba Cloudは中国国内でのクラウド利用はもちろん、日本-中国間のネットワークの不安定さの解消、中国サイバーセキュリティ法への対策など、中国進出に際する課題を解消できるパブリッククラウドサービスです。

MSPサービス

MSP(Managed Service Provider)サービスは、お客さまのパブリッククラウドの導入から運用までをトータルでご提供するマネージドサービスです。

おすすめの記事

条件に該当するページがございません