金融機関の大多数では、オンライントランザクション処理(OLTP)は静的または頻繁に更新されないデータ、いわゆる参照データに依存することが多い。参照データソースは常にACIDトランザクション機能を必要とするわけではなく、単純なデータアクセスパターンに基づく高速な読み取りクエリのサポートと、ターゲットシステムが最新の状態を保つためのイベント駆動型アーキテクチャが必要です。NoSQLデータベースはこれらの要件を満たすのに理想的な候補として現れ、AWSのようなクラウドプラットフォームは、管理された高い耐久性を持つデータエコシステムを提供しています。
本記事では、どのAWSのNoSQLデータベースが優れているかを決定するつもりはありません。データベースの良し悪しは、特定の目的のコンテキスト内でのみ存在します。AWSが管理するNoSQLデータベースのパフォーマンスを測定するためのコーディングラボを共有します。例えばDynamoDB、Cassandra、Redis、そしてMongoDBです。
パフォーマンステスティング
I will start by defining the performance test case, which will concurrently insert a JSON payload 200 times and then read it 200 times.
JSONペイロード
base_db.pyのbase
/parent
クラスは、10個のコンカレントスレッドを使用して200レコードを作成および読み取るテストケースのロジックを実装しています。
#imports
.....
class BaseDB:
def __init__(self, file_name='instrument.json', threads=10, records=20):
...................................
def execute(self):
create_threads = []
for i in range(self.num_threads):
thread = threading.Thread(
target=self.create_records, args=(i,))
create_threads.append(thread)
thread.start()
for thread in create_threads:
thread.join()
read_threads = []
for i in range(self.num_threads):
thread = threading.Thread(target=self.read_records, args=(i,))
read_threads.append(thread)
thread.start()
for thread in read_threads:
thread.join()
self.print_stats()
各スレッドは、create_records
と read_records
でそれぞれ書き込み/読み取りルーチンを実行します。これらの関数にはデータベース固有のロジックは含まれておらず、むしろ、各読み書き実行のパフォーマンスを測定します。
def create_records(self, thread_id):
for i in range(1, self.num_records + 1):
key = int(thread_id * 100 + i)
start_time = time.time()
self.create_record(key)
end_time = time.time()
execution_time = end_time - start_time
self.performance_data[key] = {'Create Time': execution_time}
def read_records(self, thread_id):
for key in self.performance_data.keys():
start_time = time.time()
self.read_record(key)
end_time = time.time()
execution_time = end_time - start_time
self.performance_data[key]['Read Time'] = execution_time
テストケースが実行されると、print_stats
関数は読み書きの平均値や標準偏差(stdev
)などの実行メトリクスを出力します。これらの値は、データベースの読み書きパフォーマンスと一貫性を示しており(小さい stdev
はより一貫性のある実行パフォーマンスを意味します)。
def print_stats(self):
if len(self.performance_data) > 0:
# パフォーマンスデータからPandas DataFrameを作成
df = pd.DataFrame.from_dict(self.performance_data, orient='index')
if not df.empty:
df.sort_index(inplace=True)
# 各列の平均値と標準偏差を計算
create_mean = statistics.mean(df['Create Time'])
read_mean = statistics.mean(df['Read Time'])
create_stdev = statistics.stdev(df['Create Time'])
read_stdev = statistics.stdev(df['Read Time'])
print("Performance Data:")
print(df)
print(f"Create Time mean: {create_mean}, stdev: {create_stdev}")
print(f"Read Time mean: {read_mean}, stdev: {read_stdev}")
NoSQLコード
標準SQLをサポートするリレーショナルデータベースとは異なり、各NoSQLデータベースは独自のSDKを持っています。各NoSQLデータベースの子テストケースクラスは、コンストラクタとcreate_record/read_record
関数のみを実装する必要があり、これらの関数はデータベース接続のインスタンス化と数行のコードでレコードの作成/読み取りを行うためのプロプライエタリデータベースSDKを含んでいます。
DynamoDBテストケース
import boto3
from base_db import BaseDB
class DynamoDB (BaseDB):
def __init__(self, file_name='instrument.json', threads=10, records=20):
super().__init__(file_name, threads, records)
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table_name = 'Instruments'
self.table = dynamodb.Table(table_name)
def create_record(self, key):
item = {
'key': key,
'data': self.json_data
}
self.table.put_item(Item=item)
def read_record(self, key):
self.table.get_item(Key={'key': key})
if __name__ == "__main__":
DynamoDB().execute()
AWSセットアップ
AWSアカウントでこれらのパフォーマンステストケースを実行するためには、以下の手順に従う必要があります。
- 必要なAWSデータサービスにアクセスする権限を持つEC2 IAMロールを作成します。
- EC2インスタンスを起動し、新しく作成されたIAMロールを割り当てます。
- 各NoSQLデータベースインスタンスを作成します。
IAM ロール
DynamoDB テーブル
Cassandra Keyspace/テーブル
DB ホストと資格情報については、mongo_db.py および redis_db.py モジュールでハードコーディングされており、削除されました。そのため、AWS アカウントに対応するデータベース接続設定で更新する必要があります。DynamoDB と Cassandra に接続するために、一時的に db_performnace_iam_role
IAM ロールに割り当てられた Boto3 セッション資格情報を使用することを選択しました。このコードは、East 1 リージョンの任意の AWS アカウントで修正なしで実行されます。
class CassandraDB(BaseDB):
def __init__(self, file_name='instrument.json', threads=10, records=20):
super().__init__(file_name=file_name, threads=threads, records=records)
self.json_data = json.dumps(
self.json_data, cls=DecimalEncoder).encode()
# Cassandra Keyspaces の設定
contact_points = ['cassandra.us-east-1.amazonaws.com']
keyspace_name = 'db_performance'
ssl_context = SSLContext(PROTOCOL_TLSv1_2)
ssl_context.load_verify_locations('sf-class2-root.crt')
ssl_context.verify_mode = CERT_REQUIRED
boto_session = boto3.Session(region_name="us-east-1")
auth_provider = SigV4AuthProvider(session=boto_session)
cluster = Cluster(contact_points, ssl_context=ssl_context, auth_provider=auth_provider,
port=9142)
self.session = cluster.connect(keyspace=keyspace_name)
EC2 インスタンスに接続します(Session Manager を使用)、そして以下のシェルスクリプトを実行してこれらのタスクを実行します。
- Git をインストールします。
- Python3 をインストールします。
- GitHub の performance_db リポジトリをクローンします。
- Python3 仮想環境をインストールしてアクティブ化します。
- サードパーティライブラリ/依存関係をインストールします。
- 各テストケースを実行します。
sudo yum install git
sudo yum install python3
git clone https://github.com/dshilman/db_performance.git
sudo git pull
cd db_performance
python3 -m venv venv
source ./venv/bin/activate
sudo python3 -m pip install -r requirements.txt
cd code
sudo python3 -m dynamo_db
sudo python3 -m cassandra_db
sudo python3 -m redis_db
sudo python3 -m mongo_db
最初の2つのテストケースに対して以下の出力が表示されるはずです。
(venv) sh-5.2$ sudo python3 -m dynamo_db パフォーマンスデータ: Create Time Read Time 1 0.336909 0.031491 2 0.056884 0.053334 3 0.085881 0.031385 4 0.084940 0.050059 5 0.169012 0.050044 .. … … 916 0.047431 0.041877 917 0.043795 0.024649 918 0.075325 0.035251 919 0.101007 0.068767 920 0.103432 0.037742
[200 rows x 2 columns] Create Time mean: 0.0858926808834076, stdev: 0.07714510154026173 Read Time mean: 0.04880355834960937, stdev: 0.028805479258627295 Execution time: 11.499964714050293 |
(venv) sh-5.2$ sudo python3 -m cassandra_db Performance Data: Create Time Read Time 1 0.024815 0.005986 2 0.008256 0.006927 3 0.008996 0.009810 4 0.005362 0.005892 5 0.010117 0.010308 .. … … 916 0.006234 0.008147 917 0.011564 0.004347 918 0.007857 0.008329 919 0.007260 0.007370 920 0.004654 0.006049
[200行 x 2列] 作成時間の平均: 0.009145524501800537, 標準偏差: 0.005201661271831082 読み込み時間の平均: 0.007248317003250122, 標準偏差: 0.003557610695674452 実行時間: 1.6279327869415283 |
テスト結果
DynamoDB | Cassandra | MongoDB | Redis | |
---|---|---|---|---|
Create | mean: 0.0859 stdev: 0.0771 |
mean: 0.0091 stdev: 0.0052 |
mean: 0.0292 std: 0.0764 |
mean: 0.0028 stdev: 0.0049 |
Read | mean: 0.0488 stdev: 0.0288 |
mean: 0.0072 stdev: 0.0036 |
mean: 0.0509 std: 0.0027 |
mean: 0.0012 stdev: 0.0016 |
Exec Time | 11.45 sec | 1.6279 sec | 10.2608 sec | 0.3465 sec |
私の観察
- I was blown away by Cassandra’s fast performance. Cassandra support for SQL allows rich access pattern queries and AWS Keyspaces offer cross-region replication.
- I find DynamoDB’s performance disappointing despite the AWS hype about it. You should try to avoid the cross-partition table scan and thus must use an index for each data access pattern. DynamoDB global tables enable cross-region data replication.
- MongoDBは非常にシンプルなSDKを持ち、使いやすく、JSONデータ型を最もサポートしています。インデックスを作成し、ネストされたJSON属性に対して複雑なクエリを実行できます。新しいバイナリデータ形式が登場するにつれ、MongoDBの魅力は失われる可能性があります。
- Redisのパフォーマンスは驚くほど速く、しかし、最終的には複雑なデータ型をサポートしているにもかかわらず、キー/値キャッシュです。Redisは、サーバーサイドでRedisにコードを渡して実行することでクエリパフォーマンスをさらに改善するための強力な機能であるパイプライン処理やスクリプティングを提供します。
結論
結論として、あなたの企業の参照データプラットフォームのためにAWSマネージドのNoSQLデータベースを選択するかは、あなたの特定の優先事項に依存します。パフォーマンスとリージョン間レプリケーションがあなたの主な懸念事項であれば、AWS Cassandraは明らかな勝者です。DynamoDBはLambdaやKinesisなどの他のAWSサービスとシームレスに統合されており、したがってAWSネイティブまたはサーバーレスアーキテクチャのための優れたオプションです。JSONデータ型を必要とするアプリケーションの場合、MongoDBがリードします。ただし、高速ルックアップや高可用性のためのセッション管理に重点を置いている場合、Redisは優れたオプションとして証明されます。最終的に、その決定は組織の固有の要件と一致するべきです。
いつものように、この記事の前半でリンクしたGitHubリポジトリにコードがあります(上記のシェルスクリプトタスク#3を参照)。このコードの実行やAWSのセットアップに関する助けが必要な場合は、お気軽にご連絡ください。
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python