Amazon Web Services ブログ

Amazon MemoryDB for Redis のご紹介 – Redis 互換で耐久性に優れたインメモリデータベースサービス

インタラクティブなアプリケーションは、非常に迅速にリクエストを処理して対応する必要があり、アーキテクチャのすべてのコンポーネントでも同様にこの要件を満たす必要があります。マイクロサービスを採用し、アーキテクチャが相互に通信する多数の小さな独立したサービスで構成されている場合、これはさらに重要です。

このため、データベースのパフォーマンスは、アプリケーションの成功に不可欠です。読み取りレイテンシーをマイクロ秒に減らすために、耐久性のあるデータベースの前にインメモリキャッシュを配置できます。キャッシュの目的で、多くのデベロッパーはオープンソースのインメモリデータ構造ストアである Redis を使用しています。実際、Stack Overflow の 2021 Developer Surveyによると、5 年間にわたって、Redis は最も愛用されているデータベースです。

このセットアップを AWS で実装するには、データ損失を最小限に抑えるために、フルマネージドのインメモリキャッシュサービスである Amazon ElastiCache for Redis を、Amazon AuroraAmazon DynamoDB などの耐久性のあるデータベースサービスの前で、低レイテンシーのキャッシュとして使用できます。ただし、この設定では、キャッシュとデータベースとの同期を維持するために、アプリケーションにカスタムコードを導入する必要があります。また、キャッシュとデータベースの両方を実行する場合にもコストが発生します。

Amazon MemoryDB for Redis のご紹介
本日、Amazon MemoryDB for Redis の一般的な可用性を発表します。これは Redis 互換で耐久性に優れた新しいインメモリデータベースです。MemoryDB を使用すると、データの耐久性高可用性を備えた、マイクロ秒の読み取りおよび一桁ミリ秒の書き込みパフォーマンスを必要とするアプリケーションを簡単かつコスト効率に優れた方法で構築できます。

耐久性のあるデータベースの前で低レイテンシーのキャッシュを使用する代わりに、アーキテクチャを簡素化し、MemoryDB を単一のプライマリデータベースとして使用できるようになりました。MemoryDB を使用すると、すべてのデータがメモリに保存され、低レイテンシーと高スループットのデータアクセスを実現します。MemoryDB は、複数のアベイラビリティーゾーン (AZ) にまたがるデータを保存する分散トランザクションログを使用して、高速フェイルオーバー、データベースリカバリ、およびノードの再起動を高耐久性で実現します。

MemoryDB はオープンソースの Redis との互換性を維持し、使い慣れたものと同じ一連の Redis データ型、パラメータ、およびコマンドをサポートしています。つまり、現在オープンソースの Redis で既に使用しているコード、アプリケーション、ドライバー、およびツールを MemoryDB で使用できるということです。デベロッパーは、文字列、ハッシュ、リスト、セット、範囲クエリを含むソートセット、ビットマップ、hyperloglogs、地理空間インデックス、ストリームなどの多くのデータ構造にすぐにアクセスできます。また、組み込みレプリケーション、LRU (最も長く使われていない) 削除、トランザクション、自動パーティション化などの高度な機能にもアクセスできます。MemoryDB は Redis 6.2 と互換性があり、オープンソースでリリースされる新しいバージョンをサポートします。

ここで、両方のサービスで Redis データ構造と API にアクセスできるため、MemoryDB が ElastiCache とどのように違うのか、疑問に思われるかもしれません。

  • MemoryDB は、データの耐久性、およびマイクロ秒の読み取りと一桁ミリ秒の書き込みレイテンシーを提供するため、アプリケーションのプライマリデータベースとして安全に利用できます。MemoryDB を使用すると、インタラクティブなアプリケーションやマイクロサービスアーキテクチャに必要な低レイテンシーを実現するために、データベースの前にキャッシュを追加する必要はありません。
  • 一方、ElastiCache は読み取りと書き込みの両方にマイクロ秒のレイテンシーを提供します。これは、既存のデータベースからのデータアクセスを高速化するワークロードのキャッシュに最適です。ElastiCache は、データ損失が許容される可能性があるユースケース (例えば、別のソースからデータベースをすばやく再構築できる場合など) のプライマリデータストアとしても使用できます。

Amazon MemoryDB クラスターの作成
MemoryDB コンソールで、左側のナビゲーションペインのリンクに従って [Clusters] (クラスター) セクションに移動し、[Create cluster] (クラスターを作成) を選択します。これにより、[Cluster settings] (クラスターの設定) が開きます。ここで、クラスターの名前と説明を入力します。

コンソールのスクリーンショット。

すべての MemoryDB クラスターは、仮想プライベートクラウド (VPC) で実行されます。サブネットグループでは、VPC の 1 つを選択し、クラスターがノードの配布に使用するサブネットのリストを指定して、サブネットグループを作成します。

コンソールのスクリーンショット。

