Lambda における実行に関する問題点のトラブルシューティング - AWS Lambda

Lambda における実行に関する問題点のトラブルシューティング

Lambda ランタイムが関数コードを実行すると、このイベントは、すでに他のイベントを処理中の関数のインスタンスで処理されるか、必要に応じて新しいインスタンスが初期化されます。関数が初期化されている間に、ハンドラーコードでイベントが処理されているときに、または関数からレスポンスが返される (または返されない) ときに、エラーが発生する場合があります。

関数の実行エラーは、コード、関数の設定、ダウンストリームのリソース、またはアクセス許可の問題に起因する場合があります。関数を直接呼び出した場合は、Lambda からのレスポンスに関数エラーが表示されます。イベントソースマッピングまたは別のサービスを通じて関数を非同期的に呼び出した場合は、ログ、配信不能キュー、または障害発生時の送信先にエラーが表示されることがあります。エラー処理オプションと再試行の動作は、関数を呼び出した方法とエラーの種類によって異なります。

関数コードまたは Lambda ランタイムからエラーが返された場合、Lambda からのレスポンスのステータスコードは 200 OK です。レスポンス内にエラーが存在することは、X-Amz-Function-Error という名前のヘッダーで示されます。400 および 500 シリーズのステータスコードは、呼び出しエラー用に予約されています。

Lambda: 実行に時間がかかり過ぎています

問題: 関数の実行に時間がかかり過ぎる。

Lambda でコードを実行すると、ローカルマシンよりもはるかに長い時間がかかる場合は、その関数で使用できるメモリまたは処理能力が制限されている可能性があります。メモリと CPU の両方を増やすには、メモリを追加して関数を設定します。

Lambda: 予想しないイベントペイロード

問題: 不正な形式の JSON または不適切なデータ検証に関連する関数エラー。

すべての Lambda 関数は、ハンドラーの最初のパラメータでイベントペイロードを受け取ります。イベントペイロードは、配列とネストされた要素を含む可能性のある JSON 構造です。

不正な形式の JSON は、JSON 構造のチェックに堅牢なプロセスを使用していないアップストリームサービスによって提供されるときに発生する可能性があります。これは、サービスがテキスト文字列を連結する場合や、サニタイズされていないユーザー入力を埋め込む場合に発生します。また、JSON は、サービス間で渡すために頻繁にシリアル化されます。JSON のプロデューサーとコンシューマーとして両方の JSON 構造を常に解析し、構造が有効であることを確認してください。

同様に、イベントペイロードの値の範囲をチェックしないと、エラーが発生する恐れがあります。次の例は、源泉徴収額を計算する関数を示しています。

