[検証]性能観点でパラメータ情報はAWSサービスのどこに保存するのが良い?


こんにちは

某SIerでソリューションアーキテクトをしております、たくまです。

Lambdaなどの処理で実行するパラメータ等の情報はどこに格納していますか?
SSMパラメータストア?S3?DynamoDB?

色々なサービスがあると思いますが、それぞれの性能観点。主にレイテンシーを考えた時に各サービスに違いはあるのか?という事が気になり検証してみました。

比較したサービスは、以下サービスです。

  • AWS Systems Manager Parameter Store (以降SSMパラメータストア)
  • AWS Systems Manager Parameter Store KMSを有効にした場合
  • AWS Secrets Manager
  • Amazon S3(以降S3)
  • DynamoDB

それぞれのサービスでの性能に関わるマニュアルは以下辺りです。

AWS Systems Manager Parameter Store

特に上限についての記載は見当たりませんでしたが、スループットの引き上げが可能な様です。
Parameter Store のスループットを引き上げる

AWS Secrets Manager

5,000/秒の読み込みが上限の様です。
AWS Secrets Manager quotas

S3

5,500/Sが GETリクエストの上限の様です。
Best practices design patterns: optimizing Amazon S3 performance

DynamoDB

40,000 read request unitsが上限の様です。
Amazon DynamoDB のサービス、アカウント、およびテーブルのクォータ

AWS Key Management Service

KMS辺りの許可50,000/秒が上限のようです。
AWS Key Management Serviceリソースクォータ

検証結果1

それぞれ、「Value=AWS」というパラメータを登録し、Lambdaから実行させました。
Lambda側の性能もある為、メモリの割り当ては128MBと1769MBで比較しました。(3回実行し平均をとっています)

※Lambdaのメモリを1769Mにしてる理由は、こちらの記事Lambdaが6vCPUまで拡張されたので性能検証してみました
を参照してください。

AWSサービス Lambda 128M Lambda 1769M 備考
SSM パラメータストア 41.08ms 25.24ms
SSM パラメータストアKMS有 53.67ms 44.38ms KMS利用で1割ぐらいお遅くなる
SecretsManager 41.59ms 31.10ms
S3 161.93ms 29.53ms 遅かったが、Lambdaメモリを上げると普通ぐらいに
DynamoDB 40.01ms 4.07ms Lamndaメメモリを上げると爆速

Lambdaのメモリの割り当てが少ないとS3は異様に遅かったですが、それ以外のサービスはそれほど大きな差はありませんでした。
KMSを使うと2割程度遅くなるようです。

Lambdaのメモリ割り当てを増やすと早くなりましたがサービスによって改善具合に差がありました。
DynamoDBやS3はLambdaの割り当を増やすとレイテンシーも大きく改善しました。

検証結果2

性能に関わるパラメータを変更させて比較しました。(Lambdaのメモリは、1769MBとしています。)

AWSサービス Lambda 1769M 設定変更時 設定変更の内容
SSM パラメータストア 25.24ms 27.89ms スループットの引き上げ設定
SSM パラメータストアKMS有 44.38ms 43.91 スループットの引き上げ設定
S3 29.53ms 57.97ms KMS利用しバケットキー無効
S3 29.53ms 41.26 KMSを利用しバケットキー有効化
DynamoDB 4.07ms 5.44 RCを1→100に変更

性能の上限をあげたとしても、レイテンシーにはあまり違いはなさそうでした。
こちらの結果からもKMSを利用するとレイテンシーが上がるようです。その為、S3は理由が無い限りはバケットキーも有効にして運用する方がよさそうです。

※S3のバケットキーについてはAmazonS3バケットキーを使用したSSE-KMSのコストの削減を参照ください。

最後に

Lambdaに適切なメモリを割り当てて上げた場合は、DynamoDB以外はどのサービスもレイテンシーに大きく違いはなく、レイテンシーという観点では使いやすいサービスを選択すればよさそうです。

ただし、秒間リクエスト数の上限はあるのでリンクした上限を確認しリクエストに耐えられるか、減らす方法は無いか確認が必要となると思います。

検証したpythonコード

get-parametar.py
import time
import boto3

ssm = boto3.client('ssm')
secretsmanager = boto3.client('secretsmanager')
s3 = boto3.resource('s3')
bucket = s3.Bucket("<S3バケット名>")
obj = bucket.Object("parameter")

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('parameter')

def lambda_handler(event, context):
    loop_num=100

    #SSM パラメータストア
    start_unixtime = time.time()
    for counter in range(loop_num):
        response = ssm.get_parameters(
            Names=[
                'parameter',
            ],
            WithDecryption=True
        )

    end_unixtime = time.time()  
    execuete_time =end_unixtime - start_unixtime
    print("SSM パラメータストア:" , execuete_time) #実行時間出力


    #SSM パラメータストアKMS利用
    start_unixtime = time.time()
    for counter in range(loop_num):
        response = ssm.get_parameters(
            Names=[
                'parameterkms',
            ],
            WithDecryption=True
        )

    end_unixtime = time.time()  
    execuete_time =end_unixtime - start_unixtime
    print("SSM パラメータストアKMS利用:" , execuete_time) #実行時間出力


    #SecretsManager
    start_unixtime = time.time()
    for counter in range(loop_num):
        response = secretsmanager.get_secret_value(
            SecretId="parameter"
        )

    end_unixtime = time.time()  
    execuete_time =end_unixtime - start_unixtime
    print("SecretsManager:" , execuete_time) #実行時間出力

    #S3 resource
    start_unixtime = time.time()
    for counter in range(loop_num):
        response = obj.get()

    end_unixtime = time.time()  
    execuete_time =end_unixtime - start_unixtime
    print("S3:" , execuete_time) #実行時間出力


    #DynamoDB
    start_unixtime = time.time()
    for counter in range(loop_num):
        response = table.get_item(Key={'id': '0'})

    end_unixtime = time.time()  
    execuete_time =end_unixtime - start_unixtime
    print("DynamoDB:" , execuete_time) #実行時間出力

    return 0