こんにちは、技術1課の中村です。
今日は、AWS IoTのRule Actionについてのお話です。
今日は、AWS IoTのRule Actionについてのお話です。
AWS IoTのRule Actionといえば、S3やSQS、DynamoDB、さらには SalesforceなどのSaaSとの連携もこなしてくれる、すごいヤツです。
今回は、AWS IoTのRule Actionの中のLambda呼び出しアクションについて検証をしてみました。
まずは、Lambdaの サポートされているイベントソース のページを確認してみたのですが、AWS IoTからの実行についての記載はなかったので実際に試してみることにしました。
Lambdaは、同期タイプと非同期タイプで異常終了時の再試行の挙動が異なります。具体的には、同期タイプの呼び出しの場合は異常終了したとしても再試行は行われません。対して、非同期タイプの呼び出しの場合は異常終了した時、その後間隔を空けて2回Lambdaによって再試行が行われます。
そのため、AWS IoTから連携するLambda Functionに意図的にエラーを仕込んで、Lambdaによって再試行されるかどうかを試してみました。結果、元々の実行が1回、その後Lambdaによって2回再実行されていることが確認できたので、非同期タイプの呼び出しであると言えるでしょう。
…と、もっともらしく検証の方法を書いたのですが、シンプルにCloudTrailを見れば良いという事に後から気がつきました。
というわけでCloudTrailから確認してみました。以下は抜粋ですが、ちゃんと
(同期呼び出しの場合は、
1 で記載した通り、AWS IoTからのLambda Functionの呼び出しは非同期です。そのため、Lambda Functionの呼び出しが成功したかどうかはステータスコード(202)で返りますが、Lambda Functionの中身のプログラムが正しく終了したかどうかは呼び出し時には受け取ることはできません。
こちらも検証してみました。
結果
結果
(Lambda Function Aの実行ログはCloudTrailには記録されていませんでした)
上記の結果から、「AWS IoTからLambdaのInvoke APIの実行に失敗した時に、Error Actionが実行される」で間違いなさそうです。
パターン1はプログラムのバグによりLambda Function Aが異常終了するケース、パターン2はLambda Functionが存在しないことにより、そもそものLambda Functionの実行(
つまり、AWS IoTからRule Actionを使ってLambdaに連携する場合には、連携するLambda Functionにバグがあって異常終了したとしてもRuleに設定したError Actionは実行されないのです。そのため、Lambda Functionの異常終了を拾いたい場合は、Lambdaのデッドレターキューを使ったり、ログ監視をしたり、プログラム内に例外発生時の通知を実装するなり、工夫する必要がありそうですね。
AWS IoTのRule Actionを使ってLambdaと直接連携する方法は、データ処理効率の点から個人的にはあまりオススメできません。
一般的にIoTのシステムは継続的に大量のメッセージが流れ込みますが、AWS IoTとLambdaを直で連携させる場合、以下のような懸念点がでてきます。
これらのサービスを挟むことによる得られるメリットは以下の通りです。
(AWS IoTとLambdaの直連携も、シンプルでいいですよ!)
今回は、AWS IoTのRule Actionの中のLambda呼び出しアクションについて検証をしてみました。
本題
今回ここで書くことは以下の3つです。- AWS IoTのRule ActionによるLambda Functionの起動は、同期タイプ?非同期タイプ?
- AWS IoTのRule ActionでLambda Functionを指定した場合、Error Actionはどのような条件で実行される?
- AWS IoTからLambda Functionを起動したい時、結局の所どうすべき?(筆者の視点から)
1. AWS IoTのRule ActionはによるLambda Functionの起動は、同期タイプ?非同期タイプ?
結論から言うと、非同期タイプでした。まずは、Lambdaの サポートされているイベントソース のページを確認してみたのですが、AWS IoTからの実行についての記載はなかったので実際に試してみることにしました。
Lambdaは、同期タイプと非同期タイプで異常終了時の再試行の挙動が異なります。具体的には、同期タイプの呼び出しの場合は異常終了したとしても再試行は行われません。対して、非同期タイプの呼び出しの場合は異常終了した時、その後間隔を空けて2回Lambdaによって再試行が行われます。
そのため、AWS IoTから連携するLambda Functionに意図的にエラーを仕込んで、Lambdaによって再試行されるかどうかを試してみました。結果、元々の実行が1回、その後Lambdaによって2回再実行されていることが確認できたので、非同期タイプの呼び出しであると言えるでしょう。
…と、もっともらしく検証の方法を書いたのですが、シンプルにCloudTrailを見れば良いという事に後から気がつきました。
というわけでCloudTrailから確認してみました。以下は抜粋ですが、ちゃんと
"invocationType":"Event"
(非同期呼び出し) となっていますね。(同期呼び出しの場合は、
"invocationType":"RequestResponse"
となります)
eventtime | eventsource | eventname | useragent | requestparameters(抜粋) |
2019-01-24T05:20:38Z | lambda.amazonaws.com | Invoke | iot.amazonaws.com | "functionName":"invoke_test" "invocationType":"Event" |
2019-01-24T05:20:38Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_test" |
2019-01-24T05:21:41Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_test" (リトライ) |
2019-01-24T05:23:38Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_test" (リトライ) |
2. AWS IoTのRule ActionでLambda Functionを指定した場合、Error Actionはどのような条件で実行される?
これも結論から言うと、恐らく「AWS IoTからLambdaのInvoke APIの実行に失敗した時に、Error Actionが実行される」だと考えられます。1 で記載した通り、AWS IoTからのLambda Functionの呼び出しは非同期です。そのため、Lambda Functionの呼び出しが成功したかどうかはステータスコード(202)で返りますが、Lambda Functionの中身のプログラムが正しく終了したかどうかは呼び出し時には受け取ることはできません。
こちらも検証してみました。
パターン1
前提- AWS IoTのRule ActionにLambda Function Aの呼び出しを、Error ActionにLambda Function Bの呼び出しを設定する
- Lambda Function A には意図的にエラーを仕込んで、プログラムが必ず異常終了するように設定する
- Lambda Function B は正常終了するように設定する
結果
- Lambda Function A は計3回実行される (1回の通常実行 + 2回の自動リトライ)
- Lambda Function B は実行されない
eventtime | eventsource | eventname | useragent | requestparameters(抜粋) |
2019-01-24T05:20:38Z | lambda.amazonaws.com | Invoke | iot.amazonaws.com | "functionName":"invoke_test" (A) "invocationType":"Event" |
2019-01-24T05:20:38Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_test" (A) |
2019-01-24T05:21:41Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_test" (Aのリトライ) |
2019-01-24T05:23:38Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_test" (Aのリトライ) |
パターン2
前提- AWS IoTのRule ActionにLambda Function Aの呼び出しを、Error ActionにLambda Function Bの呼び出しを設定する
- Lambda Function A を削除する
- Lambda Function B は正常終了するように設定する
結果
- Lambda Function A 実行されない (そもそも存在しない)
- Lambda Function B が1回実行される
eventtime | eventsource | eventname | useragent | requestparameters(抜粋) |
2019-01-24T01:44:47Z | lambda.amazonaws.com | Invoke | iot.amazonaws.com | "functionName":"invoke_failed_test" (B) "invocationType":"Event" |
2019-01-24T01:44:47Z | lambda.amazonaws.com | InvokeExecution | lambda.amazonaws.com | "functionName":"invoke_failed_test" (B) |
上記の結果から、「AWS IoTからLambdaのInvoke APIの実行に失敗した時に、Error Actionが実行される」で間違いなさそうです。
パターン1はプログラムのバグによりLambda Function Aが異常終了するケース、パターン2はLambda Functionが存在しないことにより、そもそものLambda Functionの実行(
invoke()
)に失敗するケースです。つまり、AWS IoTからRule Actionを使ってLambdaに連携する場合には、連携するLambda Functionにバグがあって異常終了したとしてもRuleに設定したError Actionは実行されないのです。そのため、Lambda Functionの異常終了を拾いたい場合は、Lambdaのデッドレターキューを使ったり、ログ監視をしたり、プログラム内に例外発生時の通知を実装するなり、工夫する必要がありそうですね。
3. AWS IoTからLambda Functionを起動したい時、結局の所どうすべき?(筆者の視点から)
これも結論から書くと、私はAWS IoTとLambdaの間にKinesis StreamsやSQS(SNS)を挟む構成を検討することが多いです。(ここでは、エラーアクションについては割愛します)AWS IoTのRule Actionを使ってLambdaと直接連携する方法は、データ処理効率の点から個人的にはあまりオススメできません。
一般的にIoTのシステムは継続的に大量のメッセージが流れ込みますが、AWS IoTとLambdaを直で連携させる場合、以下のような懸念点がでてきます。
- A. 処理の単位が 1メッセージにつき1Functionとなり、データの処理効率が悪い
- B. Lambdaが非同期タイプの起動のため、Lambdaの同時実行数(デフォルト1000)を超えた実行リクエストはキューイングされるが、キューイングされた実行リクエストはその後 6時間まで しか再試行されない ※2019年1月時点
これらのサービスを挟むことによる得られるメリットは以下の通りです。
- A. データ処理効率の件
- Kinesis StreamsやSQSを挟み、バッチサイズを適切に設定することで1Function内で複数のメッセージを扱うことが出来るようになり、処理効率が上がる
- Kinesis Streamsのシャードを複数用意することで、Lambdaによるデータ処理を並列化できる
- B. 非同期呼び出しのキューイングの話
- Kinesis StreamsやSQSから実行されるLambda Functionは非同期タイプの起動ではない
- Kinesis Streamsの場合はLambda Functionがシャード数分起動する
- SQSの場合は、Lambda Functionの同時実行数で設定した値まで起動する
- Kinesis StreamやSQSを挟むことで処理待ちデータを無限に待てるようになるわけではないが、処理待ちのデータの扱いを柔軟に設定できる
- Kinesis Streamsであれば、シャードの内のデータの保持期間を最大7日まで設定可能 ※2019年1月時点
- SQSであれば、メッセージの保持期間を最大14日まで設定可能 ※2019年1月時点
- Kinesis StreamsやSQSから実行されるLambda Functionは非同期タイプの起動ではない
(AWS IoTとLambdaの直連携も、シンプルでいいですよ!)
まとめ
この記事では、AWS IoTとLambdaの関係について、以下の3つを記載しました。- AWS IoTのRule ActionはによるLambda Functionの起動は、同期タイプ?非同期タイプ?
-> 非同期タイプ - AWS IoTのRule ActionでLambda Functionを指定した場合、Error Actionはどのような条件で実行される?
->invoke()
の実行に失敗した時。invoke()
自体が成功した後にプログラムでコケた場合にはError Actionが呼ばれないので注意 - AWS IoTからLambda Functionを起動したい時、結局の所どうすべき?(筆者の視点から)
-> 規模に応じて、Kinesis StreamsやSQSを挟むと幸せになれる。データ流入量が少ないのであれば直連携でも良さそう