はじめに
レアジョブのプラットフォームチームでチームリーダーをさせていただいている塚田です。 Microservicesで共通基盤を作るチームですが、チームの特性上コンテナやLambdaを触ることが多いチームです。 今回はLambdaについての記事です。
課題
サービス提供会社として、自身が提供しているサービスが問題なく動いているか監視する必要があります。 監視という観点でいうと、サーバのリソースを描写し、閾値を超えた場合通知するよう作るのも必要ですが、 実際ユーザーはどのくらいの体感速度だったのかという観点は非常に重要です。
ユーザーの体感を定量的に可視化するため、我々は昔からオンプレのZabbixを用いて外形監視の一つとしてユーザー視点でレスポンスタイムを観測してきました。 しかし、そろそろオンプレの運用も脱出したい。願わくばサーバ(IaaS)を使わず運用したい。
そんな中、Lambdaでカスタムランタイムをサポートしたというニュースが2018年に流れたので、 シェルを動かせばソッコー実装できるのではと思い試してみることにしました。
やってみた
まず、LambdaのLayersを作成します。 ここでLayersを作る目的は、大きく2つありました。
- シェルを実行できるようにする
- awscliを使えるようにする
という理由です。Layer化しておけば外部ライブラリを簡単にインポートできるようになります。
ソースコードは公式が公開 チュートリアル – カスタムランタイムの公開 - AWS Lambda しているものを少し調整しています。 以下のような感じです
#!/bin/sh set -euo pipefail # tmpフォルダ内にawscliを配置するためHOMEとPATHを設定 export HOME="/tmp" export PATH="$HOME/.local/bin:$PATH" # install pip cd /tmp curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py python get-pip.py --user # install awscli using pip pip install awscli --user # ハンドラ関数の読み込み # Initialization - load function handler source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh" # Processing while true do HEADERS="$(mktemp)" # Get an event EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next") REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2) # ハンドラ関数を実行 # Execute the handler function from the script RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA") # 結果を返却 # Send the response curl -kL -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$RESPONSE" -o /dev/null 2> /dev/null done
その後、zip化。zip awscli.zip bootstrap
runtimes は python3.7 を指定します。
コマンドでLambdaへuploadする際は、以下のようなコマンドで実施できます。
aws lambda publish-layer-version \ --layer-name awscli \ --zip-file fileb://awscli.zip \ --compatible-runtimes python3.7
もし、コンソール画面から行う場合はここから登録します。
ここまでは準備段階です。
その後、Lambda関数用にシェルを作成します。
function handler () { res=$(curl -kL 'https://www.rarejob.com/dna' -o /dev/null -w "%{time_total}" 2> /dev/null) aws cloudwatch put-metric-data --metric-name responseTime --namespace responseTime --value $res --dimensions Name=Time,Value=second }
運用時はURLをここにベタに書かず、DynamoDBから参照させたりした方が良いと思いますが、今回は便宜上ベタ書きにします。
今回の監視対象はDaily News Article。レアジョブで最も人気のある、日替わりのニュース教材です。 www.rarejob.com
その後、 function.shをzip化。zip function.zip function.sh
Lambda関数を登録します。
ランタイムはカスタムランタイム、 ハンドラーはfunction.handlerをしてください。
Lambdaの実行IAMに
- AWSLambdaBasicExecutionRole
- CloudWatchの書き込み権限
を与えてください。
レイヤーには準備としてuploadしたLayersのawscliを指定します。
トリガーには、CloudWatch Eventsで、スケジュール式: rate(3 minutes) を設定。 今回は3分単位で監視するようにします。
あとは、CloudWatchのダッシュボードをよしなに設定すれば、描写を確認することができます。
既存の監視(オンプレのzabbix)と比較してみる
異常値を無視すると、 オンプレのzabbixは0.1 秒程度のレスポンスタイムを確認 一方で今回のLambdaで実施したレスポンスタイムは0.3秒程度でした。
考察
レスポンスタイムが、オンプレのzabbixとLambdaで一致しているわけではないというのが注意です。
- 単純に処理のタイミング。
- zabbixに組み込まれているレスポンスタイム処理と、今回curlコマンドでのレスポンスタイム処理自体の違い。
- zabbixはオンプレで動いているが、Lambdaは毎回起動される度に同一サーバではない可能性があるという点。
などなど、考えられるので原因は複合的かもしれません。 現在は検証段階なので、外形監視の本格移行などは予定はしておりません。
今回の検証は、いちエンジニアの「やりたいこと」に過ぎなかったのですが、レアジョブでは「やりたいこと」が推奨されている会社です。 その中では、サービスの一部としてとして形になっているもの、検証だけで終わってしまったもの様々です。
しかしどんどんチャレンジして、世の中にアウトプットを出して行こうと思っています。