【ハンズオン】API Gateway+Lambdaの構成にX-Rayを有効化

# はじめに
DVA試験対策でAPI Gateway+Lambda構成にX-Rayを有効化して挙動を確認しました。
本記事では、この構成にX-Rayを有効化する方法を記載します。

# X-Rayとは
API GatewayやLambda等、各サービスの処理時間を記録するサービス
　処理時間をコンソール上で可視化
　どの処理でボトルネックが発生しているかを特定できる
　Lambdaでは、X-Ray SDKを使用することで、Lambda内のAWSサービスへのリクエスト処理時間も記録

# 構成

API Gateway+Lambda+DynamoDBの構成です。
Lambdaでは、DynamoDBテーブルにクエリし、返ってきたデータを返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/8f6df9f8-3165-8462-8c46-087649d37b8e.png)


・使用言語
Python（Lambdaでは3.9をランタイム環境として使用）

・開発環境
　OS：Windows
　Pythonバージョン：3.8.6

# 手順

## DynamoDBテーブル作成

IDとユーザー名を持つテーブルを作成します。

DynamoDBのコンソール画面にて、「テーブルの作成」をクリック
![スクリーンショット 2023-01-18 222343.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/a38844e9-157c-663f-008a-e38033cf5056.png)

テーブル名、パーティションキーを以下に設定し、他の設定はデフォルトでテーブルを作成
　テーブル名：testtable
　パーティションキー：ID（タイプ：数値）
![スクリーンショット 2023-01-18 222533.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/a426fb6c-3a44-69d4-a826-ab801788ea7a.png)

作成したテーブルにレコード（DynamoDBでは項目と呼びます）を登録
テーブル画面で、アクション→項目を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/158a0503-4a13-ce77-559b-c0f4e4bfb19f.png)

「新しい属性の追加」ボタンをクリックし、username属性（タイプ：文字列）を追加します。
追加後、レコードを入力し、「項目を作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/3e0c7092-fda6-45f6-19e6-f06ee98dc69a.png)

レコードが作成されたことを確認します。
「テーブルアイテムの探索」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/6a267179-50b8-6be9-0248-29af884e7ade.png)

返された項目欄に、登録したレコードが記録されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/df318700-0168-0f77-3752-8bc10b862585.png)


## X-Ray実行コードのパッケージをLambda Layerにデプロイ

X-Ray実行コードのパッケージをLambda Layerにデプロイします。
具体的には、X-Ray実行コードを含むディレクトリをzipし、zipファイルをLayerにデプロイします。

※Lambda Layer
Lambda Layerにコードを登録すると、Lambda関数からコードを参照できるようになります。
X-Rayは複数のLambda関数から呼び出すことが多いので、Layerにデプロイして、他Lambda関数から呼び出せるようにします。

### X-Ray実行コードのパッケージを用意

まず、X-Ray実行コードを配置するディレクトリを用意します。
コマンドプロンプトを開き、コード配置ディレクトリに移動した後、以下のpip installコマンドを実行し、requestパッケージとX-Rayパッケージをインストールします。
```
$ pip install requests -t ./
$ pip install aws-xray-sdk -t ./
```

インストール後、X-Ray実行コードファイルを作成します。
以下がコードの中身です。
　ファイル名：layer.py
```layer.py
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all

patch_all()
```
ファイル編集後、X-Ray実行コードを含むディレクトリをzipにします。

### X-Ray実行コードのパッケージをLambda Layerにデプロイ

Lambdaのコンソール画面に移動し、レイヤー→レイヤーの作成をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/05c89edb-6854-f5c6-d19c-698a70db45c6.png)

以下項目を記載の通りに入力し、レイヤーを作成します。
名前：xray
説明：X-Ray実行コード（入れなくてもOK）
zipファイルをアップロードを選択し、↑でzip化したパッケージをアップロードします。
互換性のランタイム：Python 3.9
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/c3ee3f7c-bab2-863e-66e4-8ff3bed06d6d.png)

レイヤーコンソール画面に作成したレイヤーが表示されることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/512c0a03-c8c9-5534-2dd3-521be691a8e2.png)

## Lambda関数作成