[Cluster settings] (クラスター設定) では、ネットワークポート、ノードとクラスターのランタイムプロパティを制御するパラメータグループ、ノードタイプ、シャードの数、およびシャードあたりのレプリカの数を変更できます。クラスターに保存されているデータは、シャード間でパーティション化されます。シャードの数とシャードあたりのレプリカの数によって、クラスター内のノードの数が決まります。各シャードにプライマリノードとレプリカがあることを考慮すると、このクラスターには 8 つのノードがあることが予想されます。

Redis のバージョン互換性のために、6.2 を選択します。その他のオプションはすべてデフォルトのままにして、[Next] (次へ) を選択します。

コンソールのスクリーンショット。

[Advanced settings] (詳細設定) の [Security] (セキュリティ) セクションで、サブネットグループに使用した VPC のデフォルトのセキュリティグループを追加し、以前に作成したアクセスコントロールリスト (ACL) を選択します。MemoryDB ACL は Redis ACL に基づいており、クラスターに接続するためのユーザー認証情報と許可を提供します。

コンソールのスクリーンショット。

[Snapshot] (スナップショット) セクションでは、MemoryDB で毎日スナップショットが自動的に作成されるようにデフォルトのままにし、7 日間の保持期間を選択します。

コンソールのスクリーンショット。

[Maintenance] (メンテナンス) で、デフォルトのままにして [Create] (作成) を選択します。このセクションでは、重要なクラスターイベントが通知されるように、Amazon Simple Notification Service (SNS) トピックを指定することもできます。

コンソールのスクリーンショット。

数分後にクラスターが実行され、Redis コマンドラインインターフェイスまたは任意の Redis クライアントを使用して接続できます。

プライマリデータベースとしての Amazon MemoryDB の使用
顧客データの管理は、多くのビジネスプロセスの重要な要素です。新しい Amazon MemoryDB クラスターの耐久性をテストするために、これを顧客データベースとして使用したいと考えています。簡単にするために、REST API を使用して Redis クラスターから 1 つまたはすべての顧客データを作成、更新、削除、および取得できるようにする、シンプルなマイクロサービスを Python で構築してみましょう。

server.py 実装のコードは次のとおりです。

from flask import Flask, request
from flask_restful import Resource, Api, abort
from rediscluster import RedisCluster
import logging
import os
import uuid

host = os.environ['HOST']
port = os.environ['PORT']
db_host = os.environ['DBHOST']
db_port = os.environ['DBPORT']
db_username = os.environ['DBUSERNAME']
db_password = os.environ['DBPASSWORD']

logging.basicConfig(level=logging.INFO)

redis = RedisCluster(startup_nodes=[{"host": db_host, "port": db_port}],
            decode_responses=True, skip_full_coverage_check=True,
            ssl=True, username=db_username, password=db_password)

if redis.ping():
    logging.info("Connected to Redis")

app = Flask(__name__)
api = Api(app)


class Customers(Resource):

    def get(self):
        key_mask = "customer:*"
        customers = []
        for key in redis.scan_iter(key_mask):
            customer_id = key.split(':')[1]
            customer = redis.hgetall(key)
            customer['id'] = customer_id
            customers.append(customer)
            print(customer)
        return customers

    def post(self):
        print(request.json)
        customer_id = str(uuid.uuid4())
        key = "customer:" + customer_id
        redis.hset(key, mapping=request.json)
        customer = request.json
        customer['id'] = customer_id
        return customer, 201


class Customers_ID(Resource):

    def get(self, customer_id):
        key = "customer:" + customer_id
        customer = redis.hgetall(key)
        print(customer)
        if customer:
            customer['id'] = customer_id
            return customer
        else:
            abort(404)

    def put(self, customer_id):
        print(request.json)
        key = "customer:" + customer_id
        redis.hset(key, mapping=request.json)
        return '', 204

    def delete(self, customer_id):
        key = "customer:" + customer_id
        redis.delete(key)
        return '', 204


api.add_resource(Customers, '/customers')
api.add_resource(Customers_ID, '/customers/<customer_id>')


if __name__ == '__main__':
    app.run(host=host, port=port)

これは requirements.txt ファイルで、アプリケーションが必要とする Python モジュールを一覧表示します。

redis-py-cluster
Flask
Flask-RESTful

同じコードは、MemoryDB、ElastiCache、または任意の Redis Cluster データベースで動作します。

Linux Amazon Elastic Compute Cloud (Amazon EC2) インスタンスを MemoryDB クラスターと同じ VPC で起動します。MemoryDB クラスターに接続できるようにするため、デフォルトのセキュリティグループを割り当てます。また、インスタンスへの SSH アクセスを許可する別のセキュリティグループを追加します。

server.pyrequirements.txt ファイルをインスタンスにコピーし、依存関係をインストールします。

pip3 install --user -r requirements.txt

ここで、マイクロサービスを開始します。

python3 server.py

別のターミナル接続では、curl を使用して /customers リソースで HTTP POST を使用してデータベース内に顧客を作成します。

