Amazon Web Services ブログ

OracleDBからPostgreSQLへの移行

 

Knievel Co は、アマゾン ウェブ サービスのデータベースエンジニアです。

このブログ記事では、Oracle データベースを PostgreSQL に移行する方法の概要について説明します。データベース移行の2つの主要部分は、スキーマの変換とデータの複製です。)AWS スキーマ変換ツール (AWS SCT) と AWS Database Migration Service (AWS DMS) を使用して、これら 2 つの部分に取り組む方法について説明します。

SCT と DMSについて説明する前に、予備的な手順を実行する必要があります。これらは、すべての移行に役立つことが判明しています。移行を容易にする方法の 1 つは、移行の前に、通常更新フェーズと呼ばれるものを行うことです。このフェーズでは、Oracle データベース内のオブジェクトのインベントリを作成し、いくつかの決定を下します。

最初に、不要になったオブジェクトを削除します。オブジェクトの移行にかかる時間は誰も気にかけませんが、無駄にしないでください。また、不要になった履歴データを削除することもできます。一時的なテーブルや過去のメンテナンス時のテーブルのバックアップコピーなど、不要なデータを複製するために時間を無駄にすることはありません。次に、LOB、CLOB、LONG などに保存されているフラットファイルおよび長い文字列を Amazon S3 または Amazon Dynamo DB に移動します。このプロセスではクライアントソフトウェアの変更が必要となりますが、データベースが簡素化されサイズが削減されることで、システム全体がより効率的になります。最後に、PL/SQL パッケージとプロシージャを移動します。特にビジネスロジックを含むものをクライアントソフトウェアに戻してみます。これらのオブジェクトは、SCT が変換できない場合は手動で変更する必要があります。

次の手順は、異なるデータベースエンジン (この場合は Oracle から PostgreSQL へ) に移行するための手順です。別のプラットフォームに移動していない場合は、データベースを移動するためのより適切なネイティブツールやその他のテクニックがあります。

  1. ターゲットデータベースでスキーマを作成します。
  2. ターゲットデータベースの外部キーとセカンダリインデックスを削除し、トリガーを無効にします。
  3. データを複製するためのDMSタスクを設定します (全ロードと変更データキャプチャ (CDC))。
  4. 全ロードフェーズが完了したらタスクを停止し、外部キーとセカンダリインデックスを再作成します。
  5. DMS タスクを有効にします。
  6. ツールとソフトウェアを移行し、トリガーを有効にします。

ターゲットデータベースでスキーマを作成します。

移行するスキーマを確認して、移行を開始します。このケースでは、AWS スキーマ変換ツール (AWS SCT) を使用して分析を実行します。アプリケーションを起動するときは、ソースが Oracle でターゲットが PostgreSQL となる新しいプロジェクトを作成する必要があります。再接続したら、左側で移行するスキーマの名前を選択します。スキーマ名を右クリックし、[スキーマの変換] を選択します。次に、[View / Assessment Report View] を選択します。

AWS SCT 評価レポートは、Oracle データベースを PostgreSQL に変換するために必要な作業の高レベルな概要を示します。以下に示しているのは、評価レポートの具体的な例です。

 

このレポートは、各オブジェクトタイプごとに手動で変換するために必要な手作業を示しています。一般的に、パッケージ、プロシージャ、関数には解決すべきいくつかの問題があります。AWS SCT では、これらのオブジェクトを修正する理由を説明し、その方法のヒントを示します。

スキーマが自動的に変換されない場合の、問題を解決するためのヒントを次に示します。

  • ソースの Oracle データベースのオブジェクトを変更して、AWS SCT がそれらをターゲットの PostgreSQL に変換できるようにします。
  • スキーマをそのまま変換し、AWT SCT によって生成されたスクリプトを手動で変更してから、それらをターゲットの PostgreSQL データベースに適用してみてください。
  • 変換できないオブジェクトを無視して、機能を別の AWS サービスまたは同等のものに置き換えます。

スキーマの変換機能を改善すると、反復プロセスを経てレポートとスキーマを再生成できます。[Action Items] ビューには、変換プロセスを実行する際に生じる問題のリストが表示されます。変換されたスキーマの結果が満足のいくものであれば、それらをターゲットの PostgreSQL データベースに適用することができます。

ターゲットデータベースのスキーマを参照し、列のデータ型、オブジェクト名などを簡単ににチェックすることをお勧めします。ソースおよびターゲットのデータ型の詳細については、「AWS Database Migration Service リファレンス」を参照してください。 また、Oracle から PostgreSQL への変換であるため、オブジェクト名が Oracle では大文字で、PostgreSQL では小文字であることが問題となります。

外部キー制約とセカンダリインデックスを削除する。トリガーを無効にする

ターゲット上に必要なスキーマを揃えるするには、ソースから実際のデータを移行するためにスキーマを準備する必要があります。ここでは、AWS Database Migration Service (AWS DMS) を使用します。DMSには、全ロードと変更データキャプチャ (CDC) の 2 つのフェーズがあります。全ロードフェーズでは、テーブルは順不同でロードされます。したがって、ターゲットで制約を有効にすると、いくつかの外部キーで制約違反が発生します。また、全ロード時には表のレプリケーションが遅くなる可能性があるため、セカンダリインデックスを無効にする必要があります。これは、レコードがロードされるときにインデックスを維持する必要があるためです。

ターゲットの PostgreSQL データベースで、クエリを実行してデータベーステーブルの外部キー制約に DDL を生成し、出力を保存します。これを行うための多くのサンプルクエリをオンラインで見つけることができます。次のような情報が表示されます。これを実行すると、後で外部キー制約を再作成するための DDL が提供されます。

ALTER TABLE <テーブル名> ADD CONSTRAINT <制約名> FOREIGN KEY(キー列)REFERENCES <親テーブル名>(キー列)MATCH FULL;

同様に、DDL 生成クエリを実行して、ターゲットデータベース上のすべての外部キー制約を削除します。

ALTER TABLE <テーブル名> DROP CONSTRAINT <制約名>;

ここで、セカンダリインデックスについても同じことを行います。つまり、コマンドを作成し結果を生成してから、セカンダリインデックスを削除します。

次に、トリガーを無効にします。

ALTER TABLE <テーブル名> DISABLE TRIGGER ALL;

ID 列でシーケンスを使用する場合は、ターゲットでシーケンスを作成するときに、次の値をソースデータベースよりも高く設定することをお勧めします。十分なギャップを残して、移行カットオーバーの日付で値がソースのデータベースの値よりも高くなっていることを確認してください。このアプローチによって、移行後のシーケンス ID の競合が回避されます。

DMS タスクを設定してデータをレプリケートする

ターゲットの PostgreSQL データベースでスキーマの準備ができました。これでデータをレプリケートする準備が整いました。これは DMS が入る場所となります。DMS の素晴らしい点は、各テーブルのデータをレプリケートするのではなく、移行する準備ができるまで CDC モードでデータを最新の状態で保持することです。

ソース Oracle データベースの準備:

  • Oracle ログインに必要な権限を確認します。
  • DMS が Oracle ソースデータベースから変更を取得するために必要なサプリメンタルロギングを設定します。
  • ソース Oracle データベースの準備の詳細については、DMS ドキュメントを参照してください。

AWS コンソールで DMS を起動します。最初に、レプリケーションインスタンスを作成する必要があります。レプリケーションインスタンスが DMS タスクを実行します。このインスタンスは、ソース Oracle データベースとターゲット PostgreSQL データベースの両方に接続する中間サーバーです。適切なサイズのサーバーを選択します。特に、複数のタスクの作成、多数のテーブルの移行、またはその両方を行う場合は、適切なサーバーを選択します。

次に、ソースデータベースのエンドポイントとターゲットデータベースのエンドポイントを作成します。Oracle データベースと PostgreSQL データベースの適切な接続情報をすべて入力します。各エンドポイントの作成が完了する前に、接続テストが成功した後で必ずスキーマの更新オプションを選択し、テストを実行 してください。

これで、タスクを作成する準備ができました。タスク名を入力し、作成したレプリケーションインスタンス、およびソースおよびターゲットエンドポイントを選択します。[移行タイプ] で、[既存データの移行と進行中の変更のレプリケート] を使用します。スキーマを事前に作成するためにAWS SCTを使用しているため、[ターゲットテーブル準備モード][何もしない] または [切り詰め] を選択します。

オプション [全ロードの完了後にタスクを停止する] で、[キャッシュされた変更の適用後に停止] を選択します。完全ロードが完了し、キャッシュされた変更が適用された後で、タスクを一時的に停止します。キャッシュされた変更は、テーブル全体のロードプロセスが実行されている間に発生し蓄積された変更です。これは、CDC が適用される直前のステップです。

できれば、ソース Oracle データベースを更新して、LOB を S3、DynamoDB、または別の同様のサービスに移動します。そうでない場合は、LOB を処理する方法についていくつかのオプションがあります。すべてのテーブルの LOB 全体をレプリケートする場合は、[レプリケーションに LOB 列を含める] で、[完全 LOB モード] を選択します。LOB を特定の長さまでレプリケートするのみの場合は、[制限付き LOB モード] を選択します。移行する LOB の長さは、[最大 LOB サイズ (KB)] テキストボックスで指定します。

最後に、[ログ作成の有効化] を選択して、タスクで発生したエラーや警告を確認し、問題のトラブルシューティングを行えるようにすることをお勧めします。[タスクの作成] を選択します。

次に、[テーブルマッピング] で移行するスキーマを選択し、[選択ルールの追加] を選択します。[JSON] タブを選択します。[JSON の編集を有効にする] チェックボックスを選択します。次に、次の JSON 文字列を入力し、スキーマ名 DMS_SAMPLE を使用するスキーマ名に置き換えます。

 

{

 "rules": [

  {

   "rule-type": "selection",

   "rule-id": "1",

   "rule-name": "1",

   "object-locator": {

    "schema-name": "DMS_SAMPLE",

    "table-name": "%"

   },

   "rule-action": "include"

  },

  {

   "rule-type": "transformation",

   "rule-id": "6",

   "rule-name": "6",

   "rule-action": "convert-lowercase",

   "rule-target": "schema",

   "object-locator": {

    "schema-name": "%"

   }

  },

  {

   "rule-type": "transformation",

   "rule-id": "7",

   "rule-name": "7",

   "rule-action": "convert-lowercase",

   "rule-target": "table",

   "object-locator": {

    "schema-name": "%",

    "table-name": "%"

   }

  },

  {

   "rule-type": "transformation",

   "rule-id": "8",

   "rule-name": "8",

   "rule-action": "convert-lowercase",

   "rule-target": "column",

   "object-locator": {

    "schema-name": "%",

    "table-name": "%",

    "column-name": "%"

   }

  }

 ]

}

この JSON 文字列は、PostgreSQL の場合、スキーマ名、テーブル名、列名を小文字に変換します。

タスクが作成されると、自動的に開始されます。タスクを選択して[ステータス] タブをクリックすると、DMS コンソールを使用して進行状況を監視できます。全ロードが完了しキャッシュされた変更が適用されると、タスクは自動的に停止します。

