🌳

[EC2×S3]サーバダウン→再起動後に再処理できるようにする

2022/05/14に公開

Amazon EC2はシングル AZで99.95%, マルチ AZで99.99%の稼働率ですが、予期せぬサーバダウンには備えておきたいもの(前者で21.9分/月, 後者で4.38分/月 停止することに相当)

本記事は、S3経由で受け取ったリクエストデータをEC2インスタンス上で稼働するプログラムで処理する場合の超シンプルな対策方法(という名の覚書き)です

前提条件

  • 処理対象のリクエストデータは、S3経由で受け取る
  • ソースコードはCodeDeployを用いてEC2インスタンスにデプロイするものとする

(1) S3におけるリクエストデータのネーミング

処理待ちをwait, 処理中をprocessing, 完了したものをfinishのプレフィックスをつけて管理するものとします(コマンドで、処理ステータスに応じてプレフィックスを変更する)

s3://[バケット名]/
	|
	|--- wait/ ・・処理待ち
	|
	|--- processing/ ・・処理中
	|
	|--- finish/ ・・処理完了

処理終了後、特にリクエストファイル保管の必要性がなければfinishとせず、削除してしまってもよいかも。

(2) ソースプログラム群の構成

ソースプログラム群の構成です。
再起動時に実行するシェルプログラムをscripts配下に置いています。

    hogehoge
	|
	|--- プログラム1
	|--- プログラム2
	|--- :
	|--- :
	|--- scripts
		|--- resetProcessing.sh

(3) 再起動時に実行するシェルプログラム

再起動時に実行するシェルプログラム(上記のscripts/resetProcessing.sh)は以下の通り
プレフィックスが処理中のprocessingになっていたものを、処理待ちのwaitに戻します
(→ 今回のキモはここ)

scripts/resetProcessing.sh
#!/bin/bash

# システムダウン時に進行中だったデータを処理待ちに戻す

# 動作環境(検証 or 本番)により接続先S3を変更(本番環境のEC2インスタンスは「-prod-」という文字列が入るものとする)
hostname=`hostname`
if [[ "$hostname" == *-prod-* ]]; then
    # 本番環境用の設定(Systems Managerよりキーを取得)
    ACCESS_KEY=`aws ssm get-parameter --name [本番環境S3のアクセスキー用パラメータ名] --with-decryption --query 'Parameter.Value'| /usr/bin/sed 's/"//g'`
    SECRET_ACCESS_KEY=`aws ssm get-parameter --name [本番環境S3のシークレットアクセスキー用パラメータ名] --with-decryption --query 'Parameter.Value'| /usr/bin/sed 's/"//g'`
    BUCKET=s3://[本番環境のバケット名]
else
    # 検証環境用の設定(Systems Managerよりキーを取得)
    ACCESS_KEY=`aws ssm get-parameter --name [検証環境S3のアクセスキー用パラメータ名] --with-decryption --query 'Parameter.Value'| /usr/bin/sed 's/"//g'`
    SECRET_ACCESS_KEY=`aws ssm get-parameter --name [検証環境S3のシークレットアクセスキー用パラメータ名] --with-decryption --query 'Parameter.Value'| /usr/bin/sed 's/"//g'`
    BUCKET=s3://[検証環境のバケット名]
fi

# 環境変数に設定
export AWS_ACCESS_KEY_ID=$ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY

# 処理中 → 処理待ちに変更(リクエストファイルは末尾が「*request.json」 とする)
aws s3 mv $BUCKET/processing/ $BUCKET/wait/ --exclude "*" --include "*request.json" --recursive

上記、本番環境と検証環境どちらでも処理できるようにした&Systems Managerより値をとる想定で書いてます
セキュリティ面を考えると、あまりよろしくないですが、直接キー値を環境変数に設定するなら、上記でSystems Managerで値をとってくる箇所で、環境変数設定を実施すればよいでしょう。

キー値を直接指定する場合
#!/bin/bash

# システムダウン時に進行中だったデータを処理待ちに戻す

# 動作環境(検証 or 本番)により接続先S3を変更(本番環境のEC2インスタンスは「-prod-」という文字列が入るものとする)
hostname=`hostname`
if [[ "$hostname" == *-prod-* ]]; then
    # 本番環境用の設定(Systems Managerよりキーを取得)
    export AWS_ACCESS_KEY_ID=[本番環境S3のアクセスキーの値]
    export AWS_SECRET_ACCESS_KEY=[本番環境S3のシークレットアクセスキーの値]
    BUCKET=s3://[本番環境のバケット名]
else
    # 検証環境用の設定(Systems Managerよりキーを取得)
    export AWS_ACCESS_KEY_ID=[検証環境S3のアクセスキーの値]
    export AWS_SECRET_ACCESS_KEY=[検証環境S3のシークレットアクセスキーの値]
    BUCKET=s3://[検証環境のバケット名]
fi

# 処理中 → 処理待ちに変更(リクエストファイルは末尾が「*request.json」 とする)
aws s3 mv $BUCKET/processing/ $BUCKET/wait/ --exclude "*" --include "*request.json" --recursive

(4) appspec.yml

appspec.ymlです。
デプロイ時に実行する内容を書いてます。
hooks以降の記述で、起動時に上のシェルプログラムを実行することができます。

appspec.yml
version: 0.0
os: linux
files:
  - source: /
    destination: /hogehoge
permissions:
  - object: /hogehoge
    pattern: "**"
    owner: fuga
    group: fuga
hooks:
  ApplicationStart:
    - location: scripts/resetProcessing.sh

終わりに

SLA 99.95%, 99.99%って思ったよりサーバ停止する可能性高そうですね。。
リカバリできるよう何等かの対策を講じたいところ

他のモジュールを使ったパターンや、他にいい方法があればぜひ教えてください!

参考

Discussion