以下処理を実施するPythonコードをLambda関数として登録します。
　DynamoDBテーブルにクエリ
　クエリ結果をレスポンスに入れてreturn

Pythonコードの中身
　"import layer"でLayerにデプロイしたX-Ray実行コードを読み込みます。
　　デプロイしたLambda Layerは、この後作成するLambda関数に紐づける必要があります。
　　紐づけはLambda関数作成後に実施します。
　クエリIDは、テーブルに登録したレコードの値に設定します。
```test.py
import json
import boto3
import layer
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):
    #dynamodbにアクセス
    queryID = 1
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table("testtable")
    querydata = table.query(
      KeyConditionExpression = Key("ID").eq(queryID)
    )
    if querydata["Count"] == 0:
        username = "unknown"
    else:
        username = querydata["Items"][0]["username"]
    return {
        'statusCode': 200,
        'body' : username
    }
```

Lambdaコンソールにて、関数の作成をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/86eba7f4-5167-9d11-d4a5-ddee4d37e0b7.png)

以下の内容でLambda関数を作成します。
関数名：test-xray
ランタイム：Python 3.9
　Layerと同じランタイムにする必要があります！
他はデフォルトのままでOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/25e8808b-6940-f52e-41c9-94bc22091ade.png)

Lambdaのコードをデプロイします。
↑記載のコードをLambda関数のコードに貼り付けます。
貼り付け後、「Deploy」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/476924dc-0248-4b68-5ba5-8c139ef4130e.png)


Lambda関数に紐づくIAMロールに、DynamoDBの読み取り権限を付与します。
（デフォルトで作られるIAMロールにはこの権限が付与されていないため）
作成したLambda関数の画面に移動します。
設定→アクセス権限→ロール名をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/66d88f84-cc4f-85c8-abdf-c3bca421d5bf.png)

許可→許可ポリシーの「許可を追加」→「ポリシーをアタッチ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/a09ed6a8-0a7f-7d17-538b-230d0c4c1fc2.png)

AmazonDynamoDBReadOnlyAccessポリシーを選択し、「ポリシーをアタッチ」をクリックします。
（検索フォームでDynamoと検索すると出てきます。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/f9e27332-2840-6715-266a-277634d7e1cc.png)

ポリシーがアタッチされていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/7ea892b6-0406-2657-8144-3877f594b961.png)

Lambda関数にX-Rayを有効化します。
Lambda関数画面の「設定」→「モニタリングおよび運用ツール」の「編集」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/564c8ff1-5fe3-da65-92b6-7f21e1a15e2a.png)

AWS X-Rayを有効化して保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/bd2c0483-e901-a290-8a4a-0bd7804af74b.png)

LambdaでX-Rayが実行されているか、コードを実行して確認します。
テストタブに移動し、以下内容でテストイベントを作成します。
　イベントアクションをテスト：新しいイベントを作成
　イベント名：test
他の設定はデフォルトのままで、「保存」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/aab995c7-65ec-21ac-7c56-e3f08df46336.png)

