ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

Step Functionsを使ったLambdaのDR構成 HTTPレスポンスで東京/大阪に自動切替

この記事を共有する

目次

皆さんこんにちは、サービスGの山内です。
現在の業務では DR構成を検討しており、今回はAWS Step Functionsを使った構成を紹介します。

概要と構成図

東京リージョンでAmazon EventBridgeにて定期的に実行されるAWS Lambdaの処理を、東京リージョンに障害が発生した場合に、
大阪リージョンへ自動的に切り替えるDR構成です。

構成のポイント

  • 東京・大阪の両リージョンに AWS Step Functions を配置し、同じスケジュールで起動します。
  • バージニアリージョンに配置した Amazon API Gateway + AWS Lambda が、Amazon CloudWatch Alarm の状態を確認し、どちらのリージョンで処理を実行すべきかを返します。
  • 各リージョンの AWS Step Functions は、このレスポンスに基づいて自リージョンの AWS Lambda を実行するか、何もせず終了するかを判断します。

なぜバージニアリージョンに Amazon API Gateway を置くのか

東京・大阪のどちらに障害が起きても影響を受けない第三のリージョンに判定ロジックを配置することで、判定自体の可用性を確保しています。

処理の流れ

  1. AWS Step Functions を起動する Amazon EventBridgeが起動
  2. バージニアリージョンのAmazon API Gatewayを呼び出すStepが起動
  3. Amazon API Gateway から起動された AWS Lambda が Amazon CloudWatch Alarmの状態を確認
  4. 正常時はTokyo、アラート時はOsakaをAWS Lambdaが返却
  5. レスポンスがTokyoの場合は東京リージョンのAWS Lambdaが起動、レスポンスがOsakaの場合は大阪リージョンのAWS Lambdaが起動

構成図は以下の通りです。

01.png

各リソースについて

Amazon CloudWatch Alarmを確認するAWS Lambda

AWS Lambdaのコードはシンプルです。
対象のAmazon CloudWatch Alarmを確認し、アラーム状態によってレスポンスを分けています。
AWS Lambdaの環境変数にて、Amazon CloudWatch Alarm名を渡しています。

02.png

ここを押すと展開します

import os
import json
import boto3
from botocore.exceptions import ClientError
cloudwatch = boto3.client("cloudwatch")
ALARM_NAME = os.getenv("ALARM_NAME")
def lambda_handler(event, context):
    try:
        response = cloudwatch.describe_alarms(
            AlarmNames=[ALARM_NAME]
        )
        if not response['MetricAlarms']:
            return {
                'statusCode': 404,
                'body': json.dumps({'message': f'Alarm {ALARM_NAME} not found'})
            }
        state_value = response['MetricAlarms'][0]['StateValue']
        location = 'Osaka' if state_value == 'ALARM' else "Tokyo"
        return{
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json; charset=utf-8'
            },
            'body': json.dumps({'location': location, 'state': state_value}, ensure_ascii=False)
        }
    except Exception as e:
        print(f"Error: {e}")
        return {
            'statusCode': 500,
            'body': json.dumps({'message': 'Internal Server Error'})
        }

Amazon API Gateway

Amazon API Gatewayの設定もシンプルです。
リージョンタイプの REST API とし、AWS Lambda プロキシ統合を有効化しています。

03.png

Amazon EventBridge Connections

Amazon EventBridge Connections は、AWS Step Functions の「Call HTTPS APIs」ステップで外部の HTTPS エンドポイントを呼び出す際に、認証方法や接続情報を管理するためのリソースです。
今回の構成では、各リージョンの AWS Step Functions からバージニアリージョンの Amazon API Gateway を呼び出すために使用しています。
以下の手順で作成していきます。

Amazon EventBridge の左ペイン>統合>接続から「接続を作成」をクリックします。 12.png

接続名を記載します。
説明の記載は不要です。 13.png

呼び出し設定は「パブリック」とします。 14.png

「認証を設定」では、カスタム設定、「認証タイプ」ではAPIを選択します。
今回の構成はデモのためAPIキーを使用しません。
そのため「APIキー名」と「値」は、任意の値を設定してください。 15.png

暗号化の設定はしません。
すべての設定が完了したら、「作成」をクリックします。 16.png

AWS Step Functions

東京リージョンで作成したAWS Step Functionsと、大阪リージョンで作成したAWS Step Functionsはそれぞれ以下の通りです。
アカウントIDとAmazon API Gateway IDはマスクしています。
「Call HTTPS APIs」ステップにて、レスポンスのステータスコード200以外だった場合は、

  • 東京リージョンでは AWS Lambda を実行
  • 大阪リージョンでは AWS Step Functions を終了

という処理となります。 また、Amazon EventBridge Connectionの名前は「test」を前提にしています。

東京リージョンのAWS Step Functions

ここを押すと展開します

