サーバレスとAWS Lambdaについてまとめてみた

# はじめに
このブログはサーバレスとAWS　Lambaについて自身が学習した内容のまとめ記事となります。
自身が理解しやすいように平易な表現を使って構成しているため、著しく正確性に欠ける情報がありましたらご指摘いただけると筆者は大変喜びます。


# サーバレスについて
釈迦に説法かもですが、Lambdaを理解する前にサーバレスについて大きくまとめました。
サーバレスという言葉で調べると「Google Cloud Functions」や「Azure Functions」など各社類似したサービスや説明がありますが、本記事では「AWSにおける」を枕詞として読み進めてください。


## サーバレスとは
アプリ開発者がサーバーを意識せずにアプリを開発・運用できることを指します。
サーバレスでは、サーバーの構築・保守・負荷対策までをサーバーレスの提供会社が担います。実際にはサーバ自体は存在するため、サーバレスという言葉は「アプリ開発者」目線に立った表現という理解でいるとわかりやすいと思います。


## 従来通りサーバを所有すると
通常アプリの開発・運用にはサーバを用意し、必要に応じたOSやミドルウェアをインストールし、その上でアプリを開発、稼働させます。AWSではEC2がその代表になるかと思います。そのため開発、運用時の管理対象には、アプリそのもの以外にサーバやミドルウェアに対しても開発、保守を施します。
上記に関連して少なくとも、以下は実装前には決めておく必要があるかと思います。
- サーバのセットアップ
  - OS、ミドルウェア
- キャパシティやスケーラビリティ管理
  - リクエスト量などの見積り、プランニング
- 耐障害性を確保するための冗長化
- セキュリティパッチの適用

例え綿密な計画をたて無事にアプリをリリースし本番稼働したとしても、SNS等のメディアにより当初想定していた非機能要件から大きく逸脱することによる緊急メンテナンスなどで作業時間を奪われ、本質な価値提供となるビジネスロジックの開発に集中できないことがあります。

このことについてAWSでは
「Undifferentiated Heavy Lifting （差別化に繋がらない重労働）」
と呼び、課題定義をしています。

:::note warn
もちろん差別化につながるインフラの取り組みもあると思っています
:::


## サーバレスの特徴
上記のような課題に対して以下のような特徴から、サーバレスでの開発を行うことによって多くの課題に対して一定の課題解決が見込まれることがわかります。

- プロビジョニングや管理不要
    - サーバのプロビジョニング、インフラのキャパシティプランニングが不要
    - セキュリティパッチ適用といった保守作業が不要
- 自動でスケール
    - リクエスト数で自動的に起動数が変動する
    - スケーリングに基本的な上限はない(アカウント単位で許可される数は決まっている)
- 価値に対する支払い
    - 事前の必要コストは存在しない
    - リクエスト数と処理実行時間に対してのみ課金
    - 新規事業、スタートアップ等の不透明で初期投資を抑えたいシーンに特に適している
- 高可用かつ安全
    - ハードウェアレベルでの冗長化を気にしなくて良い
    - メンテナンス時間や定期的なダウンタイムは存在しない


# Lambdaとは
> サーバーやクラスターについて検討することなくコードを実行
AWS Lambda は、サーバーレスでイベント駆動型のコンピューティングサービスであり、サーバーのプロビジョニングや管理をすることなく、事実上あらゆるタイプのアプリケーションやバックエンドサービスのコードを実行することができます。200 以上の AWS のサービスやサービス型ソフトウェア (SaaS) アプリケーションから Lambda をトリガーすることができ、使用した分だけお支払いいただきます。

[公式引用](https://aws.amazon.com/jp/lambda/)

AWSで利用できるサーバレスのFaaS(Function as a Service)です。
イベント駆動型なのでLambda単体では意味をなさなく、複数のAWSサービスとつなぎ合わせることで様々なソリューションを提供します。これは各役割が疎結合になることから、個人的にはかなり好いています。

よくLamdbaやLambaとタイポしたくなるのは私だけ？


## Lambdaの正体
最終的には「Amazon Linux」または「Amazon Linux2」サーバが動作し、その上で各ランタイムが動作しています。Linuxのため「/tmp」などの一時ディスク領域や環境変数、動的IPによるインターネット通信も利用可能です。
ランタイムで実行する開発言語も「Node.js、Python、Java、.NET、Go、Ruby」とメジャーな言語はサポートされています。
残念ながら「PHP」には門戸を閉じているため、もし使いたい場合は「カスタムランタイム」という方法を用いて実装する必要があります。（いずれメジャーサポートされることを願っています）

[公式](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html)

このLinuxの実行環境をベースに、各イベントから呼び出された関数を実行しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737072/86af3d13-017f-1648-fb3c-fa9c295db790.png)
[公式](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtimes-extensions-api.html)

