S-JIS[2013-05-30] 変更履歴

Amazon CloudWatch S3の例

AWS CloudWatchS3の容量を監視する為のプログラムの例。


概要

Amazon S3の容量監視(S3で使っている容量(バケット毎のファイルサイズの合計)の監視)を考える。

CloudWatchではカスタムメトリクスを使う(自分独自のメトリクスを保持する)ことが出来るので、
S3の容量を算出してメトリクスに登録すれば、CloudWatchで監視することが出来そう。


で、実際、メトリクスを登録することも、そのメトリクスに対してアラームを定義することも出来るのだが、問題が一点ある。
アラームに定義できるのは一定期間内の最大値・最小値・平均値等であり、「最新の値」は取れない。

S3の監視を頻繁に行わない場合、つまり1日に1回だけ容量をチェックすればいいというような場合は最新の値でチェックしたいと思うんだよね。
一時的に大量に使っても、最終的に削除されていればいいでしょう、という考え。
だから、1日の間の最大値とか最小値とか平均値ではあまり意味がない。

つまり、S3の容量をメトリクスに保持するのは履歴管理にもなるので良いと思うが、CloudWatchのアラームを定義するのは微妙。
1日1回の監視でいいなら、S3の容量算出を1日1回行い、その時点で自分で閾値チェックを行って警告メールを出すとかにした方が良さそう。


S3の使用量を登録する例

S3のバケット毎の使用量をメトリクスに登録する例。

import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.MetricDatum;
import com.amazonaws.services.cloudwatch.model.PutMetricAlarmRequest;
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
import com.amazonaws.services.cloudwatch.model.StandardUnit;
		PutMetricDataRequest request = new PutMetricDataRequest();
		request.setNamespace("EXAMPLE/S3");

		List<MetricDatum> list = getS3SizeList(credentials);
		request.setMetricData(list);

		client.putMetricData(request);
	private List<MetricDatum> getS3SizeList(AWSCredentials credentials) {
		Map<String, Long> map = getS3Size(credentials);
		Date timestamp = new Date();

		List<MetricDatum> list = new ArrayList<MetricDatum>(map.size());
		for (Entry<String, Long> entry : map.entrySet()) {
			String bucketName = entry.getKey();
			long size = entry.getValue();
		
			MetricDatum data = new MetricDatum();
			data.setMetricName("bucketSize");
			Dimension dim = new Dimension().withName("bucketName").withValue(bucketName);
			data.setDimensions(Arrays.asList(dim));
			data.setUnit(StandardUnit.Bytes);
			data.setValue((double) size);
			data.setTimestamp(timestamp);

			list.add(data);
		}
		return list;
	}

namespaceに「EXAMPLE/S3」、メトリクス名に「bucketSize」、dimensionに「bucketName」を指定してvalueにS3の使用量を設定している。


import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
	private Map<String, Long> getS3Size(AWSCredentials credentials) {
		Map<String, Long> map = new TreeMap<String, Long>();

		AmazonS3Client s3client = new AmazonS3Client(credentials);

		List<Bucket> buckets = s3client.listBuckets();
		for (Bucket b : buckets) {
			String bucketName = b.getName();
			long size = 0;

			ListObjectsRequest request = new ListObjectsRequest();
			request.setBucketName(bucketName);

			ObjectListing list;
			do {
				list = s3client.listObjects(request);
				for (S3ObjectSummary s : list.getObjectSummaries()) {
					size += s.getSize();
				}
				request.setMarker(list.getNextMarker());
			} while (list.isTruncated());

			map.put(bucketName, size);
		}

		return map;
	}

S3のバケット毎の使用量を直接取得する方法は無いようなので、
バケット一覧を取得し(credentialsで指定したユーザーのバケットのみ取れる)、
バケット毎にファイル一覧(List<S3ObjectSummary>)を取得してファイルサイズを合算している。


アラームを作成する例

バケットの使用量(カスタムメトリクス)を監視するアラームを作成する例。(CLImon-put-metric-alarmに相当)

import com.amazonaws.services.cloudwatch.model.ComparisonOperator;
import com.amazonaws.services.cloudwatch.model.PutMetricAlarmRequest;
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
import com.amazonaws.services.cloudwatch.model.Statistic;
		PutMetricAlarmRequest request = new PutMetricAlarmRequest();
		request.setAlarmName("アラーム名");
		request.setNamespace("EXAMPLE/S3");
		request.setMetricName("bucketSize");
		Dimension dim = new Dimension().withName("bucketName").withValue("バケット名");
		request.setDimensions(Arrays.asList(dim));

		// 監視間隔
		request.setPeriod((int)TimeUnit.MINUTES.toSeconds(5));
		request.setEvaluationPeriods(1);	//→evaluation-periods

		// 閾値の設定「最小値 >= 1GB」
		request.setStatistic(Statistic.Minimum);
		request.setThreshold(1.0 * 1024 * 1024 * 1024);
		request.setComparisonOperator(ComparisonOperator.GreaterThanOrEqualToThreshold);

		// アクション
		String action = "arn:aws:sns:ap-northeast-1:123456789abc:test-alarm";
		request.setAlarmActions(Arrays.asList(action));	// 閾値を超えた際のアクション
//		request.setOKActions(Arrays.asList(action));   	// 閾値より下がった際のアクション

		client.putMetricAlarm(request);

アラームの監視に引っかかったとき(閾値を超えた場合や正常に戻った場合)のアクションを指定することが出来る。
例えばメールを送る場合、メールの送信先情報はSNS(Amazon Simple Notification Service)に登録しておき、PutMetricAlarmRequestにはそれを示すARNを設定する。


CloudWatchへ戻る / AWSへ戻る / 技術メモへ戻る
メールの送信先:ひしだま