Kinesis DataStreamをトリガーに起動するLambdaは、「1秒毎に起動するとは限らない」という話

kinesis DataStreamをトリガーにして起動するLambdaについて、Lambdaの実行時間が「1秒より短い」または「1秒より長い」とき、どのタイミングでLambdaが起動するのかを調べてみました。
2019.05.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

サーバーレス開発部の藤井元貴です。

AWS公式の形で考えるサーバーレス設計は良いものですね。

このうち、Lambdaの同時実行数を制御したい等の理由で、Kinesis DataStreamを使う事は多々あります。

流入データの連続処理

Kinesis DataStreamの設定にシャード数があり、「Lambdaの同時実行数の上限」はこのシャード数と一致します。

そして、Lambdaは1秒毎にシャードを監視しており、Kinesis DataStreamにデータがあれば起動して処理します。

このとき、下記が気になったので試してみました。

  • Lambdaの実行時間が1秒より短いとき、Lambdaが終了したらすぐ起動するの? それとも1秒待つの?
  • Lambdaの実行時間が1秒より長いとき、Lambdaの終了を待たず1秒後に起動するの? それともLambdaの終了まで待つの?

以下、やってみた

おすすめの方

  • AWS SAMを使いたい
  • AWS SAMでKinesis DataStreamを定義したい
  • Kinesis DataStreamにAWS CLIでデータを送りたい
  • Kinesis DataStreamとLambdaについて、Lambdaの起動タイミングが知りたい

環境

項目 バージョン
macOS Mojave 10.14.4
AWS CLI aws-cli/1.16.89 Python/3.6.1 Darwin/17.7.0 botocore/1.12.79
AWS SAM CLI 0.10.0
Python 3.6

作成する

プロジェクトフォルダの作成

sam init --runtime python3.6 --name TryKinesisLambda

Lambda関数とtemplateファイル

app.pyとtemplate.yamlは下記です。

実験内容によって、Lambdaのtime.sleep()の秒数を変更します。

requirements.txtは空っぽにします。

S3バケットの作成

コード等を格納するためのS3バケットを作成します。作成済みの場合は飛ばします。

aws s3 mb s3://cm-fujii.genki-sam-test-bucket

build

下記でビルドします。

sam build

package

コード一式をS3バケットにアップロードします。

sam package \
    --output-template-file packaged.yaml \
    --s3-bucket cm-fujii.genki-sam-test-bucket

deploy

デプロイします。

sam deploy \
    --template-file packaged.yaml \
    --stack-name TryKinesisLambda \
    --capabilities CAPABILITY_IAM

動作確認

Kinesis DataStreamにデータを送信する準備

Kinesis DataStreamに送信するデータを作成します。

$ touch test-data.json

中身は下記です。全部で14個のデータを送信します。

test-data.json

{
    "Records": [
        {
            "Data": "aaa",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "bbb",
            "PartitionKey": "pk-2"
        },
        {
            "Data": "ccc",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "ddd",
            "PartitionKey": "pk-2"
        },
        {
            "Data": "eee",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "fff",
            "PartitionKey": "pk-2"
        },
        {
            "Data": "ggg",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "hhh",
            "PartitionKey": "pk-2"
        },
        {
            "Data": "iii",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "jjj",
            "PartitionKey": "pk-2"
        },
        {
            "Data": "kkk",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "lll",
            "PartitionKey": "pk-2"
        },
        {
            "Data": "mmm",
            "PartitionKey": "pk-1"
        },
        {
            "Data": "nnn",
            "PartitionKey": "pk-2"
        }
    ],
    "StreamName": "test-stream"
}

実際にデータを送信する場合は、下記コマンドを実行します。

aws kinesis put-records --cli-input-json file://test-data.json

データ数は14個のため、Lambdaは5回起動するはずです。

Lambda実行時間:50ミリ秒のとき

Lambda time Duration
1回目 2019-05-22T08:09:40.763796 50.67 ms
2回目 2019-05-22T08:09:40.853314 50.70 ms
3回目 2019-05-22T08:09:40.929184 50.61 ms
4回目 2019-05-22T08:09:41.004926 50.72 ms
5回目 2019-05-22T08:09:41.083495 50.74 ms
  • Kinesis DataStreamにあるデータが無くなるまで、Lambdaは起動し続ける

Lambda実行時間:5秒のとき

Lambda time Duration
1回目 2019-05-22T08:25:09.246640 5005.61 ms
2回目 2019-05-22T08:25:14.279199 5005.60 ms
3回目 2019-05-22T08:25:19.309775 5004.83 ms
4回目 2019-05-22T08:25:24.337513 5005.57 ms
5回目 2019-05-22T08:25:29.367969 5005.57 ms
  • Lambdaは5秒毎に起動する

実験終了

Kinesis DataStreamをそのままにしておくと随時課金されるため、作成したStackを削除します。

aws cloudformation delete-stack --stack-name TryKinesisLambda

まとめ

下記動作と理解しました。(間違ってたら教えてください!)

  • Lambda関数が起動していないとき、Kinesis DataStreamに対して「データある?」と聞く
    • Kinesis DataStreamにデータがある場合は、Lambda関数は起動する
    • Kinesis DataStreamにデータがない場合は、何もしない(1秒後にまた聞く)
  • Lambda関数が終了したあと、
    • Kinesis DataStreamにデータがまだあるとき、Lambda関数は続けて起動する
    • Kinesis DataStreamにデータがないとき、Lambda関数は起動しない

ざっくり図にすると下記ですね。

Kinesis DataStreamとLambdaの起動関係性

Lambda は、レコードの Kinesis ストリームにある各シャードを 1 秒あたり 1 回の基本レートでポーリングします。利用可能なレコードが増えると、Lambda は設定されている最大バッチサイズより小さいバッチを受け取るまでバッチの処理を維持します。

冒頭の振り返り

  • Lambdaの実行時間が1秒より短いとき、Lambdaが終了したらすぐ起動するの? それとも1秒待つの?
    • Lambdaが終了したらすぐ起動する
  • Lambdaの実行時間が1秒より長いとき、Lambdaの終了を待たず1秒後に起動するの? それともLambdaの終了まで待つの?
    • Lambdaの終了まで待つ

スッキリしました。

参考