🛠️

AWS Lambdaをなんとなく使っているときに陥りがちなミスとか

2022/06/09に公開

私自身がAWS Lambdaをなんとなく使っていた結果、色々と無駄な実装になってしまっていた部分がいくつかあったり、わからないまま使っている部分が多くありましたので、戒めとしてまとめておきます。

使用しているランタイムのEOLに気をつけるべし

LambdaのEOLは基本的にプログラミング言語のEOLに沿っていますが、LambdaのランタイムがEOLになると新規作成ができなくなり、その後1,2ヵ月に更新もできなくなります。
ただ、Python2.7などは言語としては2020年1月にEOLになりましたが、Lambdaのランタイムとしてはその1年半後までEOLにならずに使用できたり、AWS側でEOL後のサポートをしてくれている言語もあります。
世の中にはEOLを度外視してシステム運用をしている企業も多々あると思いますので、そういった企業がLambdaを使用する際にはEOLには細心の注意を払わなければなりません。
ランタイムの非推奨化に関するポリシー - AWS Lambda

Lambdaはarm64アーキテクチャで実行すべし

Lambdaはかつてx86_64の実行環境がありませんでしたが、昨年からarm64のインスタンスが選べるようになっています。
arm64はGraviton2 processorと呼ばれており、x86アーキテクチャのインスタンスよりも高速でかつ安価で実行できるようになっています。選ばない理由は無いのでこれからLambda関数を立ち上げるときはarm64を選びましょう。

ただ、すでにx86で動いているLambda関数についてはarm64に変更することで思わぬ不具合が生じる可能性があるかもしれませんのでお気をつけください(ほぼ無いと思いますが)

他サービス(s3, DynamoDB等)へのアクセスの際はIAM Roleで権限を付与する

これはあたり前のことなのですが、Lambdaからs3やDynamoDBを操作する際にはLambdaの実行ロールにs3やDynamoDB等のサービスへのアクセス権限を付与してあげるのが一般的です。

我々はあろうことかLambdaように新しいIAMユーザを作成し、s3等へのアクセス権限を付与した上でアクセスキーを発行し、プログラム内にアクセスキーを埋め込んでs3等外部サービスへの接続を許可していました。
これをしてしまうといくつかのセキュリティ的なリスクが有りました。

  • プログラム中にアクセスキーが埋め込まれているためLambda関数のパッケージをダウンロードするとアクセスキーが盗み見られる可能性がある。
  • アクセスキーが漏洩したときにはLambda関数を新しいアクセスキーに更新した上で再デプロイが必要になってしまう(IAMアクセスキーの定期的なローテートが必要となる)

ですので、Lambdaで他サービスに接続する際は必ずLambdaの実行ロールに必要なIAM Roleを割り当てて運用しましょう。

コールドスタートとウォームスタートを頭に入れる

AWS LambdaはPython, Node, Ruby, Java, Goなどの言語で実行が可能となっています。
Lambdaは初回呼び出し時や一定期間間が空いた後の呼び出しの際の実行はコールドスタートとなります。

コールドスタートの際は上図のフローに沿って関数を実行するのですが、これはコンパイル型言語(Java, Goなど)のほうが圧倒的に時間がかかります。逆にスクリプト型言語(Python, Node, Ruby等)においては、コールドスタートでもウォームスタートでもさほど実行時間に差はありません(数ミリ秒を争うシステムでは死活問題となりますが)。

どうしても起動が遅くてサービスに影響が出るという自体がとくにコンパイル型言語において起きる可能性があります。
その際は、Lambdaの関数をウォームスタートとして待機させておくプロビジョニングされた同時実行を設定することでレイテンシを向上させることができます(追加料金はかかります)
なお、プロビジョニングを設定していても同時実行数を超えるアクセスが来た場合にはコールドスタートが発生してしまう可能性があるのでご注意ください。

こうして書くと、スクリプト型言語との相性が良く、コンパイル型言語では使用しないほうがいいと思われるかもしれませんが、そんなことはもちろんありません。
一度Lambdaが立ち上がった後はコンパイル型言語のほうが実行速度が早くなりますし、何よりサーバレスの恩恵を受けられるLambdaはコンパイル型言語でも重宝します。

cronなどで定期実行させていても案外コールドスタートに陥る

上記の話の続きで、定期的にLambdaを起動しておけばウォームスタートであり続けるだろうと思うかもしれませんが、案外うまく行きません。
1分に一度関数にアクセスさせるcronを書いてみたのですが、頻繁にコールドスタートになってしまい実行速度がかかってしまう場面がありました。
もしかしたらもっと頻繁に実行させればウォームスタートを阻止することも可能かもしれませんのでみなさんでもお試しいただくのが良いかと思います。

メモリの影響は案外実行時間に影響がある

Lambdaの使用メモリは自由に設定が可能ですが、これは意外と実行速度に影響を与える要因となっています。
パット見メモリ使用量は、実行時使用メモリをもとに決めれば良いものと思うかもしれませんが、そうとも限りません。余分にメモリを設定しておくと実行速度が大幅に向上することが多々あります。
メモリ使用量については試行錯誤して決めるのが良いかと思います。

外部ライブラリはLambda LayersにアップロードしておいてLambda本体の容量を減らす

Lambdaには外部ライブラリの参照先としてLambda Layersというものが存在します。
これは、Pythonであればpipのsite-packages, Nodeであればnode_modules, Javaであればjarファイルなどを事前にアップロードしておくことが可能な仕組みです。
Lambdaのデプロイ時に毎度同じ外部ライブラリをデプロイするのは、デプロイ速度低下による開発スピードの低下や通信コストなどの面でデメリットがあります。
是非積極的にLayersを活用しましょう。

Lambdaは必ず自動デプロイの仕組みを整えよう。

Lambda関数をデプロイする際、個人のユーザのデプロイ用ディレクトリからコマンドを叩いてデプロイする運用をしている場面があったりします。
その際、いくつかの不都合があります。それは個人ユーザのディレクトリに含まれている不要なファイルまでもがLambdaへのデプロイ対象になってしまう点です。それによりLambda関数に不具合が生じてしまう可能性があります。
ですので、Lambda関数は必ず自動デプロイの仕組みを整えておくと良いでしょう。
GitHubを使用しているのであれば、GitHub Actionsを使用して簡単に自動デプロイを実現できます。
ここでは言及をしませんが、検索すると記事がたくさん出てくると思うのでぜひ実現しておきましょう。

LambdaのログをCloudWatchで見るとログが複数に分割されていてよくわからない理由

これは、Lambdaのインスタンスごとのログが出力されているため仕方がありません。
もし、2人のユーザが同時にLambdaにアクセスした場合、2つのインスタンスが立ち上がる可能性が高いです。そうなるとインスタンスが別になっていますのでログも別のものとして出力されています。

まとめ

以上、Lambdaを使うときに忘れられがちな点について記載してみました。
Lambdaは非常に便利なツールですが、何も知らないまま使うと逆に面倒な自体を引き起こす可能性があるツールです。ぜひしっかりと勉強した上でLambdaを使用することをおすすめします。

Discussion