SimpleDBにもCloudWatchのメトリックスが欲しい

こんにちは。
アドベントカレンダー初挑戦のはっぱのこです。
AwsAdventCalender14日目を担当します。

先日の得上さんの記事の内容が濃くて、その翌日ということで、この内容でいいのか
(((((((( ;゚Д゚))))))))ガクガクブルブル しております。
さすが、jawsug代表!

さて、気を取り直して、本題です。

AWS初心者の私が好きなサービスはSimpleDBとCloudWatchです。
CPU使用率やディスク容量など様々な値を保持してくれている縁の下の力持ちなCloudWatchですが、残念なことにSimpleDBのメトリックスがございません。

SimpleDBには以下のような制限があります。


なので、これを今回は、ドメインサイズなどの値を取得し、カスタムメトリックスに入れて、アラートを設定をするということをやりたいと思います。

得上さんが日頃から、jawsugに関連するツイートを集めてSimpleDBに保存しているということなので、
値の取得対象にそのドメインを使用させていただきました。

■ SimpleDBからメタデータを取得して、CloudWatchに入れるプログラム

SDBからドメインサイズとアトリビュート数を取得するメソッド

	protected HashMap<String, String> getMetaData(String domainName) {

                // GetMetaData
		DomainMetadataRequest domainMetadataRequest = new DomainMetadataRequest();
		domainMetadataRequest.setDomainName(domainName);
		DomainMetadataResult result = this.sdb.domainMetadata(domainMetadataRequest);
		
		// GetBoxUsage
		AmazonSimpleDBClient client = (AmazonSimpleDBClient) this.sdb;
		float boxUsageFloat = client.getCachedResponseMetadata(domainMetadataRequest).getBoxUsage();
		String boxUsageString = new java.text.DecimalFormat("####0.0###############################").format(boxUsageFloat);
	
		System.out.println("=======================================");
		System.out.println("DomainName = " + domainName);
		System.out.println("ItemCount = " + result.getItemCount());
		System.out.println("DomainSize = " + result.getAttributeValuesSizeBytes() + " byte");
		System.out.println("BoxUsate = " + boxUsageString);

		HashMap<String, String> resultMap = new HashMap<String, String>();
		resultMap.put("domainName", domainName);
		resultMap.put("itemCount", result.getItemCount().toString());
		resultMap.put("domainSize", result.getAttributeValuesSizeBytes().toString());
		resultMap.put("boxUsage", boxUsageString);

		return resultMap;
	}

SimpleDBでは、5秒以内に処理できたクエリの結果しか返さないという仕様なので、ドメイン内のデータ数が多い場合は
「select count(*) from ドメイン名」をやっても、正確なアイテム数を取得することができません。

そのため、DomainMetaDataから取得する必要があります。

また、SimpleDBのお値段の指標となるBoxUsageの値も取得しています。


カスタムメトリックスに値を入れるメソッド

	protected void putCustomMetrics(HashMap<String, String> data)  {

		Dimension dimension = new Dimension().withName("DomainName").withValue(
				data.get("domainName"));

		// Put [ItemCount]
		PutMetricDataRequest request = new PutMetricDataRequest()
				.withNamespace("SimpleDB").withMetricData(
					new MetricDatum()
								.withDimensions(dimension)
								.withMetricName("ItemCounts")
								.withUnit(StandardUnit.Count)
								.withValue((Double) Double.parseDouble(data.get("itemCount"))));

		cw.putMetricData(request);
		
		// Put [domainSize]
		request = new PutMetricDataRequest()
		.withNamespace("SimpleDB").withMetricData(
				new MetricDatum()
						.withDimensions(dimension)
						.withMetricName("DomainSizes")
						.withUnit(StandardUnit.Count)
						.withValue((Double) Double.parseDouble(data.get("domainSize"))));

         cw.putMetricData(request);
         
         // Put [BoxUsage]
 		request = new PutMetricDataRequest()
 		.withNamespace("SimpleDB").withMetricData(
 				new MetricDatum()
 						.withDimensions(dimension)
 						.withMetricName("BoxUsages")
 						.withUnit(StandardUnit.Count)
 						.withValue((Double) Double.parseDouble(data.get("boxUsage"))));

          cw.putMetricData(request);
	}

メイン処理

public class AdventCalendar2012 {
        private final String AccessKey = "MyAccessKey";
        private final String SecretKey = "MySecretKey";

        protected AmazonSimpleDB sdb = new AmazonSimpleDBClient();
        protected AmazonCloudWatchClient cw = new AmazonCloudWatchClient();

        public AdventCalendar2012(){
            this.sdb = new AmazonSimpleDBClient(new BasicAWSCredentials(AccessKey,SecretKey));
            this.sdb.setEndpoint("sdb.ap-northeast-1.amazonaws.com");
            
            this.cw = new AmazonCloudWatchClient(new BasicAWSCredentials(AccessKey, SecretKey));
            this.cw.setEndpoint("monitoring.ap-northeast-1.amazonaws.com");
        } 

	public static void main(String[] args) {
                Main m = new Main();

		String[] domainNames = {"jawsug"};
		
		for (String domainName : domainNames) {
                        // メタデータを取得する
			HashMap<String, String> data = m.getMetaData(domainName);
                        // CloudWatchに値を入れる
			m.putCustomMetrics(data);
		}
	}
}

上記のプログラムをEC2に配置して、cronで1分おきに実行するように設定しました。

■ 入れた結果を確認

しばらく動かした後、マネージメントコンソールで値が入っているかを確認してみます。


入っていますね。

■ アラートの設定と確認

さて、CloudWatchのいいところ。アラート機能の設定。

マネージメントコンソールのCloudWatchのメトリクスを確認した画面でCreateAramのボタンをポチとして
条件を入力してポチっとすれば、アラートの設定がいとも簡単にできます。メールで通知する設定も簡単です。

今回は、ドメインサイズが47369000byteを超えたら、アラートを出してメール飛ばすように設定しました。

ドメインにはデータがどんどん入っていくのでしばらく待つと、メールが来ました。
メールに書いてあるリンクをクリックすると、マネージメントコンソールで確認ができます。


今回は、アラートに使う数値を適当にしましたが、今後は
ドメインサイズの10Gの容量に近づいてきたらアラート出してメールを飛ばす設定をしておけば安心ですね!

また、SimpleDBにリクエストを送るたびにBoxUsageの値を取得してカスタムメトリックスにいれていき
別途、CloudWatchから値を取得して集計するプログラムを書いたりしたら、時間ごとや日ごとにどのくらい使用したか分かったりもしますね。


さて、今回、カスタムメトリックスに定期的に値を入れるためにバッチ実行用にEC2 microインスタンスを立ちあげたのですが
料金的なところを考えると、、、、


  • SimpleDBの魅力はお値段がお安いところでは?
  • RDSのmicroつかったら、EC2と同じくらいの金額でできるんじゃない?
  • RDSだったら、メトリックスもいろいろあるよ?
  • DynamoDBのほうが容量制限とかないし、メトリックスもあるよ?
  • カスタムメトリックスも料金かかるよね?



っていう疑問がいろいろ浮かんできますが、まだまだSimpleDB愛好家として、たくさん使っていきたいのでサンタクラウドにお願い。


AWSの2012 Xmas企画「サンタに願いを」

awsに欲しい機能などお願いごとがあったら、皆様もどんどん #jawsug #サンタクラウドハッシュタグをつけてつぶやいたり、
他の方のお願いを公式RTするといいことあるかもしれません。