exports.handler = async (event) => { let pct = event.taxPct let salary = event.salary // Calculate % of paycheck for taxes return (salary * pct) }

この関数は、イベントペイロードの給与と税率を使用して計算を実行します。ただし、このコードは属性が存在するかどうかをチェックすることはできません。また、データ型をチェックすることや、境界を確認する (税率が 0 から 1 の間であることを確認するなど) こともできません。その結果、これらの範囲外の値は、無意味な結果を生成します。型が正しくない場合や、属性がない場合には、ランタイムエラーが発生します。

テストを作成して、関数でより大きなペイロードサイズが処理されることを確認します。Lambda イベントペイロードの最大サイズは 256 KB です。コンテンツによっては、ペイロードが大きいほど、関数に渡される項目が増えたり、JSON 属性に埋め込まれるバイナリデータが増えたりする可能性があります。どちらの場合も、これによって Lambda 関数の処理が増える可能性があります。

ペイロードが大きいと、タイムアウトが発生することもあります。例えば、ある Lambda 関数は 100 ミリ秒ごとに 1 つのレコードを処理し、タイムアウトは 3 秒です。ペイロード内の 0~29 個の項目の処理は成功します。しかし、ペイロードに 30 個を超える項目が含まれていると、関数はタイムアウトし、エラーをスローします。これを回避するには、予想される最大項目数に対して追加の処理時間を処理するようにタイムアウトが設定されるようにします。

Lambda: 予想外に大きなペイロードサイズ

問題: 関数がタイムアウトしているか、大きなペイロードが原因で関数がエラーを引き起こしています。

大きいペイロードはタイムアウトやエラーを発生する可能性があります。関数が予想される最大ペイロードを処理し、関数のタイムアウトが適切に設定されていることを確認するテストの作成をお勧めします。

さらに、特定のイベントペイロードには、他のリソースへのポインタを含めることができます。例えば、128 MB のメモリを使用する Lambda 関数は、S3 にオブジェクトとして保存されている JPG ファイルで画像処理を実行できます。この関数は、小さな画像ファイルでは期待どおりに動作します。しかし、より大きな JPG ファイルが入力として提供されると、この Lambda 関数はメモリ不足によるエラーをスローします。これを回避するには、テストケースに想定されるデータサイズの上限の例を含める必要があります。コードはペイロードサイズも検証する必要があります。

Lambda: JSON エンコードとデコードエラー

問題: JSON 入力を解析する際の NoSuchKey の例外。

JSON 属性が正しく処理されていることを確認してください。例えば、S3 によって生成されたイベントの場合、s3.object.key 属性には URL エンコードされたオブジェクトキー名が含まれます。多くの関数は、この属性をテキストとして処理して、参照されている S3 オブジェクトをロードします。

const originalText = await s3.getObject({ Bucket: event.Records[0].s3.bucket.name, Key: event.Records[0].s3.object.key }).promise()

このコードはキー名 james.jpg で機能しますが、名前が NoSuchKey の場合は james beswick.jpg エラーをスローします。URL エンコーディングはキー名のスペースやその他の文字を変換するため、このデータを使用する前に関数でキーをデコードするようにする必要があります。

const originalText = await s3.getObject({ Bucket: event.Records[0].s3.bucket.name, Key: decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")) }).promise()

Lambda: ログやトレースが表示されません

問題: ログが CloudWatch Logs に表示されない。

問題: トレースが AWS X-Ray に表示されない。

関数には、CloudWatch Logs および X-Ray を呼び出すためのアクセス許可が必要です。その実行ロールを更新してアクセス許可を付与します。ログと追跡を有効にするには、以下の管理ポリシーを追加します。

  • AWSLambdaBasicExecutionRole

  • AWSXRayDaemonWriteAccess

関数にアクセス許可を追加する場合は、そのコードや設定にも些細な更新を行います。これにより、(古い認証情報により実行中の) 関数のインスタンスが、強制的に停止され置き換えられます。

注記

関数の呼び出し後にログが表示されるまで、5~10 分かかることがあります。

Lambda: 関数のログの一部が表示されない

問題: 適切な権限があっても、CloudWatch Logs に関数ログが見つからない

AWS アカウント が CloudWatch Logs のクォータ制限に達すると、CloudWatch は関数のロギングを抑制します。この場合、関数によって出力されたログの一部が CloudWatch Logs に表示されない場合があります。

関数がログを出力する頻度が高すぎて Lambda で処理できない場合、ログ出力が CloudWatch Logs に表示されない可能性もあります。Lambda は、関数がログを生成する速度でログを CloudWatch に送信できない場合、関数の実行が遅くなるのを防ぐためにログをドロップします。ログ スループットが 1 つのログ ストリームで 2 MB/秒を超えると、ログ記録が正常に行われない可能性があります。

関数が JSON 形式のログを使用するように設定されている場合、Lambda はログを削除するとき CloudWatch Logs に logsDropped イベントを送信しようとします。ただし、CloudWatch は、関数のログから受け入れることができるデータ量を調整していると、ログを受け取れない場合があります。そのため、Lambda がログを削除したときにレコードが常に表示されるとは限りません。

AWS アカウント が CloudWatch Logs のクォータ制限に達しているかどうかを確認するには、次の手順を実行します。

  1. Service Quotas コンソール を開きます。

  2. ナビゲーションペインで、[AWS services] (AWS のサービス) を選択します。

  3. [AWS サービス] リストから、Amazon CloudWatch Logs を検索します。

  4. [Service Quotas] リストで、CreateLogGroup throttle limit in transactions per secondCreateLogStream throttle limit in transactions per second および PutLogEvents throttle limit in transactions per second クォータを選択して使用状況を表示します。

また、アカウントの使用率がこれらのクォータに指定した制限を超えたときに警告するように CloudWatch アラームを設定することもできます。詳しくは、「Create a CloudWatch alarm based on a static threshold」をご覧ください。

CloudWatch Logs のデフォルトのクォータ制限がユースケースに十分ではない場合は、クォータの引き上げをリクエストできます

Lambda: 関数は実行が終了する前に返します

問題: (Node.js) コードの実行が終了する前に関数が戻る

AWS SDK を含む多くのライブラリは、非同期的に動作します。レスポンスを待つ必要があるネットワーク呼び出しや別のオペレーションを実行すると、ライブラリは、オペレーションの進行状況をバックグラウンドで追跡するプロミスと呼ばれるオブジェクトを返します。

プロミスがレスポンスに解決されるまで待つには、await キーワードを使用します。これにより、プロミスがレスポンスを含むオブジェクトに解決されるまで、ハンドラーコードの実行がブロックされます。レスポンス内のデータをコードで使用する必要がない場合は、プロミスをランタイムに直接返すことができます。

一部のライブラリはプロミスを返しませんが、これらはプロミスを返すコードでラップできます。詳細については、「Node.js の Lambda 関数ハンドラーの定義」を参照してください。

Lambda: 意図しない関数バージョンまたはエイリアスの実行

問題: 関数のバージョンまたはエイリアスが呼び出されない

コンソール内または AWS SAM を使用して新しい Lambda 関数を発行するとき、最新のコードバージョンは $LATEST で表されます。デフォルトでは、バージョンまたはエイリアスを指定しない呼び出しは、関数コードの $LATEST バージョンを自動的にターゲットにします。

特定の関数バージョンまたはエイリアスを使用する場合、これらは $LATEST に加えて変更不可能な関数の公開バージョンです。これらの関数をトラブルシューティングする際、発信者が意図したバージョンまたはエイリアスを呼び出したことを最初に確認します。これを行うには、関数ログを確認します。呼び出された関数のバージョンは、常に START ログ行に表示されます。

デバッグオペレーションの図 1

Lambda: 無限ループの検出

問題: Lambda 関数に関連する無限ループパターン

Lambda 関数には 2 タイプの無限ループがあります。1 つ目は関数自体に存在し、終了しないループによって発生します。呼び出しは、関数がタイムアウトしたときにのみ終了します。タイムアウトをモニタリングし、ループ動作を修正することにより、特定できます。

2 つ目のタイプは、Lambda 関数と他の AWS リソース間のループです。これらは、S3 バケットなどのリソースからのイベントが Lambda 関数を呼び出し、同じソースリソースとやり取りして別のイベントをトリガーする場合に発生します。関数が再度呼び出され、同じ S3 バケットで別の相互作用が作成されるという動作が続きます。これらのタイプのループは、Amazon SQS キューや DynamoDB テーブルなど、多数のさまざまな AWS イベントソースによって発生する可能性があります。再帰ループ検出を使用してこれらのパターンを特定できます。

デバッグオペレーションの図 2

Lambda 関数が消費するリソースとは別のリソースに書き込むことを確認することにより、これらのループを回避できます。消費するリソースにデータを発行し返す必要がある場合、新しいデータが同じイベントをトリガーしないことを確認してください。または、イベントフィルタリングを使用します。例えば、S3 リソースおよび DynamoDB リソースを使用して無限ループに対する 2 つの提案ソリューションは次のとおりです。

  • 同じ S3 バケットに書き戻す場合、イベントトリガーとは異なるプレフィックスまたはサフィックスを使用します。

  • 同じ DynamoDB テーブルに項目を書き込む場合、消費する Lambda 関数がフィルタリングできる属性を含めてください。Lambda が 属性を検出した場合、別の呼び出しは行われません。

一般: ダウンストリームサービスの不可用性

問題: Lambda 関数が依存するダウンストリームサービスが利用できない

サードパーティーのエンドポイントやその他のダウンストリームリソースを呼び出す Lambda 関数では、サービスエラーやタイムアウトを処理できることを確認してください。これらのダウンストリームリソースは応答時間が異なったり、サービス中断によって利用できなくなったりする場合があります。実装状況によっては、サービスのエラーレスポンスが関数コード内で処理されない場合、これらのダウンストリームエラーが Lambda のタイムアウトまたは例外として表示されることがあります。

関数が API コールなどのダウンストリームサービスに依存する際、適切なエラー処理および再試行ロジックを実装してください。重大なサービスの場合、Lambda 関数はメトリクスまたはログを CloudWatch に発行する必要があります。例えば、サードパーティーの支払い API が利用できなくなった場合、Lambda 関数はこの情報をログ記録できます。その後、これらのエラーに関連する通知を送信するように CloudWatch アラームを設定できます。

Lambda は迅速にスケールできるため、サーバーレス以外のダウンストリームサービスがトラフィックの急増の処理に苦戦する場合があります。これを処理するには、一般的に次の 3 つのアプローチがあります。

  • キャッシュ — 頻繁に変更されない場合、サードパーティーのサービスによって返される値の結果をキャッシュすることを検討してください。これらの値は、関数のグローバル変数または別のサービスに保存できます。例えば、Amazon RDS インスタンスからの製品リストクエリの結果を関数内に一定期間保存して、冗長クエリを防ぐことができます。

  • キューイング - データを保存または更新する際、Lambda 関数とリソースの間に Amazon SQS キューを追加します。キューは、ダウンストリームサービスがメッセージを処理する間、データを永続的に保持します。

  • プロキシ - Amazon RDS インスタンスなど、存続期間の長い接続が一般的に使用される場合、プロキシレイヤーを使用してそれらの接続をプールして再利用します。リレーショナルデータベースの場合、Amazon RDS Proxy は Lambda ベースのアプリケーションのスケーラビリティおよび回復性を向上させるために設計されたサービスです。

AWS SDK: バージョンと更新

問題: ランタイムに含まれている AWS SDK が最新バージョンではない

問題: ランタイムに含まれている AWS SDK が自動的に更新される

スクリプト言語のランタイムには AWS SDK が含まれており、定期的に最新バージョンに更新されます。各ランタイムの現行バージョンは、ランタイムページに表示されます。より新しいバージョンの AWS SDK を使用したり、関数を特定のバージョンにロックしたりするには、ライブラリを関数コードでバンドルするか、Lambda レイヤーを作成します。依存関係を持つデプロイパッケージの作成の詳細については、以下のトピックを参照してください。

Node.js

.zip ファイルアーカイブで Node.js Lambda 関数をデプロイする

Python

Python Lambda 関数で .zip ファイルアーカイブを使用する

Ruby

.zip ファイルアーカイブで Ruby Lambda 関数をデプロイする

Java

.zip または JAR ファイルアーカイブで Java Lambda 関数をデプロイする

Go

.zip ファイルアーカイブを使用して Go Lambda 関数をデプロイする

C#

.zip ファイルアーカイブを使用して C# Lambda 関数を構築し、デプロイする

PowerShell

.zip ファイルアーカイブを使用した PowerShell Lambda 関数のデプロイする

Python: ライブラリが正しくロードされません

問題: (Python) 一部のライブラリがデプロイパッケージから正しくロードされない

C または C++ で記述された拡張モジュールを持つライブラリは、Lambda (Amazon Linux) と同じプロセッサアーキテクチャの環境でコンパイルする必要があります。詳細については、「Python Lambda 関数で .zip ファイルアーカイブを使用する」を参照してください。

Java: Java 11 から Java 17 への更新後、関数によるイベントの処理に時間がかかる

問題: (Java) Java 11 から Java 17 への更新後、関数によるイベントの処理に時間がかかる

JAVA_TOOL_OPTIONS パラメータを使用して、コンパイラを調整します。Java 17 以降の Java バージョンの Lambda ランタイムによって、デフォルトのコンパイラオプションが変更されます。この変更により、実行時間の短い関数のコールドスタートに要する時間は短縮されますが、計算負荷が高く、実行時間が長い関数については、変更前の動作のほうが適しています。Java 11 の動作に戻すには、-XX:-TieredCompilationJAVA_TOOL_OPTIONS を設定します。JAVA_TOOL_OPTIONS パラメータの詳細については、「JAVA_TOOL_OPTIONS 環境変数について」をご参照ください。