{
  "Comment": "A description of my state machine",
  "StartAt": "Call HTTPS APIs",
  "States": {
    "Call HTTPS APIs": {
      "Type": "Task",
      "Resource": "arn:aws:states:::http:invoke",
      "Parameters": {
        "ApiEndpoint": "https://xxxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/prod/",
        "Method": "GET",
        "Authentication": {
          "ConnectionArn": "arn:aws:events:ap-northeast-1:xxxxxxxxxxxx:connection/test/5a7c61aa-84f5-44b0-9b0c-3d1967f19539"
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.Http.StatusCode.429",
            "States.Http.StatusCode.503",
            "States.Timeout"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 2,
          "MaxAttempts": 3
        }
      ],
      "Next": "Evaluate the alarm status.",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "Lambda Invoke"
        }
      ]
    },
    "Lambda Invoke": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "OutputPath": "$.Payload",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "arn:aws:lambda:ap-northeast-1:xxxxxxxx:function:getlambda:$LATEST"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException",
            "Lambda.TooManyRequestsException"
          ],
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "BackoffRate": 2,
          "JitterStrategy": "FULL"
        }
      ],
      "End": true
    },
    "Evaluate the alarm status.": {
      "Type": "Choice",
      "Choices": [
        {
          "Next": "Stop Workflow",
          "Variable": "$.ResponseBody.location",
          "StringEquals": "Osaka"
        }
      ],
      "Default": "Lambda Invoke"
    },
    "Stop Workflow": {
      "Type": "Succeed"
    }
  },
  "QueryLanguage": "JSONPath"
}

04.png

大阪リージョンのAWS Step Functions

ここを押すと展開します

{
  "Comment": "A description of my state machine",
  "StartAt": "Call HTTPS APIs",
  "States": {
    "Call HTTPS APIs": {
      "Type": "Task",
      "Resource": "arn:aws:states:::http:invoke",
      "Parameters": {
        "ApiEndpoint": "https://xxxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/prod/",
        "Method": "GET",
        "Authentication": {
          "ConnectionArn": "arn:aws:events:ap-northeast-3:xxxxxxxxxxxx:connection/osaka-connection/01ba4523-77fa-4f28-8436-4421e86f256a"
        }
      },
      "Retry": [
        {
          "ErrorEquals": [
            "States.Http.StatusCode.429",
            "States.Http.StatusCode.503",
            "States.Timeout"
          ],
          "BackoffRate": 2,
          "IntervalSeconds": 2,
          "MaxAttempts": 3
        }
      ],
      "Next": "Evaluate the alarm status.",
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "Next": "Stop Workflow"
        }
      ]
    },
    "Lambda Invoke": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "OutputPath": "$.Payload",
      "Parameters": {
        "Payload.$": "$",
        "FunctionName": "arn:aws:lambda:ap-northeast-3:xxxxxxxxxxxx:function:getlambda:$LATEST"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException",
            "Lambda.TooManyRequestsException"
          ],
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "BackoffRate": 2,
          "JitterStrategy": "FULL"
        }
      ],
      "End": true
    },
    "Evaluate the alarm status.": {
      "Type": "Choice",
      "Choices": [
        {
          "Next": "Lambda Invoke",
          "Variable": "$.ResponseBody.location",
          "StringEquals": "Osaka"
        }
      ],
      "Default": "Stop Workflow"
    },
    "Stop Workflow": {
      "Type": "Succeed"
    }
  },
  "QueryLanguage": "JSONPath"
}

05.png

動作確認

実際に Amazon CloudWatch Alarm の状態を切り替えて、期待通りにリージョンが切り替わるか確認します。

アラームが正常な場合の動作

正常時(東京リージョンで処理を実行すべき状態)の動作を確認します。

06.png

東京リージョンでは、AWS Lambdaが起動しました。

07.png

大阪リージョンでは、AWS Lambdaを起動せずに終了しました。

08.png

アラームが異常な場合の動作

異常時(大阪リージョンへ切り替えるべき状態)の動作を確認します。

09.png

東京リージョンでは、AWS Lambdaを起動せずに終了しました。

10.png

大阪リージョンでは、AWS Lambdaが起動しました。

11.png

まとめ

今回は、AWS Step Functions を活用して東京・大阪リージョン間で AWS Lambda の実行を自動切り替えする DR 構成を紹介しました。

この構成のポイントをまとめると以下の通りです。

  • 第三のリージョン(バージニア)に判定ロジックを置くことで、東京・大阪どちらの障害にも対応可能
  • Amazon CloudWatch Alarm の状態に基づいて、実行リージョンを動的に切り替え
  • 各リージョンの AWS Step Functions が自律的に判断するため、手動での切り替え操作が不要

なお、今回はデモのため Amazon API Gateway の認証(API キー)を省略しています。本番環境で利用する際は、適切な認証設定を行ってください。

初めてAWS Step Functionsを使った構成だったため、構築に時間がかかりましたが、正常にAWS Step Functionsが起動したときはとても嬉しかったです。
機会があればほかの構成についても紹介したいと思います。

この記事は私が書きました

山内 宏紀

記事一覧

CloudFormationが好きです。 使っているギターはSGです。

山内 宏紀

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。