Scalable PDFでは、EC2インスタンスの起動/終了やCloudWatchを使ったリソースのモニターなどを、Google App Engineからできるようになっている。わざわざGAEを使っているのは、利用料削減とレイテンシーの改善のためである。EC2インスタンスをずっと起動しているとチャージされてもったいないので、必要なときに必要な分だけのインスタンスを起動する、というオンデマンド的な利用がおすすめだ。インスタンス起動は数十秒で可能であり、また、Reflex iTextが揮発性で疎結合であるため、このような経済的なシステム利用(グリーンIT?)が可能になっている。レイテンシーについては、前記事にも書いたとおり、GAEを介す方が50%も改善できるという結果もある。
さて今回は、このScalable PDFでも採用しているテクニックをいくつかご紹介したいと思う。まずはCloudWatchから。
GAEでCloudWatch
【Amazon CloudWatchとは】
・Amazon EC2のインスタンス(仮想サーバ)の状態を監視するサービス。
・インスタンスのCPU使用率やネットワークI/O、ディスクI/Oをチェックすることができる。
・$0.015 per Amazon EC2 instance hour
・インスタンスを落としても2週間は参照可能。
・AWS Management Consoleからは2009-07-02現在使用できないため、利用開始時にはEC2コマンドラインツールの「ec2-monitor-instances」を実行する必要がある。
・モニターしたインスタンスの情報はCloudWatchコマンドラインツールの「mon-get-stats」で参照できる。
【リンク】
Amazon CloudWatch on GAE/J (beta)デモ
ソース
【このツールの内容】
・CloudWatchの監視対象としたインスタンスの情報をGAE/J上から閲覧する。
・公開版は過去に使用したインスタンスの情報のみ参照できるようにしている
・Firefox3.0とIE6では動作確認済み。
【このツールの仕組み】
基本的に、CloudWatchAPIの実行結果XMLをReflexを使って一旦パースし、それをJSONに変換してブラウザに渡して、JavaScriptを使って表示している。
1.GAE/J→CloudWatch
CloudWatchAPIのListMetricsを叩いて、参照可能な監視情報一覧を取得(json)。
2.GAE/J
参照する情報を指定。
3.GAE/J→CloudWatch
CloudWatchAPIのGetMetricStatisticsを叩いてインスタンスの情報を取得(json)。
4.GAE/J
取得した情報を表示。
【項目の説明】
MeasureName
参照する監視内容。
CPU使用率、ネットワークI/O、ディスクI/O。
DimensionName
監視対象の分類。
インスタンスIDごと、イメージIDごと、インスタンス種別ごと。
DimensionValue
監視対象の詳細。
インスタンスID、イメージID、インスタンス種別。
From
参照開始日時。
To
参照終了日時。
Period
抽出する間隔(秒)。
60なら1分ごとのデータ。
3600なら60分ごとのデータ。
【使用例】
1.Amazon CloudWatch on GAE/J (beta) > Menu > CloudWatch > Control
2.-MeasureNameでCPUUtilizationを選択。
3.-DimensionNameでInstanceIdを選択。
4.-DimensionValueでi-b3ac89daを選択。
5.Fromを2009-06-22T00:00にセット。
6.Toを2009-06-24T00:00にセット。
7.Periodを3600にセット。
8.GetStatisticsMetricsボタンをクリック。
9.結果テーブルのタイトル行をクリックするとソート可能(TinyTable JavaScript Table Sorterを利用)
※参照可能なデータが無い場合や表示データ上限数を超えている場合などは「Error!」と表示される。
【リンク】
Amazon CloudWatch
AWS Management Console(EC2)
TinyTable JavaScript Table Sorter - 2.5KB
GAEでEC2インスタンスを管理する
次に、EC2インスタンスの起動や終了をGAEに通知する方法について説明したいと思う。まずは、EC2インスタンス作成から。
【EC2インスタンスを作成】
【初期操作】
AWS Management Console等からAWSのデフォルトAMIを指定して新規インスタンスを作成。
↓
インスタンスに接続してカスタマイズ。
↓
AMIをS3に登録・保存
S3に保存することで次回からも同じ設定のインスタンスを使用できる。
【Amazon EC2のAMIをS3に登録する】
インスタンスへsshして保存用イメージファイル(AMI)を作成→S3へアップロード→AMI登録
* 保存イメージファイル(AMI)作成
/mntディレクトリに移動して「ec2-bundle-vol」を実行。
#cd /mnt/
#ec2-bundle-vol -d /mnt --privatekey /path/to/pk-XXXX.pem --cert /path/to/cert-xxxx.pem --user YOUR-ACCOUNT-NUMBER --fstab /etc/fstab
** pk-XXXX.pem: Secret Access Key File
** cert-xxxx.pem: X.509 Certificate File
** YOUR-ACCOUNT-NUMBER: Account Number
* S3へアップロード
「ec2-upload-bundle」コマンドをバケット名を指定して実行。
#ec2-upload-bundle --bucket /path/to/BUCKET_DIRECTORY_NAME --manifest image.manifest.xml --access-key XXXX --secret-key xxxx
** BUCKET_DIRECTORY_NAME: S3側のBucket Directory
** XXXX: Access Key ID
** xxxx: Secret Access Key
* AMI登録
インスタンスからログアウトして、「ec2-register」を実行。
C:\>ec2-register /path/to/BUCKET_DIRECTORY_NAME/image.manifest.xml
【起動時にGAEに伝える仕組み】
EC2インスタンスの起動終了時に、GAEのWebサービスプロバイダに対してステータスを通知することで、GAE上で利用可能なEC2インスタンスを管理することができるようになる。
【仕組み】
インスタンス起動時のnetworkが立ち上がる箇所で、自身のエンドポイント(ホスト名、インスタンスID)をec2nodeに登録するスクリプト(post_endpoint_to_gae.sh)を実行。
インスタンス終了時にec2nodeから登録を削除するスクリプト(delete_endpoint_from_gae.sh)を実行。削除キーはインスタンスID。
【/etc/rc.d/ini.d/networkの変更】
インスタンス起動・終了時にエンドポイントの登録・削除を行うための設定。
startコマンド最終行に以下を追加。(エンドポイント登録用)
/bin/sleep 5
/path/to/post_endpoint_to_gae.sh
stopコマンド先頭行に以下を追加(エンドポイント削除用)
/path/to/delete_endpoint_from_gae.sh
/bin/sleep 20
※sleepをかけないとdelete_endpoint_from_gae.shの実行前にネットワークが切断されてしまい削除できない。
【エンドポイント登録・削除用スクリプト】
登録(post_endpoint_to_gae.sh)
エンドポイント情報を取得し、ec2nodeへPOSTする。
「http://169.254.169.254/latest/」はAWS側で用意されているインスタンスID等の問い合わせ先。
#!/usr/bin/php
<?php
$publicHostname = trim(file_get_contents("http://169.254.169.254/latest/meta-data/public-hostname"));
$instanceId = trim(file_get_contents("http://169.254.169.254/latest/meta-data/instance-id"));
$status = "IDLE";
$data = array(
"ec2record" =<
array(
"ec2node" => "{$instanceId}",
"endpoint_url" => "{$publicHostname}",
"status" => "{$status}"
)
);
$json = json_encode($data);
$url = "http://www.example.com/ec2node";
$options = array(
"http" => array(
"method" => "POST",
"header" => "Content-type: text/plain",
"content" => $json
)
);
$context = stream_context_create($options);
$fp = fopen($url, "r", false, $context);
fpassthru($fp);
fclose($fp);
exit("\n");
?>
削除(delete_endpoint_from_gae.sh)
インスタンスID(削除キー)を取得し、ec2nodeへDELETEする。
#!/usr/bin/php
<?php
$instanceId = trim(file_get_contents("http://169.254.169.254/latest/meta-data/instance-id"));
$url = "http://www.example.com/ec2node?ec2node={$instanceId}";
$options = array(
"http" => array(
"method" => "DELETE",
"header" => "Content-type: text/plain"
)
);
$context = stream_context_create($options);
$fp = fopen($url, "r", false, $context);
fpassthru($fp);
fclose($fp);
exit("\n");
?>
0 件のコメント:
コメントを投稿