全ロードフェーズが完了したらタスクを停止し、外部キーとセカンダリインデックスを再作成します。

テーブルのロードが完了しました。今度は、ログを確認してタスクにエラーがないことを確認するのがよいでしょう。

タスクの次のフェーズは、ソースデータベースで発生した順序で変更を適用する CDC です。このアプローチは、親テーブルがターゲットデータベース上の子テーブルの前に更新されるため、外部キーを再作成できることを意味します。

必要に応じて生成されたスクリプトを調整して、以前に削除された外部キーとセカンダリインデックスを再作成します。セカンダリインデックスはタスクのこのフェーズで重要となります。このフェーズは重要です。なぜなら、where 句を使用してソースデータベースに対して行われた更新は、ターゲットデータベース上のインデックスのルックアップでもあるからです。更新に欠落しているインデックスがある場合、これらの更新は全テーブルスキャンとして実行されます。

ソースからのデータを更新できるため、移行の切り替えまでトリガーを有効にしないでください。

DMS タスクを有効にする

これで外部キーとセカンダリインデックスが戻ったので、DMS タスクを有効にすることができます。DMS コンソールに移動して、[タスク] を選択します。リストでタスクを選択し、[開始/再開] を選択します。[開始] オプションを選択し、[タスクの開始] を選択します。

ツールとソフトウェアを移行し、トリガーを有効にします。

最後に、カットオーバーポイントがここにあります。ツールとソフトウェアの接続がソースデータベースへのアクセスを停止し、DMS タスクが最後のデータ変更をターゲットデータベースにレプリケートしたら、DMS コンソールで DMS タスクを停止します。次に、ターゲットデータベースでトリガーを有効にします。

ALTER TABLE <テーブル名> ENABLE TRIGGER ALL;

最後のステップは、アプリケーションを新しいターゲット PostgreSQL データベースに再配置して再起動することです。完了です。

役立つヒント

スキーマを変換しやすくするには、AWS SCT を使用して評価レポートを取得し、アクション項目を反復処理します。ターゲット PostgreSQL スキーマの最終バージョンに到達するまで、ターゲットスキーマを複数回生成する必要があります。
新しいスキーマのクエリが新しいプラットフォームで機能するようにするには、ターゲットシステムでアプリケーションをテストします。AWS SCT は、アプリケーションクエリを PostgreSQL に変換することもできます。詳細については、AWS SCT ドキュメントを参照してください。また、ターゲットシステムの負荷テストを実装して、ターゲットサーバーのサイズとデータベース設定が正しいことを確認します。
前に概要を説明した実際の移行手順を実践し、プロセスを合理化します。上記の手順は単なる出発点に過ぎず、各データベースは一意のものです。

詳細情報

また、次を検討することをお勧めします。

AWS SCT および AWS DMS のドキュメント
DMS のステップバイステップチュートリアル
DMS のベストプラクティス
GitHub の DMS サンプルデータベース
関連するブログ記事: SQL を使用して Oracle から PostgreSQL へユーザー、ロール、および許可をマップする

詳解: Amazon ECSのタスクネットワーク

この記事はECSのSr. Software Dev EngineerのAnirudh Aithalの寄稿です。

2017年11月14日に、AWSはコンテナにElastic Network InterfaceをアタッチできるようにするAmazon ECSのTask Networkingを発表しました。

この記事では、ECSが管理するインスタンス(コンテナインスタンスと呼ばれます)上でContainer Networking Interfaceプラグインを使って、この新しいコンテナネイティブなawsvpcネットワークモードがどのように実装されているかを詳しくご紹介したいと思います。

こちらはAmazon ECSでタスクネットワークが動作するかにdeep diveしたものです。もし自身のコンテナ化したアプリケーションでどうやってタスクネットワークを使い始めれば良いかについて学びたい時には、Amazon ECSコンテナにCloud Native Networkingが登場をご覧下さい。Cloud Native Computing Foundation (CNCF)がContainer Networking Interface (CNI)プロジェクトをホストしており、Linuxコンテナでネットワークインターフェースを設定するためのプラグインを書くための仕様やライブラリが含まれています。AWSのクラウドネイティブコンピューティングについての詳細は、Adrian CockcroftのCloud Native Computingについての投稿をご覧下さい。

コンテナインスタンスのセットアップ

コンテナインスタンス上でのタスクネットワーク有効化の詳細をご説明する前に、ECSの典型的なインスタンスがどのようになっているかを見てみましょう。

上の図は典型的なコンテナインスタンスを示しています。ECS agentは自身もコンテナとして実行されているのですが、以下のような責任を負っています:

  • EC2インスタンスをECSのバックエンドに登録
  • コンテナインスタンスに対してECSバックエンドが発生させたタスク状態の変化を、正しく適応
  • Dockerデーモンと会話しながら、コンテナの作成、開始、停止、監視
  • コンテナの状態とタスクの状態の遷移をECSバックエンドにリレー

ECS agentはその管理下のコンテナのスーパーバイザーの様に動作するので、Dockerデーモン(Dockerのデフォルトネットワークモードで設定されたコンテナ用)、又はCNIプラグイン達(ネットワークモードがawsvpcで設定されたタスク内のコンテナ)のための、ネットワーク設定をする難しさをオフロードしてくれます。

いずれの場合にも、コンテナのネットワークスタックは、ネットワークのnamespaceを通じて設定されます。ip-netns(8)のマニュアルによると「ネットワークnamespaceは論理的なネットワークスタックのコピーで、自身のルーティング、ファイアウォールルール、ネットワークデバイスを持っています。」 とあります。ネットワークnamespaceの構成によって、ホスト上で動いているプロセスやコンテナ間でのネットワークスタックの隔離を可能としてくれます。

ネットワークnamespaceとCNIプラグイン

CNIプラグインとは、CNI仕様を満たしコンテナのネットワーク接続性の設定を行う実行ファイル群です。CNIプロジェクトではプラグインの仕様を定義し、プラグインが利用するライブラリを提供することで、一貫していて信頼でき、かつ簡素なプラグイン用のインタフェースを提供してくれます。

コンテナやネットワークnamespaceを指定してプラグインを呼び出す時に、ADDコマンドでコンテナにネットワークインターフェースを追加したり、DELコマンドでそれを落としたりします。例えばリファレンスのBridgeプラグインは、ホストネットワークnamespaceの中にいるブリッジに対してホスト上の全てのコンテナを追加します。

このプラグインのモデルはECS agentの「コンテナのライフサイクルへの最小限の介入」というモデルと相性が良く、agentはコンテナのネットワーク設定の詳細について考慮する必要がなくなります。また拡張性の高いモデルなので、将来必要になった時には、agentが異なるプラグイン群を利用できるようにスイッチさせることもできます。最後に、これらプラグインは必要な時に呼び出されるだけなので、その死活監視をECS agentがする必要はありません。

ECS agentからCNIプラグインを呼び出す

ECSがElastic Network Interfaceをインスタンスにアタッチし、agentに対しそのElastic Network Interfaceをタスク内のコンテナに対してプロビジョンするようにメッセージを送った時には、(任意のネットワークデバイスを使う) そのElastic Network Interfaceはホストのグローバルデフォルトネットワークnamespaceに現れてきます。ECS agentは複数のCNIプラグインを順番に呼び出すことで、そのElastic Network Interfaceがコンテナのネットワークnamespaceに正しく設定されていることを保証してくれます。これらのプラグインはamazon-ecs-cni-pluginsのGitHubレポジトリで見ることができます。

最初に呼び出されるものはecs-eniプラグインで、Elastic Network Interfaceがコンテナのネットワークnamespaceにアタッチされ、VPCから割り当てられたIPアドレスとサブネットのゲートウェイに対するデフォルトルートが設定されていることを保証します。コンテナは更にIAMロールの認証情報を得るために、(ECS agentが提供している) 認証情報エンドポイントにHTTPリクエストできるようになる必要があります。これはその次に実行されるecs-bridgeecs-ipamプラグインによって処理されます。CNIのライブラリはこれらのプラグインの実行結果を解釈する仕組みを提供しているので、agent上で効果的にエラーをハンドリングすることができます。以下の図は、このプロセスのそれぞれのステップを図解したものです:

ネットワークスタックの設定とアプリケーションコンテナの中で実行されるコマンドのレースコンディションを避けるために、ECS agentはタスク毎にそのタスク定義内にあるコンテナを開始する前に、pauseコンテナを作成します。その後、前述のCNIプラグイン群を実行することで、pauseコンテナのネットワークnamespaceをセットアップします。それからタスクにある残りのコンテナ達を開始するので、pauseコンテナのネットワークスタックを共有します。これは、タスク内の全てのコンテナはElastic Network InterfaceのIPアドレスによって到達可能であり、かつlocalhostインタフェースを通じて互いに通信することができることを意味しています。

このセットアップ例では、1つのElastic Network Interfaceの後ろに2つのコンテナを持った1つのタスクがあります。以下のコマンドでそれらが同じネットワークスタックを持っていて、localhostインタフェースを通して互いに会話可能であることを見ていきましょう。

ホスト上で実行している最新3つのコンテナをリストする (タスクで起動した2つのコンテナと、ECS agentが追加で起動したネットワークnamespaceの設定用コンテナ):

$ docker ps -n 3 --format "{{.ID}}\t{{.Names}}\t{{.Command}}\t{{.Status}}"
7d7b7fbc30b9	ecs-front-envoy-5-envoy-sds-ecs-ce8bd9eca6dd81a8d101	"/bin/sh -c '/usr/..."	Up 3 days
dfdcb2acfc91	ecs-front-envoy-5-front-envoy-faeae686adf9c1d91000	"/bin/sh -c '/usr/..."	Up 3 days
f731f6dbb81c	ecs-front-envoy-5-internalecspause-a8e6e19e909fa9c9e901	"./pause"	Up 3 days

3つのコンテナのインタフェースをリストし、それらが同じであることを確認する:

$ for id in `docker ps -n 3 -q`; do pid=`docker inspect $id -f '{{.State.Pid}}'`; echo container $id; sudo nsenter -t $pid -n ip link show; done
container 7d7b7fbc30b9
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff

container dfdcb2acfc91
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff

container f731f6dbb81c
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff

まとめ

以上の仕組みによって、新しいawsvpcネットワークモードを使うことができ、コンテナに対してネイティブなネットワークサポートによる利便性を享受することができます。awsvpcモードの詳しい使い方は、Amazon ECSコンテナにCloud Native Networkingが登場ECSドキュメントをご覧下さい。

GitHubのECS CNIプラグインECS Agentのレポジトリで私にフィードバック頂けると幸いです。

原文: Under the Hood: Task Networking for Amazon ECS (翻訳: SA岩永)

Amazon ECSコンテナにCloud Native Networkingが登場

この記事はECSのSr. Software Dev EngineerのAnirudh Aithalの寄稿です。

2017年11月14日に、AWSはAmazon ECSのTask Networkingを発表しました。これによって、Elastic Network Interfaceを使ったAmazon EC2のネットワーク機能をタスクに持ち込むことができるようになります。