curl -i --header "Content-Type: application/json" --request POST \
     --data '{"name": "Danilo", "address": "Somewhere in London",
              "phone": "+1-555-2106","email": "danilop@example.net", "balance": 1000}' \
     http://localhost:8080/customers

この結果で、データが保存され、一意の ID (Python コードによって生成された UUIDv4) がフィールドに追加されたことを確認できます。

HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 172
Server: Werkzeug/2.0.1 Python/3.7.10
Date: Wed, 11 Aug 2021 18:16:58 GMT

{"name": "Danilo", "address": "Somewhere in London",
 "phone": "+1-555-2106", "email": "danilop@example.net",
 "balance": 1000, "id": "3894e683-1178-4787-9f7d-118511686415"}

すべてのフィールドは、customer:<id> として形成されたキーを持つ Redis Hash に格納されます。

前のコマンドを数回繰り返して、3 つの顧客を作成します。顧客データは同じですが、それぞれに一意の ID が付与されます。

ここで、HTTP GET を使用して /customers リソースにすべての顧客のリストを取得します。

curl -i http://localhost:8080/customers

コードには、SCAN コマンドを使用して一致するキーに対するイテレータがあります。 応答では、3 つの顧客のデータが表示されます。

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 526
Server: Werkzeug/2.0.1 Python/3.7.10
Date: Wed, 11 Aug 2021 18:20:11 GMT

[{"name": "Danilo", "address": "Somewhere in London",
"phone": "+1-555-2106", "email": "danilop@example.net",
"balance": "1000", "id": "1d734b6a-56f1-48c0-9a7a-f118d52e0e70"},
{"name": "Danilo", "address": "Somewhere in London",
"phone": "+1-555-2106", "email": "danilop@example.net",
"balance": "1000", "id": "89bf6d14-148a-4dfa-a3d4-253492d30d0b"},
{"name": "Danilo", "address": "Somewhere in London",
"phone": "+1-555-2106", "email": "danilop@example.net",
"balance": "1000", "id": "3894e683-1178-4787-9f7d-118511686415"}]

顧客の一人が残高を使い果たしたばかりです。ID (/customers/<id>) を含む顧客リソースの URL で HTTP PUT を使用してフィールドを更新します。

curl -i --header "Content-Type: application/json" \
     --request PUT \
     --data '{"balance": 0}' \
     http://localhost:8080/customers/3894e683-1178-4787-9f7d-118511686415

コードは Redis Hash のフィールドをリクエストのデータで更新しています。ここでは、残高をゼロに設定しています。ID で顧客データを取得して更新を検証します。

curl -i http://localhost:8080/customers/3894e683-1178-4787-9f7d-118511686415

応答では、残高が更新されていることがわかります。

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 171
Server: Werkzeug/2.0.1 Python/3.7.10
Date: Wed, 11 Aug 2021 18:32:15 GMT

{"name": "Danilo", "address": "Somewhere in London",
"phone": "+1-555-2106", "email": "danilop@example.net",
"balance": "0", "id": "3894e683-1178-4787-9f7d-118511686415"}

これが Redis の力です。 ほんの数行のコードでマイクロサービスのスケルトンを作成できました。さらに、MemoryDB は、バックエンドに別のデータベースを追加する必要なく、本番環境に必要な耐久性と高可用性を提供します。

ワークロードに応じて、MemoryDB クラスターを、ノードを追加または削除して水平方向にスケールしたり、より大きなノードタイプまたはより小さいノードタイプに移行して垂直方向にスケーリングしたりできます。MemoryDB は、シャーディングによる書き込みスケーリングと、レプリカの追加による読み取りスケーリングをサポートしています。クラスターのオンライン状態は継続し、サイズ変更オペレーション中に読み取りおよび書き込みオペレーションがサポートされます。

利用可能なリージョンと料金
Amazon MemoryDB for Redis は現在、米国東部 (バージニア北部)、欧州 (アイルランド)、アジアパシフィック (ムンバイ)、南米 (サンパウロ) で利用可能です。また、近日中には、さらに多くの AWS リージョンで利用可能となる予定です。

AWS マネジメントコンソールAWS Command Line Interface (CLI)、または AWS SDK を使用して MemoryDB クラスターを数分で作成できます。AWS CloudFormation のサポートが近日公開される予定です。ノードについては、MemoryDB は現在 R6g Graviton2 インスタンスをサポートしています。

ElastiCache for Redis から MemoryDB に移行するには、ElastiCache クラスターのバックアップを取得して MemoryDB クラスターに復元します。Amazon Simple Storage Service (Amazon S3) に保存されている Redis Database Backup (RDB) ファイルから新しいクラスターを作成することもできます。

MemoryDB では、ノードあたりのオンデマンドインスタンス時間、クラスターに書き込まれたデータの量、およびスナップショットストレージに基づいて、使用した分の料金が発生します。 詳細については、MemoryDB の料金のページを参照してください。

詳細はこちら
簡単な概要については、以下の動画をご覧ください。

プライマリデータベースとしての Amazon MemoryDB for Redis の利用を今すぐ開始しましょう。

Danilo

原文はこちらです。