Pythonを使用したAWS NoSQLパフォーマンスラボ

金融機関の大多数では、オンライントランザクション処理(OLTP)は静的または頻繁に更新されないデータ、いわゆる参照データに依存することが多い。参照データソースは常にACIDトランザクション機能を必要とするわけではなく、単純なデータアクセスパターンに基づく高速な読み取りクエリのサポートと、ターゲットシステムが最新の状態を保つためのイベント駆動型アーキテクチャが必要です。NoSQLデータベースはこれらの要件を満たすのに理想的な候補として現れ、AWSのようなクラウドプラットフォームは、管理された高い耐久性を持つデータエコシステムを提供しています。

本記事では、どのAWSのNoSQLデータベースが優れているかを決定するつもりはありません。データベースの良し悪しは、特定の目的のコンテキスト内でのみ存在します。AWSが管理するNoSQLデータベースのパフォーマンスを測定するためのコーディングラボを共有します。例えばDynamoDBCassandraRedis、そして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.pybase/parentクラスは、10個のコンカレントスレッドを使用して200レコードを作成および読み取るテストケースのロジックを実装しています。

Python

 

#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_recordsread_records でそれぞれ書き込み/読み取りルーチンを実行します。これらの関数にはデータベース固有のロジックは含まれておらず、むしろ、各読み書き実行のパフォーマンスを測定します。

Python

 

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 はより一貫性のある実行パフォーマンスを意味します)。

Python

 

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テストケース

Python

 

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アカウントでこれらのパフォーマンステストケースを実行するためには、以下の手順に従う必要があります。

  1. 必要なAWSデータサービスにアクセスする権限を持つEC2 IAMロールを作成します。
  2. EC2インスタンスを起動し、新しく作成されたIAMロールを割り当てます。
  3. 各NoSQLデータベースインスタンスを作成します。

IAM ロール

DynamoDB テーブル

Cassandra Keyspace/テーブル

DB ホストと資格情報については、mongo_db.py および redis_db.py モジュールでハードコーディングされており、削除されました。そのため、AWS アカウントに対応するデータベース接続設定で更新する必要があります。DynamoDB と Cassandra に接続するために、一時的に db_performnace_iam_role IAM ロールに割り当てられた Boto3 セッション資格情報を使用することを選択しました。このコードは、East 1 リージョンの任意の AWS アカウントで修正なしで実行されます。

Python

 

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 を使用)、そして以下のシェルスクリプトを実行してこれらのタスクを実行します。

  1. Git をインストールします。
  2. Python3 をインストールします。
  3. GitHub の performance_db リポジトリをクローンします。
  4. Python3 仮想環境をインストールしてアクティブ化します。
  5. サードパーティライブラリ/依存関係をインストールします。
  6. 各テストケースを実行します。
Shell

 

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