Elastic Network InterfaceはVPC内のインスタンスにアタッチすることができる仮想的なネットワークインタフェースです。EC2の仮想マシンを起動する時には、インスタンスにネットワークの機能を提供するために自動的に1つのElastic Network Interfaceがプロビジョンされます。

タスクは実行されるコンテナの論理的なグループです。これまでは、Amazon ECSで実行されるタスクはそれが動くEC2ホストのElastic Network Interfaceを共有していました。これからは、新しいawsvpcというネットワークモードを使うことで、Elastic Network Interfaceが直接タスクにアタッチされます。

これによってネットワークの設定を簡略化することができ、VPCが持っているネットワークの全機能、隔離性、そしてセキュリティの制御を各コンテナにEC2インスタンスと同様のレベルで利用することができます。

この記事では、awsvpcモードがどのように動作し、ECSのタスクでどのようにElastic Network Interfaceを使い始めることができるかをご紹介します。

背景: EC2のElastic Network Interface

VPC内にEC2インスタンスを起動する時には、各インスタンスが互いに通信できるようにするために、追加のオーバーレイネットワークを設定する必要はありません。標準で、VPCのルーティングテーブルがインスタンスや他のエンドポイント間での通信をシームレスに実現してくれます。これは、Elastic Network Interfaceと呼ばれるVPC内の仮想的なネットワーク・インタフェースによって可能となっています。全ての起動されるEC2インスタンスは自動的に1つのElastic Network Interface(プライマリネットワークインタフェース)がアサインされます。サブネット、セキュリティグループといった全てのネットワークパラメータは、このプライマリネットワークインタフェースの属性として扱われます。

さらに、各Elastic Network Interfaceは作成時にVPCによってIPv4アドレス(プライマリIPv4アドレス)が割当られます。このプライマリアドレスはユニークでVPC内でルーティング可能なものです。これによって、VPCは実際はフラットなネットワークとなり、ネットワークトポロジを簡潔なものとしてくれます。

Elastic Network InterfaceはVPC上で多様なエンドポイントとの接続を実現するための基本的なビルディングブロックとみなすことができ、そのうえでより高レベルな抽象レイヤを構築することができます。これによってElastic Network Interfacdeは以下の機能を利用することが可能となっています:

  • VPCネイティブなIPv4アドレスとルーティング (VPC上でのインスタンス間や他のエンドポイントとの間)
  • ネットワークトラフィックの隔離
  • ACLとファイアウォールルール(セキュリティグループ)を使ったネットワークポリシーの強制
  • (サブネットのCIDRを通じた)IPv4アドレスレンジの強制

なぜawsvpcを使うのか?

以前はECSはDockerが提供する標準のネットワークの挙動が提供するネットワーク機能に依存した形でコンテナ向けのネットワークスタックを構成していました。デフォルトのBridgeネットワークモードでは、インスタンス上のコンテナ達はdocker0ブリッジを使って互いにつながっています。インスタンス外のエンドポイントと通信する時には、コンテナはこのブリッジを利用し、それが実行されているインスタンスのプライマリネットワークインタフェースを使います。コンテナは、ファイアウォールルール(セキュリティグループ)やIPアドレスは、そのプライマリElastic Network Interfaceのネットワーク属性を共有しまた依存しています。

これは、Dockerによって割当られたIPアドレス(ローカルスコープのアドレスプールから割当られます)を使ってもこれらのコンテナに到達できないことと、細かいNetwork ACLやファイアウォールルールを強制できないことを意味します。代わりに、VPCからはインスタンスのプライマリElastic Network InterfaceのIPアドレスと、マップされたホスト側のポート番号(静的か動的なポートマッピング)の組み合わせによって、コンテナに到達することができます。また、1つのElastic Network Interfaceが複数のコンテナで共有されているので、各コンテナに最適なネットワークポリシーを簡単に作成することが難しくなっています。

awsvpcネットワークモードでは、タスク毎にElastic Network Interfaceをプロビジョンすることによって、これらの課題を解決しています。従って、コンテナ達はこれらのリソースを共有もせず干渉することももはやありません。これによって、以下のことが可能となります:

  • 複数のコンテナのコピーを同じインスタンス上で同じコンテナポートを使っていても、ポートマッピングの様なことをせずに実行することができ、アプリケーションの構成を簡素化できます。
  • 共有ブリッジで帯域が干渉することがないので、アプリケーションのネットワークパフォーマンスを向上させられます。
  • 各Amazon ECS タスクにセキュリティグループのルールを紐付けることで、コンテナ化したアプリケーションに緻密なアクセス制御を強制することができるので、アプリケーションのセキュリティを向上できます。

タスク内のコンテナにセキュリティグループを紐付けることで、送信元のポートとIPアドレスで受け付けるネットワークトラフィックを制限することができます。例えば、インスタンスにはSSHアクセスを許可するが、コンテナにはそれを許可しないということが可能です。あるいは、HTTPのトラフィックを80番ポートでコンテナは受付可能とするポリシーを強制するが、インスタンスではブロックするといったことができます。このようなセキュリティグループのルールを強制することによって、インスタンスもコンテナも攻撃にさらされる範囲を限りなく狭めることができます。

ECSはタスクのためにプロビジョンされるElastic Network Interfaceのライフサイクルを管理しており、オンデマンドで作成し、タスクが停止したら削除します。EC2インスタンスを起動する時と全く同じプロパティをタスクに指定することができます。こうしたタスクの中にあるコンテナは以下のような特徴を持ちます:

  • Elastic Network InterfaceのIPアドレスとDNS名で到達可能
  • Application Load BalancerとNetwork Load BalancerにIPターゲットとして登録可能
  • VPC Flow Logで観測可能
  • セキュリティグループでアクセス制御可能

これはまた、全く同じタスク定義から複数のタスクを同じインスタンス上で実行するときに、ポートの衝突を心配する必要をなくしてくれます。Bridgeネットワークモードの時にはあった、共有のdocker0ブリッジでのポートの変換や帯域の干渉が不要となるので、より高いパフォーマンスを得ることもできます。

始めてみよう

まだECSクラスタを持っていなければ、クラスタ作成ウィザードを使って1つ作成することができます。この記事ではawsvpc-demoをクラスタ名として使います。また、コマンドラインの手順を行うのであれば、最新バージョンのAWS CLISDKをインストールしていることを確認してください。

タスク定義を登録する

タスクネットワークの為にタスク定義で変更する必要がある唯一のものは、ネットワークモードのパラメータをawsvpcにするだけです。ECSコンソールでは、この値はNetwork Modeに入力します。

もしこのタスク定義のコンテナをECSサービスへ登録しようと思っている場合には、コンテナポートをタスク定義で指定します。この例ではNGINXコンテナは80番ポートを開放するように指定しています:

これでnginx-awsvpcという名前のタスク定義が作成され、ネットワークモードがawsvpcに設定されています。以下のコマンド群は、コマンドラインでタスク定義を登録する方法を示しています:

$ cat nginx-awsvpc.json
{
        "family": "nginx-awsvpc",
        "networkMode": "awsvpc",
        "containerDefinitions": [
            {
                "name": "nginx",
                "image": "nginx:latest",
                "cpu": 100,
                "memory": 512,
                "essential": true,
                "portMappings": [
                  {
                    "containerPort": 80,
                    "protocol": "tcp"
                  }
                ]
            }
        ]
}

$ aws ecs register-task-definition --cli-input-json file://./nginx-awsvpc.json

タスクを実行する

このタスク定義でタスクを実行するために、Amazon ECSコンソールのクラスタ画面に行き、Run new taskを選択します。nginx-awsvpcのタスク定義を指定します。次に、このタスクを実行するサブネットの集合を指定します。これらサブネットの少なくとも1つにはECSに登録されたインスタンスが必要です。そうしないと、ECSはElatic Network Interfaceをアタッチする候補を見つけることができません。

コンソールを使うと、Cluster VPCの値を選ぶことで、サブネットの候補を絞り込むことができます:

次に、タスクのセキュリティグループを選択します。この例では、新しいセキュリティグループを作成し、80番ポートの内向きのみを許可します。もしくは、既に作成済のセキュリティグループを選択することもできます。

次に、Run Taskをクリックしてタスクを実行します。

これで実行中のタスクができました。タスクの詳細画面をみると、Elastic Network Interfaceが割り当てられていることと、そのElatic Network Interfaceに紐付いたIPアドレスを確認することができます:

コマンドラインを使って同じことができます:

$ aws ecs run-task --cluster awsvpc-ecs-demo --network-configuration "awsvpcConfiguration={subnets=["subnet-c070009b"],securityGroups=["sg-9effe8e4"]}" nginx-awsvpc $ aws ecs describe-tasks --cluster awsvpc-ecs-demo --task $ECS_TASK_ARN --query tasks[0]
{
    "taskArn": "arn:aws:ecs:us-west-2:xx..x:task/f5xx-...",
    "group": "family:nginx-awsvpc",
    "attachments": [
        {
            "status": "ATTACHED",
            "type": "ElasticNetworkInterface",
            "id": "xx..",
            "details": [
                {
                    "name": "subnetId",
                    "value": "subnet-c070009b"
                },
                {
                    "name": "networkInterfaceId",
                    "value": "eni-b0aaa4b2"
                },
                {
                    "name": "macAddress",
                    "value": "0a:47:e4:7a:2b:02"
                },
                {
                    "name": "privateIPv4Address",
                    "value": "10.0.0.35"
                }
            ]
        }
    ],
    ...
    "desiredStatus": "RUNNING",
    "taskDefinitionArn": "arn:aws:ecs:us-west-2:xx..x:task-definition/nginx-awsvpc:2",
    "containers": [
        {
            "containerArn": "arn:aws:ecs:us-west-2:xx..x:container/62xx-...",
            "taskArn": "arn:aws:ecs:us-west-2:xx..x:task/f5x-...",
            "name": "nginx",
            "networkBindings": [],
            "lastStatus": "RUNNING",
            "networkInterfaces": [
                {
                    "privateIpv4Address": "10.0.0.35",
                    "attachmentId": "xx.."
                }
            ]
        }
    ]
}

awsvpcのタスクの詳細を見ると、Elastic Network Interfaceの詳細についてはattachmentsオブジェクトとして値が返ってきます。containersオブジェクトの中でもこの情報を見ることができます。例:

$ aws ecs describe-tasks --cluster awsvpc-ecs-demo --task $ECS_TASK_ARN --query tasks[0].containers[0].networkInterfaces[0].privateIpv4Address
"10.0.0.35"

まとめ

nginxコンテナはVPC上で10.0.0.35というIPv4アドレスでアクセスすることが可能です。80番ポートでリクエストを受け付けるために、インスタンスのセキュリティグループを編集する必要はありませんので、インスタンスのセキュリティを向上できます。また、アプリケーションの改修を全くせずに、80番ポート以外の全てのポートがブロックされていることも保証できるので、ネットワーク上でタスクの管理が簡単になります。Elastic Network InterfaceのAPI操作はECSが全て面倒を見てくれるので、何もする必要がありません。

タスクネットワークの機能に関するより詳しい情報はECSのドキュメントをご覧下さい。この新しいネットワークモードがインスタンス上でどのように実装されているかの詳細は、詳説: Amazon ECSのタスクネットワークをご覧下さい。

