Lambda ではホットスタートが続くときグローバル変数が共有される

mull

Lambda ではある程度の短い間隔でリクエストが続く場合「ホットスタート」といって同一のインスタンスが処理を担い続けます。Lambda に関しては「ウォームスタート」の方が一般的かもしれません。

この1つの Lambda の単位で CloudWatch のログストリームも1つ分として構成されるのが基本ルールっぽいですし、何かと意識するタイミングは多いです。

実行速度など主にパフォーマンスの観点で語られることが多いですが、同一プロセス内で動作するような処理のためにグローバルで定義した変数は共有されてしまうということがあるみたいです。

以下のようなコードを書いてしまったときにたまたま気が付きました。

from datetime import datetime

now = datetime.now()

def lambda_handler(event, context):
    # do something

AWS 側が用意するログのタイムスタンプとdatetime.now()した時刻が全くもって合わないので「もしや?」と思えました。ちょうど今始めて同じ内容でググってみたのですが、他にも全く同じパターンで気づいた方が多いみたいです(やっぱり現在時刻を冒頭に脳死で初期化するということ自体に問題を感じた…)。

ちなみに「グローバル」と言っているのはlambda_handler()の外かどうか、と同義です。

なので対策としては「ロジックで使うような変数は全てメイン関数の中で宣言しましょう」ということになります。

from datetime import datetime

def lambda_handler(event, context):
    now = datetime.now()

    # do something

ただこれを裏返して言うと、DB とのコネクションや AWS SDK のセッションなど、パフォーマンス的に積極的に使いまわしたいものはグローバルで宣言した方がいいということになりますね。

RDS を使うときのパフォーマンス測定でコネクションを共有するかどうかで実行時間の差をテストしたことがあるのですが、2回目以降は劇的に早くなります。当然コールドスタート時(ある程度前回からのリクエストから時間が空いたとき)だけは初動が遅くなってしまいますが、全体論で考えたらほとんどのユーザーの体感速度を上げられるのでプラスしかありません。やろう。

Comments

タイトルとURLをコピーしました