図の通り「Lambda Service」に登録したそれぞれの関数は直接実行されるわけではなく、実行時にはLambdaが「Execution Environment」を作成し「Runtime API」を経由して登録した関数を実行します。
このExecution Environmentは登録した関数単位で作成されます。この仕組みのおかげでそれぞれの関数が独立し、安全に実行されます。


## ライフサイクル
公式図で紹介されている通り、大きく、Init・Invoke・Shutdownの３つのフェーズがあります。基本的にこのサイクルを繰り返して処理を実行し続けます。
ここではLambda関数が呼び出されたことを想定し、各フェーズの役割を大まかに説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737072/05239b4d-29a5-4d1f-9ce5-10b76c9dabdd.png)
[公式](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html#runtimes-lifecycle)
Lambda関数が呼ばれるとまず「Initフェーズ」で「Execution Environment」を作成し関数実行のための準備をします。
その後「Invokeフェーズ」で実際の関数を実行します。ここでLambdaはInvokeフェーズが終わってもすぐに「Execution Environment」を破棄するのではなく、次回同じ関数が呼び出された際にInitフェーズをスキップして関数をすぐに実行できるように一定時間保持し続けます。
一定時間経過しても呼び出されない場合は「Shutdownフェーズ」で「Execution Environment」を破棄します。


## Lambdaで出来ること
基本的にLambdaはイベント駆動型なので、各AWSリソース（イベントソース）から呼ばれることを前提としています。(草食系男子と一緒ですね)

よく使われるサービスとしては以下が挙げられます。
S3、SES、DynamoDB、CloudWatch Events、API Gateway

例えば以下のようなよくあるユースケースも、Lambdaと他サービスで実現可能です。
- 画像ファイルがS3に置かれたら債務ネイル用画像をリサイズしてS3に再格納する
- メールが届いたら自動返信する
- ○分経過したら指定した処理を実行する
- HTTPリクエストが来たらJSON形式で返却する

ここではサムネイル画像を作るアーキテクチャをAWS公式サイトから引用紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737072/08403563-fa2a-d3bb-9c72-cf42041cc880.png)
[公式チュートリアル](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-s3-example.html)を一通りやるとより理解できると思います。

## 利用にあたっての注意点
すでに紹介した通り、Lambdaを用いて実装することによりサーバレスの様々な恩恵を享受できますが、技術的特徴を理解していないと、思わぬところで落とし穴に引っかかる可能性もあります。
以下は特に知っておくべき内容となります。
注意点として
- パフォーマンスについて
    - ライフサイクルのInitフェーズの有無により実行時間が大きくぶれる可能性がある
        - プロビジョニング機能で回避可能だがコスト高になる
- 実行時間あたりの課金額
    - メモリ量が大きいほど実行時間あたりの課金額が増える
        - メモリとCPUの性能は連動しているので仕方ない場合もある
    - 過剰なタイムアウト時間の設定は無限ループ時に致命傷となる場合がある
        - 最大で15分の設定が可能
- プログラミング時の特性
    - 前回実行したデータが残っている可能性がある
        - 例えば「/tmp」にファイル書き出しの処理の場合、前回の処理で書き出したファイルが残っている場合があり、常に空の状態を想定した処理ではエラーになる可能性がある
    - イベントの数だけ同時実行される
        - 例えばS3をイベントソースとしたファイル操作の処理をする場合、１０個ファイルが置かれたら、10個Lambdaが並列起動しても良いようなプログラムにする必要がある
- IAMロール権限
    - 必要以上の権限をLambdaに与えないようにする
        - 開発時に付与したAdministorator権限をそのままにしない
- 技術格差が出やすく、エンジニア採用に苦しむ
    - Lambda特有の作法を理解する学習コストが必要
        - WEBシステムとして作る場合はさらに周辺技術（Chalice・SAM）の習得も必要


# 最後に
本記事ではLambdaのポジショントークとならないように意識して書いたつもりですが、私はインフラエンジニアではないことから、餅は餅屋に依頼できるLambdaには少なからず好印象をもっています。
ただ気をつけなければいけない側面も多分にあるため、何でもかんでもサーバレスにするようなバイアスはもたず、アプリケーション設計の選択肢の一つとして考えるようにしたいなと改めて思いました。
また、記事執筆にあたってAWSについて深く理解したい際は、やっぱり公式ドキュメントを読み込む必要性があるなと感じました。