[AWS/EFS]CloudWatch+SNS+Lambdaで動的にスループットモードを変更させる
こんにちは。Opt Fit CROの森田です。
タイトルのものを構築した際にハマったポイントを共有してみたいと思います。
内容としては簡単なのですが、結構引っ掛かる人居ませんかね、僕だけかな…笑
背景
弊社サービスにおいてEFSを小容量で運用しているのですが、バーストクレジットという罠が存在し、それが枯渇するとI/Oが激重になって使い物にならなくなる(ファイル存在チェックだけで0.5秒とか)という事件に遭遇しました。
そこで、バーストクレジットが枯渇する前にEFSのスループットモードをプロビジョニングモードに変更して回復させてあげるLambdaを自動実行する仕組みを構築します。
プロビジョニングモードは非常に高価(スループット1MBの保証で月7.2USDの追加課金)なので、基本はバーストモードを使用し、バーストクレジットが減ったら回復させるのがコスト的にベストです。
基本的に、下記の記事を参考にしています。大変助かりましたm(_ _)m
設計
下図が処理の流れです。
EFSのメトリクスは下記の2条件でアラーム設定します。
- バーストクレジットが○○以下になったとき
- バーストクレジットが××以上になったとき
実装詳細
Lambdaの作成
バーストクレジットが多いとき・少ないときの2箇所でアラーム設定をするので、Lambdaもその2箇所分設定します。
バーストモード→プロビジョニングモードの関数は下記のような感じで作りました。
その逆は、paramsの"ThroughputMode"を"provisioned"にし、追加で"ProvisionedThroughputInMibps": "10 (任意のスループット値)"を足す感じです。
CloudWatchから送られてくるメッセージには、何故かEFS IDが付いていませんので、自前で"FileSystemId": message.AlarmDescription (CloudWatchアラームの説明)として用意する感じです。普通標準で付いてると思いますよね。
Slack通知に関してはあってもなくてもどちらでもいいです。
console.log('Loading function');
var https = require('https');
var http = require('http');
const aws = require('aws-sdk');
var efs = new aws.EFS();
const url = require("url");
const slackUrl = "Slack WebhookのURL";
exports.handler = (event, context) => {
(event.Records || []).forEach(function (rec) {
if (rec.Sns) {
var message = JSON.parse(rec.Sns.Message);
var params = {
"FileSystemId": message.AlarmDescription,
"ThroughputMode": "bursting"
};
// EFSスループットモードの変更処理
efs.updateFileSystem(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
// Slack通知処理
var slackReqOptions = url.parse(slackUrl);
slackReqOptions.method = "POST";
var payload = {
text: "--- *EFS provisioned to burst lambda function called with following parameters.* ---",
attachments: [
{
title: "event",
color: "#e47911",
text: "```\n" + JSON.stringify(event, null, " ") + "```\n",
mrkdwn_in: ["text"],
},
],
};
var body = JSON.stringify(payload);
slackReqOptions.headers = {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body),
};
var req = https.request(slackReqOptions, function (res) {
if (res.statusCode === 200) {
console.log("Posted to slack");
} else {
console.log("Failed");
}
return res.statusCode;
});
req.write(body);
req.end();
}
});
};
{
"Records": [
{
"Sns": {
"Message": "{\"AlarmDescription\":\"EFSのID\"}"
}
}
]
}
SNSの設定
CloudWatchからLambdaを呼び出すためにSNSを利用します。
バーストクレジットが多いとき・少ないときの2箇所でアラーム設定をするので、SNSもその2箇所分設定します。
トピックを作成してから、サブスクリプションで前項のLambdaを指定します。
ここでSNSの単体テストですが、メッセージの発行では、
{"AlarmDescription": "EFSのID"}
を本文として設定する感じです。
EFSメトリクスのアラーム設定
CloudWatchの「アラームの作成」で、EFS IDを入力して検索し、「EFS > ファイルシステムメトリクス」の「BurstCreditBalance」を選択します。
バーストモード→プロビジョニングモードのアラーム条件は、バーストクレジットの減少率にもよりますが、安全を見て大体100GB以下くらいでしょうか。
プロビジョニングモード→バーストモードのアラーム条件はいくつでもいいのですが、バーストクレジットが初期で2.31TB (2308974418330 byte)与えられるので、小さい値だとずっとアラーム状態になって気持ち悪いです。そのため全快値である2308974418330を設定すればいいんじゃないでしょうか。
次に「アラームの通知」では、前項のSNSトピックを選択します。
最後に「アラームの説明」でEFS IDを記述しておきます。
まとめ
EFSのバーストクレジットという罠、SNSとLambdaのテスト設定の罠をご紹介しました。
これからもいろいろな罠と戦っていきたいと思います。
参考
- Amazon Elastic File System (Amazon EFS) におけるバーストとプロビジョニングの変更を自動化する
🔔採用情報
ジム施設向けDXソリューションGYMDXではエンジニアを積極採用中です。
ジュニア層のエンジニアからリーダー職まで幅広く募集しています。
2022年7月にプレシリーズAラウンドにて資金調達を実施しました。
リードエンジニア
バックエンドエンジニア
Discussion