原文: Introducing Cloud Native Networking for Amazon ECS Containers (翻訳: SA岩永)

Amazon ElastiCache for Redis を使ったChatアプリの開発

Sam Dengler は、アマゾン ウェブ サービスのソリューションアーキテクトです。

このブログ記事では、チャットアプリケーションに関連する概念とアーキテクチャのパターンについて説明します。また、チャットクライアントとサーバーの実装の詳細、サンプルのチャットアプリケーションを AWS アカウントに展開する方法についても説明します。

背景情報

チャットアプリケーションを構築するには、クライアントがチャットルームの他の参加者に再配信されるメッセージを送信できる通信チャネルが必要となります。この通信は、一般に publish-subscribe パターン (PubSub) を使用して実装されます。このパターンでは、メッセージが中央トピックチャネルに送信されます。関係者は、このチャンネルをサブスクライブして更新の通知を受けることができます。このパターンでは、発行者の知識なしに受信者のグループを拡大または縮小できるように、発行者と受信者を切り離しています。

PubSubは、クライアントが WebSockets を使用して通信するバックエンドサーバーに実装されます。WebSockets は、クライアントとサーバー間で双方向にストリーミングされるデータのチャネルを提供する永続的な TCP 接続です。単一サーバアーキテクチャでは、1 つの PubSub アプリケーションが発行者と受信者の状態を管理し、WebSocket を介してクライアントにメッセージを再配布することもできます。次の図は、単一サーバー PubSub アーキテクチャ上の 2 つのクライアント間でメッセージが WebSocket を通過するパスを示しています。

単一サーバーアーキテクチャは、通信フローを説明するのに役立ちます。しかし、ほとんどのソリューションビルダーはマルチサーバーアーキテクチャで設計したいと考えています。マルチサーバーアーキテクチャは、信頼性を高め、伸縮性を高め、クライアントの数が増えるにつれてアプリケーションを水平的に拡大するのに役立ちます。

マルチサーバーアーキテクチャでは、クライアントはサーバープールにトラフィックを転送するロードバランサーに対して WebSocket 接続を行います。これらのサーバーは、WebSocket 接続とそれを経由してストリーミングされるデータを管理します。WebSocket 接続が PubSub アプリケーションサーバーとの間で確立されると、その接続は永続化され、データは両方向のアプリケーションにストリームされます。ロードバランサーは、WebSocket 接続のリクエストを健全なサーバーに配信します。つまり、2 つのクライアントが異なるアプリケーションサーバーに WebSocket 接続を確立できます。

 

複数のアプリケーションがクライアントの WebSocket 接続を管理するため、アプリケーションはメッセージを再配布するためにそれらの間で通信する必要があります。この通信が必要なのは、メッセージが WebSocket を介して 1 つのアプリケーションサーバーにストリームアップされ、別のアプリケーションサーバーに接続されたクライアントにストリームダウンされる必要があるためです。クライアント接続を管理しているアプリケーションから PubSub ソリューションを外部に出すことで、アプリケーション間の共有通信の要件を満たすことができます。

 

次の図は、マルチサーバー PubSub アーキテクチャ上の 2 つのクライアント間でメッセージが WebSocket を通過するパスを示しています。永続的な接続は、各クライアントと WebSocket サーバー間のロードバランサーを通じて確立されます。また、永続的な接続は、WebSocket サーバーと PubSub サーバー間で、すべてのクライアント間で共有されるサブスクリプショントピックごとに確立されます。

 

 

カスタムの PubSub ソリューションも可能ですが、既存のソフトウェアアプリケーションを使用してこの機能を提供することもできます。Redis は、高速なオープンソースのインメモリ型データストアおよびキャッシュで、PubSub をサポートしています。Amazon ElastiCache for Redis は、Redis 対応のインメモリサービスです。使いやすく、Redis の性能を利用でき、もっとも要求の厳しいアプリケーションに対応できる可用性、信頼性、パフォーマンスを提供します。

Using ElastiCache for Redis and the WebSocket support found in the that is part of Elastic Load Balancing の一部である Application Load Balancer にある ElastiCache for Redis と WebSocket サポートを使用して、サンプルのチャットアプリケーションを構築する方法を説明します。アプリケーションには、Node.js と AWS Elastic Beanstalk に基づくバックエンドと、Vue.js ウェブクライアントがあります。サンプルアプリケーションのすべてのコードは、すべて elasticache-redis-chatapp GitHub リポジトリにあります。

アーキテクチャ

次の図は、Redis、Application Load Balancer、Node.js Elastic Beanstalk アプリケーション、および Vue.js ウェブクライアント用の ElastiCache を使用した AWS の最終的なアーキテクチャを示しています。

チャットアプリケーションの実装を高いレベルで見てみましょう。

実装の概要

サンプルチャットアプリケーションは、以下のスクリーンショットに示す共有チャットルームで通信するメンバーとメッセージで構成されています。

このサンプルアプリケーションでは、メンバー登録、プロフィール管理、ログインを拒否しています。代わりに、ブラウザでチャットアプリケーションを開くと、ユーザーの代わりにランダムなユーザー名とアバターでメンバーが生成されます。この名前とアバターは、左側のメンバーリストに表示されます。他のメンバーがブラウザでアプリケーションを開いて参加したり離したりすると、その名前がウェブアプリケーションに表示されます。メンバーは、他のウェブクライアントに再配信されメインのチャットウィンドウに表示されるメッセージを送信できます。

次に、Vue.js ウェブクライアントの詳細を調べ、Node.js バックエンドアプリケーションを確認します。

Vue.js ウェブクライアント

ウェブクライアントは、ビューレイヤを管理する Vue.js、UI 用の Bootstrap、および WebSocket 通信用の Socket.io を使用して実装されています。初心者向けに複雑さを軽減するために、JavaScript バンドルは使用していません。ただし、本稼働アプリケーションでは webpack または類似のソフトウェアを検討する必要があります。Vue.js は、基礎となるデータモデルの更新に基づいて UI の変更をレンダリングします。これらのフレームワークとライブラリを、最新の単一ページの代表的なウェブアプリケーションとして選択しました。ただし、コミュニティには多くの類似した選択肢があり、毎日多くのものが出現しています。

次に、Vue.js アプリケーションコンポーネントを設定する HTML マークアップのコードスニペットと、メンバーを表示するイテレーターを示します。機能に焦点を当てるために、いくつかの中間的なマークアップと CSS スタイルを削除しています。。完全なサンプルは GitHub リポジトリにあります。

<html>
<body>
    <div id=”app”>
        <li v-for="(value, key) in members">
            <img v-bind:src="value.avatar">
            <small>{{ value.username }}</small>
        </li>
    </div>

v-for パラメータは、イテレーターを定義するために使用されます。この場合は、この後で説明するメンバーオブジェクトデータモデルのキー値タプルです。反復されるループ内で Mustache テンプレートを使用して、各メンバーオブジェクトにアクセスし、ユーザー名を表示します。Mustache テンプレートは HTML 属性内では機能しないため、メンバーのアバター画像 URL を解決するためには v-bind 引数を使用する必要があります。

Vue.js は、スマート DOM の差の計算に基づいて UI の変更を最小限にレンダリングします。このアプローチにより、基になる Vue.js データモデルの状態変更に専念できます。サンプルアプリケーションでは、HTML 内で JavaScript コードをインライン展開しています。しかし、本番稼働用システムでは、外部の .vue ファイルを使用して UI コンポーネントをモジュール化し、ビルド時に webpack を使用して変換する可能性があります。Socket.io ライブラリも初期化されており、多少カバーされています。