テストを実施します。
「テスト」ボタンをクリックします。
実行後、以下の結果が返ってくることを確認します。
```
{
  "statusCode": 200,
  "body": "Taro Tanaka"
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/42d7a390-8792-8dd3-91d2-76236295d842.png)

AWS X-Rayが実行されているか確認します。
モニタリングタブに移動します。
Service Mapにて、下図のようにLambdaとDynamoDBが可視化されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/616a8a2e-8efe-eb3e-1c80-a501b014d147.png)

さらに、Map下のIDをクリックすると、CloudWatchのX-Rayコンソール画面に移動し、詳細内容を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/5f141731-4140-25bf-2b7e-3a6d26c602ee.png)

CloudWatachのX-Rayコンソールの、セグメントのタイムライン欄で、DynamoDBへのクエリに要した時間が記録されていることが確認できます。
このように、X-Ray SDKを使うことで、Lambda関数内のAWSサービス呼び出しに要した時間も把握できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/fe3e3acb-1777-d2ed-0de6-31202a440fb1.png)


Lambda関数の設定は以上です。
次に、API Gatewayを作成します。


## API Gatewayの作成

API Gatewayのコンソールに移動し、「APIを作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/31365594-ed08-9346-0e25-efe25b7489e4.png)

REST APIの「構築」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/cb38cf4d-bf07-a064-7f92-e7119f345435.png)


以下内容でREST APIを作成します。
　REST選択
　「新しいAPI」を選択
　API名：testxray
　エンドポイントタイプ：リージョン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/c871ea11-8c5d-b11f-464d-caf5d6f8ce39.png)



APIが作成されると以下画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/1921471b-209e-7788-cd33-a746f94776b6.png)


API作成後、GETメソッドを作成します。
アクション→「メソッドの作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/ca5fbcd5-b012-adb2-554c-0d92a1e18aed.png)

GETメソッドを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/cad09876-ba44-7f32-b574-ff08ff6d114a.png)

メソッド横のチェックボタン（下図赤枠）をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/f49e04fb-1c0f-74f1-0c8a-3d587269598b.png)

以下内容で設定し、「保存」をクリックします。
　統合タイプ：Lambda関数
　Lambdaプロキシ統合の使用：チェックを入れる
　Lambdaリージョン：ap-northeast-1
　Lambda関数：test-xray
　デフォルトタイムアウトの使用：チェックを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/179cc748-2ec8-4acd-558a-6a0e2f48c58a.png)

以下画面が表示されるのでOKをクリックします。
（Lambda関数ポリシーに、当該API Gatewayが関数を呼び出す権限を付与します）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/e0fde1f0-eeac-2a31-3f54-06bdeb13c985.png)

これでAPI GatewayにLambda関数が紐づかれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/57b191df-efcd-b76a-f5eb-f80b0911ce7d.png)

Lambdaの画面に、API Gatewayが表示されていることも確認します。
（API GatewayとLambdaが紐づかれていることの確認です）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/9aac60d1-536c-a45c-0230-bd00820f3cd7.png)


APIを実行できる状態にするために、API をデプロイします。
アクション→「APIのデプロイ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/4b68c2f1-7473-a092-f257-cd6ee7f97b3a.png)

以下の内容でデプロイします。
　デプロイされるステージ：新しいステージ
　ステージ名：任意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/f8680c29-763f-abd6-703c-0de9d900700f.png)

APIがデプロイされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/158523f7-7c1c-2eb8-b8d8-c635d1e80d81.png)

デプロイされたAPIにX-Rayを有効化します。
ログ/トレースタブの、「X-Rayトレースの有効化」にチェックを入れ、「変更を保存」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/5fb73c8a-ea83-8cc4-651b-a21dc87115ea.png)

有効化後、APIのURLにブラウザでアクセスします。
以下のように、DynamoDBのテーブルの値が返ってくることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/c22c865d-7ed6-c869-e5a9-ad65babf5e39.png)

X-Rayのコンソールに移動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/262671e8-b9db-0504-77ae-97751701c797.png)

対象のAPI URLのログのIDをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/15f46a9d-d20f-7de6-7b85-7b2783a0e8d5.png)


以下画面のように、DynamoDBへの呼び出しも可視化されていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/7aa3d715-36cc-4cf5-2af4-3cdcec1fbcb4.png)

API全体の所要時間に加えて、Lambda処理のトータル所要時間、Lambda内のDynamoDB呼び出しの所要時間が可視化されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/a4b8c57b-9caa-2f58-68fc-eb9344135f42.png)


# まとめ
API GatewayとLambdaにX-Rayを有効化することで、各コンポーネントの処理時間を可視化して把握することができます。
さらにLambdaにて、X-Ray SDKを使うことで、Lambda内の各AWSサービスへの呼び出しの所要時間も可視化されます。
X-Ray SDKも使うことで、より細かく各処理の所要時間を把握できるので、どの部分がボトルネックとなっているか知ることができそうです。
運用ではX-Ray SDKも利用するのが望ましいと感じました。

# 参考記事
https://qiita.com/mksamba/items/448c538236ab2989eba9
https://qiita.com/miyuki_samitani/items/f01f1bd49334f97fe84c
https://qiita.com/Ricordanza/items/d68d708e274e28b6bfa2