<script src="js/vue/2.1.10/vue.min.js"></script>
<script src="js/socket.io/1.7.2/socket.io.min.js"></script>
<script>
    var socket = io();

    new Vue({
        el: '#app',
        data: {
            message: '',
            messages: [],
            members: {}
        }

ここでは、Vue.js アプリケーションを宣言し、アプリケーション ID で HTML div 要素にバインドしました。また、次の 3 つのデータモデルを宣言しました。

  • message: フォームに入力されたメッセージテキスト
  • messages: メッセージのリスト。メッセージを追加するだけなので、配列が使用されます。
  • messages: メンバーのリスト。メンバーがチャットルームを離れたときにメンバーを見つけて削除できるように、オブジェクトが使用されています。

マークアップおよび Vue.js アプリケーション宣言に加えて、ウェブクライアントは WebSocket 接続を確立し、サブスクライブするトピックを宣言し、それらのトピックに発行されたメッセージが前に宣言されたデータモデルをどのように変更するかを確立します。このアプリケーションでは、コミュニケーションのための 5 つのトピックを確立します。それぞれのトピックが、トリガーイベントと対応するアクションとともに示されます。

[メッセージ]

トリガー: メッセージがチャットルームに送信される。

アクション: メッセージテキストおよびメンバーメタデータを使用して、メッセージのリストを更新します。

[member_add]

トリガー: メンバーがチャットルームに参加する。

アクション: メンバーのユーザー名とパスワードをメンバーのリストに追加します。

[member_delete]

トリガー: メンバーがチャットルームを離れる。

アクション: メンバーの一覧からメンバーを削除します。

[message_history]

トリガー: クライアントがメッセージのリストを初期化。

アクション: メッセージのリストを、最近の履歴メッセージの切り詰められたリストとして設定します。

[member_history]

トリガー: クライアントがメンバーのリストを初期化。

アクション: メンバーリストをチャットルームに参加しているメンバーのリストとして設定します。

 

以下に、これらのメソッドを実装するための JavaScript コードを示します。以前の Vue.js コードをリファレンスポイントとして維持しています。

new Vue({
    el: '#app',
    data: {
        message: '',
        messages: [],
        members: {}
    },
    methods: {
        send: function() {
            socket.emit('send', this.message);
            this.message = '';
        },
    mounted: function() {
        socket.on('messages', function(message) {
            this.messages.push(message);
        }.bind(this));

        socket.on('member_add', function(member) {
            Vue.set(this.members, member.socket, member);
        }.bind(this));

        socket.on('member_delete', function(socket_id) {
            Vue.delete(this.members, socket_id);
        }.bind(this));

        socket.on('message_history', function(messages) {
            this.messages = messages;
        }.bind(this));

        socket.on('member_history', function(members) {
                    this.members = members;
        }.bind(this));
    }

以前のコードスニペットで宣言された Socket.io オブジェクトは、前述のトピックごとに 1 つずつ、socket.on を使用してデータトピックにサブスクライブします。メッセージがトピックに発行されると、コールバック関数が実行されます。データモデルは、アクション (セット、追加、削除) とターゲットデータモデル (配列、オブジェクト) に従って更新されます。バインド (this) 文が追加され、Vue.js データモデルがコールバック関数スコープに挿入されます (詳細については、Function.prototype.bind を参照してください)。

最後は、メッセージフォームの送信を処理する Vue.jsメソッドです。Vue.js は、フォーム提出をメソッドにバインドする便利なメソッドを提供します。このメソッドは、WebSocket 上にメッセージテキストを発行し、メッセージを空の文字列に設定します。この文字列は、Vue.js バインディングを使用して UI を更新します。

Node.js バックエンドアプリケーション

ここでは、ウェブクライアントの基本について説明しました。次に、Node.js バックエンドアプリケーションについて見ていきましょう。PubSub を使ってデータを保持し、WebSocket メッセージを再配布するために Redis がどのように使用されるかを見ていきます。

Redis と WebSockets の設定

ウェブクライアントがブラウザで開かれると、PubSub アプリケーションで WebSocket が確立されます。接続すると、アプリケーションは既存のメンバーとメッセージを新しいクライアントに発行するために、いくつかのデータをアセンブルする必要があります。また、新しいチャットルーム参加者について他のクライアントを更新する必要があります。次に、HTTP アプリケーションと WebSocket の宣言を示すコードスニペットを示します。

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var port = process.env.PORT || 3000;

WebSocket リスナーの作成に加えて、アプリケーションは Redis クラスタへの複数の接続も確立する必要があります。 Redis データモデルを更新してトピックにメッセージを発行するには、1 つの接続が必要です。 トピックのサブスクリプションごとに追加の接続が必要になります。

var Redis = require('ioredis');
var redis_address = process.env.REDIS_ADDRESS || 'redis://127.0.0.1:6379';

var redis = new Redis(redis_address);
var redis_subscribers = {};

function add_redis_subscriber(subscriber_key) {
    var client = new Redis(redis_address);

    client.subscribe(subscriber_key);
    client.on('message', function(channel, message) {
        io.emit(subscriber_key, JSON.parse(message));
    });

    redis_subscribers[subscriber_key] = client;
}
add_redis_subscriber('messages');
add_redis_subscriber('member_add');
add_redis_subscriber('member_delete');

このコードスニペットでは、
Redis コマンドチャネルは ioredis JavaScript クライアントを使用して確立されています。
また関数は、新しいトピックのチャンネルを初期化するためにも定義され、
チャンルのトピックについてキー入力されたすべての受信者のハッシュに追加されます。
各サブスクリプションチャネルは同じように機能します。

  • Redis サブスクリプションチャンネルで JSON 文字列メッセージを受信します。
  • JSON 文字列を JavaScript オブジェクトに解析します。
  • Redis PubSub と同じトピックを使用して、JavaScript オブジェクトを WebSocket 接続に発行します。

この後で説明するように、JavaScript オブジェクトは、Redis データ型の値として保存され、PubSub トピックに発行されるときに JSON 文字列にシリアル化されることが重要です。WebSocket を介して発行する前に、JSON 文字列を JavaScript オブジェクトに逆シリアル化して戻す必要があります。Socket.io ライブラリがクライアントと通信するときには、オブジェクトをシリアル化したり逆シリアル化したりするため、この逆シリアル化が生じる必要があります。

ウェブクライアントがブラウザのチャットルームに参加すると、クライアントは WebSocket への新しい接続を確立します。次のような関数を定義することによって、この接続が確立されたときにアクションを実行できます。

io.on('connection', function(socket) {

... application business logic ... 

}

ソケットは、クライアントへの各 WebSocket 接続を識別するために使用される ID プロパティを含むオブジェクトです。socket.id 値を使用して、メンバーを識別します。この識別により、Redis データモデルからメンバーを見つけて削除することができます。また、member_delete トピックを使用しているすべてのチャットルームクライアントにメンバーの削除を伝えることもできます。以下で説明する他の関数は、このコールバック関数のコンテキストにあります。

次のセクションでは、新しいクライアントが WebSocket を介して Node.js バックアップアプリケーションに接続すると何が起こるかを見ていきます。

新しいクライアント接続の初期化

新しいクライアントがチャットルームに参加すると、いくつかのことが起こります。

現在のメンバーリストが取得されます。
これがクライアントの再接続でない限り、ランダムなユーザー名とアバター URL で新しいメンバーが作成され、Redis Hash に保存されます。
最近の履歴メッセージの切り詰められたリストが検索されます。
これらのタスクを達成するためのコードを見てみましょう。まず、次のコードがあります。

var get_members = redis.hgetall('members').then(function(redis_members) {
    var members = {};
    for (var key in redis_members) {
        members[key] = JSON.parse(redis_members[key]);
    }
    return members;
});

ioredis JavaScript クライアントは、非同期実行処理で Promises を使用します。HGETALL (‘members’) 呼び出しは、キー ‘members’に格納されているハッシュのすべてのキーと値を返します。Redis はハッシュデータ型をサポートしていますが、1 レベルの深さしかありません。ハッシュの値は文字列でなければなりません。コールバック関数は、次のチェーンで逆シリアル化されたハッシュのキーと値のペアを反復して、メンバーを初期化します。

var initialize_member = get_members.then(function(members) {
    if (members[socket.id]) {
        return members[socket.id];
    }

    var username = faker.fake("{{name.firstName}} {{name.lastName}}");
    var member = {
        socket: socket.id,
        username: username,
        avatar: "//api.adorable.io/avatars/30/" + username + '.png'
    };
    
    return redis.hset('members', socket.id, JSON.stringify(member)).then(function() {
        return member;
    });
});

initialize_member Promise 関数は、メンバーが再接続ソケットであるかどうかをまずチェックします。再接続ソケットでない場合は、Faker を使用してランダムなユーザー名で新しいメンバーが生成されますこのユーザー名から、Adorable Avatars サービスを使用してランダムなアバター URL が生成されます。

クライアント初期化の最後のステップは、過去の最近のメッセージの切り捨てられたリストを取得することです。これを行うには、ソート対象セットと呼ばれる別の Redis データ型を利用することができます。このタイプは Redis セットに似ていますが、セット内の各要素のランクを含みます。ソート対象セットは、リーダーボードの一般的なデータ型です。タイムスタンプがランクとして使用されている場合は、時間順に並べられた要素のコレクションを格納するためにも使用できます。

var get_messages = redis.zrange('messages', -1 * channel_history_max, -1).then(function(result) {
    return result.map(function(x) {
       return JSON.parse(x);
    });
});

We use a Redis method on the Sorted Set, called ZRANGE というソート対象セットでは、ランクに基づいて要素のリストを返す Redis メソッドを使用します。要素は最低スコアから最高スコアまで並べられます。したがって、初期化時に取得するメッセージの最大数 (-1 * channel_history_max) まで最後の要素 (-1) を取得する必要があります。繰り返しになりますが、各要素は JSON 文字列としてシリアル化されていますので、要素を JavaScript オブジェクトに対して逆シリアル化する必要があります。

要約すると、新しいクライアントがチャットルームに参加すると、いくつかのことが起こります。

  1. 現在のメンバーリストが取得されます。
  2. これがクライアントの再接続でない限り、ランダムなユーザー名とアバター URL で新しいメンバーが作成され、Redis Hash に保存されます。
  3. 最近の履歴メッセージの切り詰められたリストが検索されます。

これらの手順をそれぞれを確認しました。ここで、初期化とクライアントへのストリームデータの完了方法を見ていきましょう。ioredis は Promise を使用するため、非同期の実行を連鎖させて、すべてが完了するのを待ってから Promise.all を使用して結果を処理できます。

Promise.all([get_members, initialize_member, get_messages])
    .then(function(values) {
        var members = values[0];
        var member = values[1];
        var messages = values[2];

...

)};

これですべての必要なデータが得られたので、WebSocket 接続を使用してデータをストリーミングして新しいクライアントを初期化し、新しいメンバーがチャットルームに参加したことをすべてのメンバーに伝える必要があります。

io.emit('member_history', members);
io.emit('message_history', messages);
redis.publish('member_add', JSON.stringify(member));

Socket.io の emit メソッドを使用して、初期化中のクライアントにメッセージとメンバーのリストをストリーミングします。1 つの WebSocket を使用して複数のメッセージを送信できます。ここでは、トピック (member_history, message_history) は先ほどのクライアントコードでレビューしたトピックリスナーに対応しています。新しいメンバーはすべての参加者に伝えなければなりません。これを行うには、Redis コマンドチャネルを使用して、シリアル化された JSON 文字列を member_add トピックに発行します。すでに行っているように、WebSocket を使用して同じトピックをリッスンしているクライアントにメッセージを再配布するため、3 つの Redis トピックを設定しました。

次のセクションでは、チャットルームで送信されたメッセージを処理するハンドラを設定する方法を見ていきましょう。

メッセージの処理

新しいクライアントが初期 WebSocket 接続を完了すると、新しいクライアントによって送信されるメッセージ用のメッセージハンドラも定義する必要があります。メッセージは、メッセージテキスト、メンバーのユーザー名、メンバーのアバター、メッセージの作成タイムスタンプで構成されます。

socket.on('send', function(message_text) {
    var date = moment.now();
    var message = JSON.stringify({
        date: date,
        username: member['username'],
        avatar: member['avatar'],
        message: message_text
    });

    redis.zadd('messages', date, message);
    redis.publish('messages', message);
});

ZADD コマンドとメッセージ作成タイムスタンプをランクとして使用して、ソート対象セットに格納されたメッセージ履歴にメッセージを追加します。最後に、Redis コマンドチャネルを使用してメッセージトピックを発行しました。Redis/WebSockets の再配布は以前に定義しています。

クライアントを初期化し、チャットルームで送信されたメッセージを処理する方法について説明しました。最後に、クライアントがチャットルームを離れるときの対処方法を見てみましょう。

切断処理

Socket.io は、クライアントがサーバーに接続するときに確立された WebSocket のハートビートを作成します。ハートビートが失敗すると、クライアントで切断イベントが発生します。

socket.on('disconnect', function() {
    redis.hdel('members', socket.id);
    redis.publish('member_delete', JSON.stringify(socket.id));
});

クライアントが切断すると、メンバーの初期化中に実行されたアクションが取り消されます。まず、Redis HDEL メソッドを使用して、クライアントの WebSocket ソケット ID を使用するメンバーハッシュ Redis データ型からクライアントを削除します。同じメソッドをクライアントをハッシュに追加するのに使用します。すべての参加者に対してチャットルームに加わった新しいメンバーを通知するように、メンバーがチャットルームを離れることをすべての参加者に通知する必要があります。これは、member_delete Redis トピックを使用して行います。このトピックは、WebSocket を使用して残りのクライアントに再配布されます。

これでコードの確認は完了です。次に、AWS CloudFormation を使用してアプリケーションスタックを AWS にデプロイする方法を確認します

AWS CloudFormation を使用したアプリケーションスタックのデプロイ

CloudFormation は、開発者やシステム管理者は、関連する AWS リソースのコレクションを簡単に作成および管理する方法を提供します。CloudFormation は、整った予測可能な方法でリソースを提供し、更新します。チャットアプリケーションの CloudFormation スタックを起動するには、次のボタンをクリックします。

CloudFormation スクリプトは、Elastic Beanstalk 環境、アプリケーション、および構成テンプレートを作成します。Redis の ElastiCache クラスタと、ロードバランサ、アプリケーションサーバー、Redis クラスタの Amazon EC2 セキュリティグループも作成します。このようにして、アーキテクチャレイヤ間の最小権限セキュリティ構成にベストプラクティスを使用します。

ElisiCache for Redis の設定スニペットに関する 1 つの注意点AWS::EC2::SecurityGroup では進入セキュリティルールのインライン指定が可能ですが、そうすることで、CacheCluster と SecurityGroup の間に循環参照が作成されてしまいます。次のスニペットに示すように、進入ルールを別の AWS::EC2::SecurityGroupIngress に分割して循環参照を破棄する必要があります。

リソース:

RedisCluster:
    Type: AWS::ElastiCache::CacheCluster
    Properties:
      CacheNodeType:
        Ref: ClusterNodeType
      VpcSecurityGroupIds:
        - !GetAtt CacheSecurityGroup.GroupId
      Engine: redis
      NumCacheNodes: 1
  CacheSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cache security group
  CacheSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !GetAtt CacheSecurityGroup.GroupId
      IpProtocol: tcp
      FromPort: !GetAtt RedisCluster.RedisEndpoint.Port
      ToPort: !GetAtt RedisCluster.RedisEndpoint.Port
      SourceSecurityGroupId: !GetAtt ApplicationSecurityGroup.GroupId

次に、WebSocket をサポートするための Elastic Beanstalk Nginx プロキシ設定の設定を変更する方法を確認してみましょう。

WebSocket サポートのための AWS Elastic Beanstalk の Nginx 設定

AWS Elastic Beanstalk は、Java、.NET、PHP、Node.js、Python、Ruby、Go および Docker を使用して開発されたウェブアプリケーションやサービスを、Apache、Nginx、Passenger、IIS など使い慣れたサーバーでデプロイおよびスケーリングするための、使いやすいサービスです。

Elastic Beanstalk は、Elastic Load Balancer (ELB) と Application Load Balancer (ALB) の両方をサポートします。弊社のクライアントとサーバーは WebSocket を使用して通信するので、WebSockets サポートのための ALB を構成しますサンプルの Node.js バックエンドアプリケーションでは、Node.js ベースの Elastic Beanstalk の事前構成済みアプリケーションスタックを選択します。アプリケーションコードの前で、ウェブ層プロキシとして Nginx を使用します。

WebSocket がサポートされていない場合、Socket.io にはポーリング戦略に戻る手段があります。ただし、単純に ALB と Nginx に設定を変更することで、WebSocket のサポートを有効にし、サーバーからクライアントへのプッシュベースのデータストリームを使用することができます。ALB で WebSocket サポートを有効にするには、クライアントが 2 つの連続した HTTP リクエストを行って接続をアップグレードして Websocket を使用したときに、同じインスタンスが応答するように、スティッキーセッションを有効化する必要があります。Nginx で WebSocket サポートを有効にするには、Elastic Beanstalk の .ebextensions メカニズムを使用して、Nginx の設定を少し変更する必要があります。コンテナコマンドは、アプリケーションアーカイブが展開された後、アクティブアプリケーションとしてインストールされる前に、アプリケーションに変更を導入する方法を提供します。

container_commands:
  enable_websockets:
    command: |
      sed -i '/\s*proxy_set_header\s*Connection/c \
              proxy_set_header Upgrade $http_upgrade;\
              proxy_set_header Connection "upgrade";\
      ' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf

前述のコードスニペットは、Nginx 設定ファイルを所定の位置で変更します。/tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf。これは、sed コマンドを使用して「プロキシセットヘッダー」行を検索し、WebSocket をサポートする設定に置き換えます。アプリケーションがインストールされると、Elastic Beanstalk は設定ファイルを /etc/nginx/conf.d/00_elastic_beanstalk_proxy.conf にコピーします。この手順を実行すると、Nginx サービスが再起動され変更がアクティブになります。

まとめ

このブログ記事では、publish-subscribe パターンについて見てきました。また、それを ElastiCache for Redis 内で使用して、チャットアプリケーションの複数のクライアントの双方向ストリーミング通信をサポートする方法についても説明しました。

リマインダーとして、awslabs GitHub リポジトリにこのサンプルアプリケーションの完全なソースがあります。このサンプルアプリケーションを起動したら、ユーザー認証、添付ファイル、または自分のチャットや PubSub アプリケーションに役立つその他の機能を追加して、チャットアプリケーションに独自のアイデアを組み込んで拡張することをお勧めします。

がんの早期発見を促進するために Matrix Analytics が AWS でディープラーニングを使用

Matrix Analytics は人の命を救うために使われています。コロラド州のスタートアップ企業は肺結節と診断された患者の疾患の進行経過を追うために、アマゾン ウェブ サービス (AWS) でディープラーニングを使用しています。大方の場合、結節が良性でも慎重に監査したりフォローアップ治療を行うことは、結節が悪性腫瘍になった場合に重要な意味を持つことになります。

同社の設立者である Dr. Aki Alzubaidi 氏は、Glenwood Springs 病院に勤務していた時に見過ごされている患者が何人もいることに気付きました。患者の様子を把握するためのシステムは面倒な上にまとまりがなく、肺結節と診断された多くの患者が推奨されているフォローアップ治療を受けていないという、避けられるはずの粗末な結果を生み出していました。

がんリスクの予測と治療の管理

同社のフラッグシップアプリケーションである LungDirect は、初期のがん介入に二面性を持つアプローチを使用して悪性の危険性を予測したりフォローアップ治療を自動化しています。

まず、ディープラーニングのアルゴリズムを使用して構築した高度なコンピュータビジョン機能は、肺結節の悪性のリスクを結節の大きさや形、密度、容積、そして患者の喫煙年数、年齢、性別、人種などをもとに診断します。「放射線検査、臨床検査、個人的な臨床レベルでの変化など、臨床的な情報を考慮に入れ、病状について説明し次の対策に関する実用的な提案と管理方法を提供することが、ディープラーニングを利用する我々が目指すゴールです」と Dr. Alzubaidi 氏は述べています。

データに潜んでいるかもしれない非線形性クラスから成るがんリスクの診断を行うために、Machine Learning の 5 つのクラスを適用しています。こうした機能の 4 つのクラスは、一連のコンピュータビジョンアルゴリズムを使用してイメージから直接自動的に抽出されます。

がんの予測や診断を行うために、患者のスキャンを自動的に読み取れるツールを開発することは簡単ではありませんでした。けれども、Matrix Analytics は PoC (実証支援) を示すプロトタイプを素早く開発することができました。次に、当社のディープラーニングモデルを実装して、既存の論文で表示されている基準と比較しました。

(more…)

Amazon ElastiCache の更新 – Redis クラスターのオンラインサイズ変更

Amazon ElastiCache では、高速なインメモリ型データストアおよびキャッシュを簡単にセットアップできます。ElastiCache は、最も人気のある 2 種類のオープンソースのソフトウェア (Redis および Memcached) をサポートしているため、要求の高いゲームのリーダーボードやインメモリアナリティクス、大規模なメッセージングのニーズに対応できます。

本日は、Amazon ElastiCache for Redis に追加された重要な機能についてご紹介します。最大 15 のシャードを作成して、それぞれに特定のスロットセットのキーと値を保存することができます (各クラスターの厳密なスロット数は 16,384 個)。1 つのクラスターで 3.55 テラバイトのインメモリデータを保存できると同時に、1 秒あたり 2,000 万回の読み取りと 450 万回の書き込みが可能です。

オンラインのサイズ変更
実行中の Redis 用 Amazon ElastiCache クラスターでシャード数を調整しながら、そのクラスターのオンライン状態を維持してリクエストに応答できるようになりました。これにより、クラスターをオフラインにしたり、空のキャッシュを使用しなくても、トラフィックやデータのボリュームの変更に対応することができます。また、シャード数を変更せずに、実行中のクラスターを再分散してスロットスペースを均一に再配置することもできます。

リシャーディングオペレーションまたは再分散オペレーションを開始すると、Redis 用 ElastiCache は、クラスターのシャード間でスロットが均等分散されるように計画の準備を開始します。その後、シャード全体にスロットを転送し、効率性を重視して並列的に多数のスロットを移動します。これは、クラスターでリクエストに応答する場合に行われ、送信時のスロットへ書き込む書き込みスループットが少し上がります。移行率は、インスタンスタイプ、ネットワーク速度、スロットへの読み込み/書き込みトラフィックによって異なり、通常 1 分あたり約 1 ギガバイトです。

リシャーディングオペレーションと再分散オペレーションは、クラスタモードを有効にして作成された Redis クラスターに適用されます。

クラスターのリシャーディング
一般的に、大幅なメモリプレッシャーの問題に直面したり、個々のノードがボトルネックになった場合は、リシャーディングでクラスターを拡張します。クラスターの CloudWatch メトリクスを監視すれば、以下のような状況を識別できます。

メモリプレッシャー – FreeableMemory、SwapUsage、BytesUsedForCache。

CPU ボトルネック – CPUUtilization、CurrConnections、NewConnections。

ネットワークボトルネック – NetworkBytesIn、NetworkBytesOut。

これらのメトリクスを監視するには CloudWatch ダッシュボード、リシャーディングプロセスを自動化するには CloudWatch アラームを使用できます。

ElastiCache ダッシュボードから Redis クラスターをリシャーディングするには、該当するクラスターをクリックして詳細ページに移動後、[Add shards] ボタンをクリックします。

シャード数、(必要に応じて) 目的のアベイラビリティーゾーンを入力し、[Add] をクリックします。

クラスターのステータスが「変更中」に変わり、リシャーディングプロセスが開始します。前述のとおり、このプロセスは数分から数時間かかります。クラスターの詳細ページで進捗を追跡できます。

シャード間を移動しているスロットを表示できます。

クラスターのイベントを監視することもできます。

リシャーディング中、KEYSSMEMBERS コマンド、および大量の演算を行う Lua スクリプトは実行しないでください。クラスターのシャードで適切にロードを行うためです。FLUSHDBFLUSHALL コマンドは一切使用しないでください。これらのコマンドを使用すると、リシャーディングプロセスは中断され、停止します。

プロセスが完了すると、各シャードのステータスは [Available] に戻ります。

シャード削除時にも同様のプロセスが行われます。

スロットの再分散
このオペレーションを実行する方法については、クラスターの詳細ページに移動し、「スロット配置の再分散」をクリックします。

主要事項
この新機能には、いくつかの注意事項があります。

エンジンバージョン – クラスターが Redis エンジンのバージョン 3.2.10 を実行している必要があります。

移行サイズ – シリアル化後、256 メガバイトより大きいアイテムを含むスロットは移行されません。

クラスターエンドポイント – リシャーディングまたは再分散を行っても、クラスターエンドポイントは変更されません。

提供開始
この機能はすでに提供が開始されているので、今すぐ使い始めることができます。

Jeff;

12 月の AWS Black Belt オンラインセミナーのご案内

こんにちは。プロフェッショナル サービスの宮本です。AWS Black Belt オンラインセミナー12月の配信についてご案内させて頂きます。サービスカットは、10/24 に Generally Available を迎えた Amazon Aurora with PostgreSQL Compatibility をはじめ、今月も様々なテーマを取り扱います。また、ソリューションカットは、「AWSサービスを利用したアプリケーション開発を始めよう」と題して、AWSにおけるアプリケーション開発に活用できる様々なサービスについてご紹介や、AWSにおけるIPv6のサポート状況についてご紹介します。

 

 

 

 

 

 

 

 

 

 

 

 

12月の開催予定

サービスカット
12/6(水) 18:00-19:00 Amazon Elasticsearch Service
12/14(木) 18:00-19:00 Amazon ElastiCache ※ 通常の開催曜日と異なりますのでご注意ください。
12/20(水) 18:00-19:00 Aurora PostgreSQL

ソリューションカット
12/1(金) 12:00-13:00 AWS re:Invent 2017 Report  ※ 通常の開催曜日と異なりますのでご注意ください。
12/5(火) 12:00-13:00 AWSのIPv6対応
12/12(火) 12:00-13:00 AWSサービスを利用したアプリケーション開発を始めよう

お申し込みは、それぞれ上記のリンクより行って頂けます。キャンセルの際も連絡不要ですので是非お早めにご登録ください。Speaker、Staff 一同みなさまのご参加をお待ちしております。

SSML の新しい声道機能を使用して Amazon Polly の声の音色を変更

本日、Amazon Polly チームは、開発者がテキスト読み上げ (TTS) 音声の音色を変更できるようにする、新しい音声合成マークアップ言語 (SSML) 機能のリリースを発表します。これは、Amazon Polly ポートフォリオの既存の音をカスタマイズし、ユースケース用に探している特定のペルソナの音に近づけることを希望するお客様にとって魅力的な機能です。特に、多くの異なる音が関連するシナリオを持つお客様にとって有益です。音色機能により、利用可能な各 Amazon Polly の声から複数の音のペルソナを簡単にカスタマイズできるためです。

音色とは

音色は、ピッチや大きさとは独立した、音の知覚色または品質を表します。これは、よく音楽で金管楽器と弦楽器の違いを指摘したり、ビオラとバイオリンの微妙な区別を表したりする場合などに使用されます。音色は、各楽器が同じボリュームで同じ音符を演奏していても、それぞれを区別する知覚属性です。音声においても同様に、ピッチ (基本周波数) と大きさ (振幅) が同じでも、音色により 1 つの声が別の声から区別されます。

各個人の声の音は、その人物の生理機能や発声方法を含むさまざまな要素により、独自のものになります。個人の声帯、声道、そして体全体の大きさや形でさえも、その人物の標準的な音声品質を形作るうえで重要な役割を果たします。人の舌の位置、筋肉を緊張または弛緩させる方法、空気圧を加える方法は、声のピッチ、ボリューム、音色を変えるための技法の一部にすぎません。訓練を受けた物まね役者は、自分の声をまるで他人のように変えることができるレベルまで、これらの動きを制御する方法を会得しています。

声道とピッチ

音声の音色に貢献する重要な生理機能として、声道があります。これは声帯上部から唇の端までにおよぶ空気の通り道です。声道を長くしたり短くしたり、または広げたり狭めたりして、その形を変更できるようにするさまざまな筋肉があります。こうした変更の効果によって、音声が増幅または除去されて聞こえます。

ピッチは、音声を高く、または低く聞こえるようにする聴覚属性です。音声生成においては、ピッチは声帯の振動周波数によって決定されます。一般的に、女性の声帯は男性と比較して短く、より多く (1 秒あたり 180~200 回) 振動します。男性の声帯は平均的により長く、より少なく (1 秒あたり 最大 110 回) 振動します。同様に、平均的な声道の長さは、女性が男性よりも短くなっています (最大 14cm 対最大 17cm)。

声帯の長さと声道の長さとの間には自然な相関関係があり、どちらか 1 つが大きければ、もう一方も大きくなる傾向があります。音色機能では、開発者がピッチを制御する機能を維持しながら、声道の大きさを変更することができます。

声道と音声合成

vocal-tract-length SSML タグを使用して話者の声道の長さを変更することで、入力音声の音色を制御できるようになりました。これは話者の体の大きさを変更したかのように聞こえます。 vocal-tract-length を変更すると、話者の音声は体が大きくなったかのように聞こえます。このタグを小さくすると、小さい体のような音になります。このタグは Amazon Polly のテキスト読み上げポートフォリオのいずれの声にも使用できます。

話者の声道の長さを変更する方法は次のとおりです。

  • +n% または -n%: 現在の声で、相対割合 (%) の変更により声道の長さを調整します。たとえば、+4%、-2% などです。
  • n%: 現在の声の絶対割合値 (%) に声道の長さを調整します。たとえば、104%、98% などです。
  • 声道の長さは、最大 +100% まで長くし、最小 -50% まで短くできます。
  • 声道の長さを現在の声のデフォルト値にリセットするには、<amazon:effect vocal-tract-length=“100%”> を使用します。

次の例では、Mizuki の声を使用して、声道の長さを変更する方法を示します。

<speak>
これは変更のない私の元の声です。<amazon:effect vocal-tract-length="+15%"> ここで、私の体がとても大きくなったことを想像してみてください。</amazon:effect> <amazon:effect vocal-tract-length="-15%"> 
または、私がとても小さくなったときの声をお望みですか? </amazon:effect> より細かい調整により、私の
声の音色をさらに制御できます。<amazon:effect vocal-tract-length="+10%"> たとえば、音を少し大きくしてみます。</amazon:effect> <amazon:effect vocal-tract-length="-10%"> または、少しだけ音を小さくします。</amazon:effect> 
</speak> 
聞く

Amazon Polly の声

(more…)

今すぐご利用可能 – Amazon EC2 コンピューティング最適化インスタンス C5

新しくコンピューティングに最適化されたC5インスタンスが、3つのAWSリージョン、6つのインスタンスサイズでリリースされ、今日から利用可能であることを発表することに興奮しています!

これらのインスタンスは、バッチ処理、分散解析処理、高性能コンピューティング(HPC)、広告配信、スケーラブルなマルチプレーヤゲーミング、ビデオエンコーディングなどのコンピューティング重視のアプリケーション用に設計されています。 新しいインスタンスは、C4インスタンスに対して25%の価格/パフォーマンスの向上をもたらし、一部のワークロードでは50%を上回ります。 また、vCPUあたりの追加メモリ(新しいAVX-512命令を使用できるコードにおいて)は、2倍のベクターおよび浮動小数点演算のパフォーマンスを備えています。

AWSによって設計、構築された専用ハードウェアにさまざまな種類の作業をオフロードすることに長期的に視点を置き、最高のネットワーク、ストレージ、およびコンピューティングパフォーマンスを顧客に提供するために、私たちは長年にわたりノンストップで取り組んできました。 C5インスタンスタイプには、最新世代のハードウェアオフロードが組み込まれており、ハードウェアに手を加えて新しいハイパーバイザーを追加することで、さらに大きな前進を遂げています。新しいハイパーバイザーを使用すると、ホストハードウェアが提供するすべての処理能力にアクセスすることができます。同時に、パフォーマンスをより一貫して強化し、さらにセキュリティを強化します。 私たちはAWS re:Inventで、それに関する多くの技術的な詳細を共有します。

新しいインスタンス
C5インスタンスは6つのサイズが利用可能です:

Instance Name vCPUs
RAM
EBS Bandwidth Network Bandwidth
c5.large 2 4 GiB Up to 2.25 Gbps Up to 10 Gbps
c5.xlarge 4 8 GiB Up to 2.25 Gbps Up to 10 Gbps
c5.2xlarge 8 16 GiB Up to 2.25 Gbps Up to 10 Gbps
c5.4xlarge 16 32 GiB 2.25 Gbps Up to 10 Gbps
c5.9xlarge 36 72 GiB 4.5 Gbps 10 Gbps
c5.18xlarge 72 144 GiB 9 Gbps 25 Gbps

各vCPUは、3.0 GHz Intel Xeon Platinum 8000シリーズプロセッサのハードウェアハイパースレッドコアです。 EC2用に最適化されたこのカスタムプロセッサは、2つの最大サイズのC-stateを完全に制御できるため、Intel Turbo Boost Technologyを使用して単一コアで最大3.5GHzで動作できます。

この表からわかるように、4つの最小インスタンスサイズは、前世代のコンピューティング最適化インスタンスよりも大幅に拡張されたEBSならびにネットワーク帯域幅を提供します。

すべてのネットワーキングおよびストレージ機能はハードウェアで実装されているため、C5インスタンスにはElastic Network Adapter(ENA) およびNVMe用のドライバを含むHVM AMIが必要です。 最新のAmazon Linux、Microsoft Windows、Ubuntu、RHEL、CentOS、SLES、Debian、およびFreeBSD AMIはすべてC5インスタンスをサポートしています。 もし機械学習の推論処理やその他のコンピューティングが重視される作業を行っている場合は、最新のバージョンのIntel Math Kernel Libraryを確認してください。 インテル®Xeon®Platinumプロセッサー用に最適化されており、作業を大幅に高速化する可能性があります。

Xenハイパーバイザーを使用するインスタンスとの互換性を維持するために、EBSボリュームのデバイス名は、引き続き既存の/dev/sdおよび/dev/xvd のプレフィックスを使用します。 NVMeドライバが独自のデバイス名を割り当てるため、インスタンスにボリュームを接続するときに指定したデバイス名は使用されません(詳しくは、Amazon EBSおよびNVMeを参照してください)。

nvmeコマンドは、各ボリュームに関する追加情報を表示します (必要に応じてsudo yum -y install nvme-cliを使用してインストールします)。

出力のSNフィールドは、 “vol”プレフィックスの後に ” – “を挿入することでEBSボリュームIDにマッピングできます (悲しいことに、NVMe SNフィールドがID全体を格納するのに十分な長さではありません)。 この情報を使用して、接続されている各ボリュームのEBSスナップショットを作成する簡単なスクリプトを次に示します。

$ sudo nvme list | \
  awk '/dev/ {print(gensub("vol", "vol-", 1, $2))}' | \
  xargs -n 1 aws ec2 create-snapshot --volume-id

もう少し作業 (そして多くのテスト) をすれば、一杯になっているEBSボリュームを拡張するスクリプトを作成できます。

Getting to C5

先ほどお話したように、私たちはハードウェアアクセラレータに処理をオフロードする努力をかなり前から行なっています。 ここに要約します:

CC12010年ローンチ、CC1はスケールアウトHPCアプリケーションをサポートするように設計されています。 10 Gbpsネットワーキングをサポートする最初のEC2インスタンスと、HVM仮想化をサポートする最初のEC2インスタンスでした。 CC1用に設計したネットワークファブリック(独自のスイッチハードウェアに基づく)は、すべてのAWSデータセンターの標準となっています。

C32013年ローンチ、C3ではEnhanced Networkingが導入され、各仮想プライベートクラウド(VPC)内のソフトウェア定義ネットワークをサポートする専用のハードウェアアクセラレータが使用されています。 ハードウェア仮想化は、ゲストOSによる直接アクセスを優先してI / Oスタックをハイパーバイザから削除し、より高いパフォーマンスと変動性の低減をもたらします。

C42015年ローンチ、C4インスタンスはデフォルトで専用ネットワーク接続によってEBS最適化され、EBSの処理(暗号化されたEBSボリュームに対するCPUでの暗号化処理を含む)をハードウェアアクセラレータにオフロードします。

C5 – 本日ローンチ、C5インスタンスに動力を与えるハイパーバイザーは、ホストCPUのほとんどのリソースをお客様のインスタンスに費やすことを可能にします。 ENAネットワーキングとEBSへのNVMeインターフェイスはどちらもハードウェアアクセラレータによって駆動されます。 インスタンスは、効率を高めるために除去されたXen準仮想化ネットワーキングまたはブロックデバイスドライバを必要としません(またはサポートしません)。

今後はこのハイパーバイザーを使用して他のインスタンスタイプを強化します、そしてAWS re:Inventのセッションで追加の技術的な詳細を共有する予定です。

本日C5を発表

オンデマンドとスポット(リザーブドインスタンスも利用可能)で、米国東部(バージニア)、米国西部(オレゴン)、EU(アイルランド) リージョンでC5インスタンスを今すぐ起動できます。なお対象リージョンの追加作業を行なっています。

使用前の簡単な注意点:現在のNVMeドライバは高性能シーケンシャルワークロード用に最適化されておらず、sc1またはst1ボリュームと組み合わせてC5インスタンスを使用することはお勧めしません。 私たちはこの問題を認識しており、この重要な利用ケースのためにドライバを最適化するよう努めています。

Jeff;

(翻訳:SA小川、元の記事はこちらです)

AWS 料金表 API の更新 – 新しいクエリとメタデータ関数

新規 – AWS 料金表 API に記載されている元の AWS 料金表が、構造化された URL を使用して JSON 形式と CSV 形式で料金にアクセスできるようになりました。これはいくつかの種類のコスト管理ツールでうまく機能しましたが、そのファイルのサイズと複雑さのためダウンロードが困難で、解析が面倒でした。今回は API を更新し、新しい関数を追加して必要な料金だけを返すきめ細かな料金クエリを実行できるようにしました。これにより、モバイルおよびブラウザベースのアプリケーションで料金表を利用することができるようになります。

新しい関数
新しい関数は以下のとおりです。

DescribeServices – サービス内の製品を定義するために使用される属性キーのセットを返します。たとえば、EC2 に返されるキーには、physicalProcessormemoryoperatingSystemlocationtenancy があります。

GetAttributeValues – 指定された属性キーのすべての許容値を返します。たとえば、operatingSystem キーの値には、WindowsRHELLinuxSUSE があり、location キーの値には米国東部 (バージニア北部)アジアパシフィック (ムンバイ) があります。

GetProducts – サービス名と属性値に基づくフィルタ式に一致する、すべての製品を公表価格とともに返します。

これらの関数には、AWS SDK からアクセスできます。それらを試してみるために、私は Python と AWS SDK for Python を使用しました。まず、SDK をインポートしてクライアントを作成するところから始めます。

import boto3
import json
import pprint

pricing = boto3.client('pricing')

すべてのサービスと属性を一覧表示する方法は次のとおりです。

print("All Services")
print("============")
response = pricing.describe_services()
for service in response['Services']:
    print(service['ServiceCode'] + ": " + ", ".join(service['AttributeNames']))
print()

出力は次のようになります。

All Services
============
SnowballExtraDays: productFamily, termType, usagetype, locationType, snowballType, feeDescription, servicecode, feeCode, location, operation
OpsWorks: productFamily, servicecode, termType, usagetype, locationType, location, operation, serverLocation, group
mobileanalytics: productFamily, servicecode, includedEvents, termType, usagetype, description, locationType, location, operation
IngestionServiceSnowball: productFamily, fromLocationType, termType, usagetype, locationType, toLocationType, toLocation, snowballType, servicecode, groupDescription, transferType, location, fromLocation, operation, group
IngestionService: productFamily, termType, usagetype, locationType, servicecode, groupDescription, dataAction, location, operation, group
ElasticMapReduce: productFamily, softwareType, instanceType, termType, usagetype, locationType, instanceFamily, servicecode, location, servicename, operation
datapipeline: productFamily, frequencyMode, termType, usagetype, locationType, description, executionFrequency, servicecode, location, operation, group, executionLocation
...

EC2 のすべての料金属性の値をすべて取得する方法は次のとおりです。

print("Selected EC2 Attributes & Values")
print("================================")
response = pricing.describe_services(ServiceCode='AmazonEC2')
attrs = response['Services'][0]['AttributeNames']

for attr in attrs:
    response = pricing.get_attribute_values(ServiceCode='AmazonEC2', AttributeName=attr)

    values = []
    for attr_value in response['AttributeValues']:
        values.append(attr_value['Value'])

    print("  " + attr + ": " + ", ".join(values))

出力は次のようになります。

Selected EC2 Attributes & Values
================================
  volumeType: Throughput Optimized HDD, Provisioned IOPS, Magnetic, General Purpose, Cold HDD
  maxIopsvolume: 500 - based on 1 MiB I/O size, 40 - 200, 250 - based on 1 MiB I/O size, 20000, 10000
  instanceCapacity10xlarge: 1
  locationType: AWS Region
  instanceFamily: Storage optimized, Micro instances, Memory optimized, GPU instance, General purpose, Compute optimized
  operatingSystem: Windows, SUSE, RHEL, NA, Linux
...

そして、ここでは、サービス名と属性値を使用して、64 の vCPU、256 GiB のメモリ、あらかじめインストールされた SQL Server Enterprise を持つ EC2 インスタンスのアジアパシフィック (ムンバイ) リージョンにおける料金表の取得方法を示します。各料金は JSON 文字列です。

print("Selected EC2 Products")
print("=====================")

response = pricing.get_products(
     ServiceCode='AmazonEC2',
     Filters = [
         {'Type' :'TERM_MATCH', 'Field':'operatingSystem', 'Value':'Windows'              },
         {'Type' :'TERM_MATCH', 'Field':'vcpu',            'Value':'64'                   },
         {'Type' :'TERM_MATCH', 'Field':'memory',          'Value':'256 GiB'              },
         {'Type' :'TERM_MATCH', 'Field':'preInstalledSw',  'Value':'SQL Ent'              },
         {'Type' :'TERM_MATCH', 'Field':'location',        'Value':'Asia Pacific (Mumbai)'}
     ],
     MaxResults=100
)

for price in response['PriceList']:
 pp = pprint.PrettyPrinter(indent=1. width=300)
 pp.pprint(json.loads(price))
 print()

出力は次のようになります (その他多数)。

Selected EC2 Products
=====================
{'product': {'attributes': {'clockSpeed': '2.3 GHz',
                            'currentGeneration': 'Yes',
                            'dedicatedEbsThroughput': '10000 Mbps',
                            'ecu': '188',
                            'enhancedNetworkingSupported': 'Yes',
                            'instanceFamily': 'General purpose',
                            'instanceType': 'm4.16xlarge',
                            'licenseModel': 'No License required',
                            'location': 'Asia Pacific (Mumbai)',
                            'locationType': 'AWS Region',
                            'memory': '256 GiB',
                            'networkPerformance': '20 Gigabit',
                            'normalizationSizeFactor': '128',
                            'operatingSystem': 'Windows',
                            'operation': 'RunInstances:0102',
                            'physicalProcessor': 'Intel Xeon E5-2686 v4 (Broadwell)',
                            'preInstalledSw': 'SQL Ent',
                            'processorArchitecture': '64-bit',
                            'processorFeatures': 'Intel AVX, Intel AVX2, Intel Turbo',
                            'servicecode': 'AmazonEC2',
                            'servicename': 'Amazon Elastic Compute Cloud',
                            'storage': 'EBS only',
                            'tenancy': 'Shared',
                            'usagetype': 'APS3-BoxUsage:m4.16xlarge',
                            'vcpu': '64'},
             'productFamily': 'Compute Instance',
             'sku': '24GRA8RB2KZ9NPCS'},
 'publicationDate': '2017-10-07T00:26:55Z',
 'serviceCode': 'AmazonEC2',
...

レスポンスの次の部分には、インスタンスを購入する特定の方法を説明する用語の配列が含まれています (オンデマンド またはさまざまなタイプのリザーブドインスタンス)。

 'terms': {'OnDemand': {'24GRA8RB2KZ9NPCS.JRTCKXETXF': {'effectiveDate': '2017-09-01T00:00:00Z',
                                                        'offerTermCode': 'JRTCKXETXF',
                                                        'priceDimensions': {'24GRA8RB2KZ9NPCS.JRTCKXETXF.6YS6EN2CT7': {'appliesTo': [],
                                                                                                                       'beginRange': '0',
                                                                                                                       'description': '$30.88 per On Demand Windows with SQL Server Enterprise m4.16xlarge Instance Hour',
                                                                                                                       'endRange': 'Inf',
                                                                                                                       'pricePerUnit': {'USD': '30.8800000000'},
                                                                                                                       'rateCode': '24GRA8RB2KZ9NPCS.JRTCKXETXF.6YS6EN2CT7',
                                                                                                                       'unit': 'Hrs'}},
                                                        'sku': '24GRA8RB2KZ9NPCS',
                                                        'termAttributes': {}}},
           'Reserved': {'24GRA8RB2KZ9NPCS.38NPMPTW36': {'effectiveDate': '2017-04-30T23:59:59Z',
                                                        'offerTermCode': '38NPMPTW36',
                                                        'priceDimensions': {'24GRA8RB2KZ9NPCS.38NPMPTW36.2TG2D8R56U': {'appliesTo': [], 'description': 'Upfront Fee', 'pricePerUnit': {'USD': '374227'}, 'rateCode': '24GRA8RB2KZ9NPCS.38NPMPTW36.2TG2D8R56U', 'unit': 'Quantity'},
                                                                            '24GRA8RB2KZ9NPCS.38NPMPTW36.6YS6EN2CT7': {'appliesTo': [],
                                                                                                                       'beginRange': '0',
                                                                                                                       'description': 'Windows with SQL Server Enterprise (Amazon VPC), m4.16xlarge reserved instance applied',
                                                                                                                       'endRange': 'Inf',
                                                                                                                       'pricePerUnit': {'USD': '14.2400000000'},
                                                                                                                       'rateCode': '24GRA8RB2KZ9NPCS.38NPMPTW36.6YS6EN2CT7',
                                                                                                                       'unit': 'Hrs'}},
                                                        'sku': '24GRA8RB2KZ9NPCS',
                                                        'termAttributes': {'LeaseContractLength': '3yr', 'OfferingClass': 'standard', 'PurchaseOption': 'Partial Upfront'}},
...

これらの関数とそれらが返すデータの詳細については、「AWS の料金表 API の使用」を参照してください。

提供開始
新しい関数は今すぐご利用いただけます。現在、米国東部 (バージニア北部) および アジアパシフィック (ムンバイ) リージョンでこれらの関数を使用して、すべてのパブリック AWS リージョンおよび AWS GovCloud (US)のメタデータおよび料金表に無料でアクセスすることができます。

これらの関数を使用する方法の実際の例を見るには、「AWS マネジメントツールのブログ」の新しい投稿「Controlling Projected User Costs Through Monthly Budget Policies」を参照してください。

Jeff;