SlideShare a Scribd company logo
Serverless Anti-Patterns
Keisuke Nishitani (@Keisuke69)
Amazon Web Services Japan K.K.
Mar 09, 2017
Photo via VisualHunt.com
Profile
Keisuke Nishitani
Specialist Solutions Architect, Serverless
Amazon Web Service Japan K.K
@Keisuke69 Keisuke69
✤ RESTおじさん
✤ 餃⼦の王将エヴァンジェリスト(⾃称)
✤ ⾳楽が好きです、フジロッカーです、今年も⾏きます
✤ ブログ: http://keisuke69.hatenablog.jp/
Keisuke69 Keisuke69Keisuke69x
What is Serverless?
Serverless = No servers to manage and scale
サーバレスのメリット
✤ サーバレスはバックエンドのアウトソース
⎻ サーバサイドやインフラがわからないフロントエンジニアだけでシステムを実
現することも可能
⎻ バックエンド側のコードとサーバが減るため開発運⽤コストが最⼩化
⎻ ⾃分の書いたコードをすぐ試せる、トライ&エラーが容易
⎻ サービスプロバイダによってマネージされ、スケーラビリティやキャパシティ、
セキュリティの⼼配が不要
⎻ ⾮常にコスト効率化が⾼く、多くの場合コスト減が⾒込める
✤ 開発者がビジネスにフォーカスできる
You donʼt do that, we do that.
アーキテクチャパターン
AWSにおけるアプリケーションの実⾏パターン
✤ Amazon Elastic Compute Cloud (EC2)
✤ Docker + Amazon EC2 Container Service(ECS)
✤ AWS Lambda
AWSのComputeサービス
Amazon EC2 Amazon ECS AWS Lambda
スケールの単位 インスタンス アプリケーション ファンクション
抽象化 ハードウェア OS ランタイム
AWSのComputeサービス
Amazon EC2 Amazon ECS AWS Lambda
スケールの単位 インスタンス アプリケーション ファンクション
抽象化 ハードウェア OS ランタイム
AWSのComputeサービス
Amazon EC2 Amazon ECS AWS Lambda
スケールの単位 インスタンス アプリケーション ファンクション
抽象化 ハードウェア OS ランタイム
AWSのComputeサービス
Amazon EC2 Amazon ECS AWS Lambda
スケールの単位 インスタンス アプリケーション ファンクション
抽象化 ハードウェア OS ランタイム
すべてのデベロッパーをハッピーに
AWS Lambda
⾼いコスト効率インフラ管理不要
使った分だけ100ms単位で課⾦
⾃分のコードを実⾏
標準的な⾔語のコードを実⾏ビジネスロジックにフォーカス
サーバレスなアプリケーションモデル
イベントソース ファンクション サービスなど
Java
C#
Node.js
Python
λ
イベント
S3にオブジェクトが作られる
Kinesisにストリームデータが保存される
HTTPSによるリクエスト
etc...
Amazon S3 Amazon
DynamoDB
Amazon
Kinesis
AWS
CloudFormation
AWS
CloudTrail
Amazon
CloudWatch
Amazon SNSAmazon
SES
Amazon
API Gateway
Amazon
Cognito
AWS
IoT
Amazon
Alexa
Cron events
DATA	STORES ENDPOINTS
REPOSITORIES EVENT/MESSAGE	SERVICES
AWS Lambdaと連携するイベントソース
Amazon
Config
Amazon
Aurora
AWS Lambdaのユースケース
Data Processing Control SystemsBackends
AWS Lambdaを利⽤する場合のユースケース
データの変更、システム状態の遷移もしくはユーザによ
るアクションといったものに対応したコードの実⾏
レスポンスのカスタマイズとAWS内の状態やデータ変更
に対するワークフローのレスポンス
Web、モバイル、IoTや外部APIへのリクエストを扱う
バックエンドロジックの実⾏
Data Processing
Backends
Control Systems
Real-time File Processing
✤ イメージのサムネイル⽣成やビデオの変換
✤ ドキュメントのメタデータをインデックス化
✤ ログの処理
✤ メディアコンテンツのバリデーション
元画像 サムネイル画
像
1 3
1.ファイルストレージを
提供するAmazon S3
2.処理ロジックを提供す
るAWS Lambda
Real-time Stream Processing
✤ クライアントのアクティビティトラッキング
✤ クリックストリーム分析
✤ データクレンジング
✤ ログフィルタリング
✤ インデクシング
✤ デバイスデータのテレメトリと測定
AWS	LambdaAmazon	Kinesis
集計処理
リアルタイム
Cloudwatch logsやSNSなど
との連携も可能
⼀般的な3-tier Webアプリ
プレゼンテーション層 ロジック層 データストア層
Webサーバ/アプリサーバブラウザ/モバイル データベース
Traditional Web Backend
AP
(EC2)
DB
(RDS)
LB
(ELB)
Web
(EC2)
Static Contents
(S3)
ブラウザ/モバイル CDN
(CloudFront)
Traditional Web Backend
✤ メリット
⎻ 実績が多く枯れた構成
⎻ カスタマイズ性が⾼い
⎻ 知⾒を持っている⼈が多い
✤ デメリット
⎻ サーバのスペック、台数などスケールを意識して設計する必要がある
⎻ サーバの運⽤は利⽤者が負う必要がある
⎻ アイドル時にもコストが発⽣する
Serverless Web Backend
ブラウザ/モバイル API Gateway AWS Lambda DynamoDB etc
S3CloudFront
AWSによるマネージ
(フルマネージド)
Serverless Web Backend
✤ メリット
⎻ クライアント側の実装は従来とあまり変わらずノウハウを活かせる
⎻ サーバの運⽤、スケールはAWSに⼀任できる
⎻ サービスの組み合わせだけで、セキュアなAPIアクセス制御などが実装できる
⎻ コスト効率が⾼い
✤ デメリット
⎻ カスタマイズ性が低い
⎻ 設計および運⽤ノウハウが枯れていない
Amazon API Gateway
統⼀化されたAPIの作成と管理
APIの定義とホスティング
クラウド上のリソースへの
アクセス認証
AWSのAuthを活⽤
バックエンド保護のための
DDoS対策やスロットリング
ネットワークトラフィックの管理
AWSのサーバレスオファリング
AWS LambdaAmazon API Gateway
Amazon DynamoDB
Amazon Kinesis Amazon Mobile Analytics
Amazon SNS
Amazon Cognito
AWS IoT
Amazon S3 Amazon Elastic Transcoder
AWS CloudWatch
AWS CloudTrail
Amazon SESAmazon Machine Learning
Amazon Route53Amazon SQS
アンチパターン
アンチパターン①
LambdaでRDBMS使いがち問題
LambdaでRDBMS使いがち問題
✤ Lambda + RDBMSがアンチパターンな理由
⎻ コネクション数の問題
⎻ Lambdaはステートレスなプラットフォームであるため、コネクションプールの実装は難しい
⎻ Lambdaがスケールする、つまりファンクションのコンテナが⼤量に⽣成された場合に、各コン
テナからDBへコネクションが張られることになり、耐えられないケースがある
⎻ VPCコールドスタートの問題
⎻ VPCのコールドスタートが発⽣する場合、通常のコールドスタートに⽐べて10秒程度の時間を
必要とする
✤ ベストプラクティス
⎻ DynamoDBを使う
⎻ 何らかの理由でRDBMSとの連携が必要な場合はDynamoDB StreamsとLambdaを利⽤
して⾮同期にする
アンチパターン②
メモリやたら少ない問題
メモリやたら少ない問題
✤ メモリ設定
⎻ 設定値としてはメモリとなっているが実際はコンピューティングリソース全体
の設定
⎻ メモリサイズと⽐例してCPU能⼒も割り当てられる
⎻ メモリ設定はパフォーマンス設定と同義
⎻ コストを気にしがちだが、メモリを増やすことで処理時間がガクンと減り、結
果的にコストはそれほど変わらずとも性能があがることもある
✤ ベストプラクティス
⎻ 最⼩から少しずつ調整し、変更しても性能が変わらない値が最適値
アンチパターン③
同期実⾏にこだわりすぎ問題
同期実⾏にこだわりすぎ問題
✤ 同期でInvokeすると同時実⾏数の制限に引っかかってつまりがち
⎻ 同時実⾏数の計算は「1 秒あたりのイベント数 * 関数の実⾏時間」
⎻ ⾮同期呼び出しの場合、許可された同時実⾏数内で順次処理をし、バーストも許容さ
れている
⎻ 同期呼び出しの場合、許可された同時実⾏数を超えた時点でエラーが返されてしまう
⎻ 同時実⾏数は制限緩和可能だが、実際にスロットルされていない状態でいきなり申請
しても基本的に通らない
✤ ベストプラクティス
⎻ できるだけ⾮同期でInvokeするのがオススメ
⎻ その処理、本当にレスポンス必要ですか?
⎻ 特にAPI Gatewayとの組み合わせの場合、PUT系の処理をGatewayのバックエンドと
してLambdaで直接処理するのではなく、サービスプロキシとして構成してSQS、
Kinesisに流すなどする
アンチパターン④
サーバレスに夢⾒がち問題
サーバレスに夢⾒がち問題
✤ サーバレスであれば全く運⽤が必要ない、インフラ費⽤が10分の1に
なる
⎻ サーバの管理は不要だが運⽤は必要
⎻ コスト効率が⾼いため、サーバを並べて同様のことを実装するよりは安くなる
可能性が⾼いが、リクエスト数が多い場合などはそれなりの費⽤になる
⎻ インフラ費⽤だけでなく、トータルコストで考える必要がある
⎻ 複雑なことをやろうとすると、設計・開発コストがあがる可能性も⼤きい
✤ シンプルに使うべきものはシンプルに使いましょう
アンチパターン⑤
サーバレスで難しいことしがち問題
サーバレスで難しいことしがち問題
✤ サーバレスはシンプルに使ったほうが効果は⾼い
⎻ 基本は「Aが発⽣したら処理をしてBにアウトプット」
⎻ シンプルに使うべきものを複雑な箇所に適⽤しようとすると難易度は上がる
⎻ 分散環境の考慮、失敗時のリトライなど
サーバレスで難しいことしがち問題
✤ サーバレスはシンプルに使ったほうが効果は⾼い
⎻ 基本は「Aが発⽣したら処理をしてBにアウトプット」
⎻ シンプルに使うべきものを複雑な箇所に適⽤しようとすると難易度は上がる
⎻ 分散環境の考慮、失敗時のリトライなど
✤ サーバレス以外と同じこと
⎻ 標準的なプログラミング⾔語とプロトコル
⎻ 標準的なデプロイとテストのプラクティス
サーバレスで難しいことしがち問題
✤ サーバレスはシンプルに使ったほうが効果は⾼い
⎻ 基本は「Aが発⽣したら処理をしてBにアウトプット」
⎻ シンプルに使うべきものを複雑な箇所に適⽤しようとすると難易度は上がる
⎻ 分散環境の考慮、失敗時のリトライなど
✤ サーバレス以外と同じこと
⎻ 標準的なプログラミング⾔語とプロトコル
⎻ 標準的なデプロイとテストのプラクティス
✤ サーバレス特有のこと
⎻ イベント/リクエストドリブン
⎻ モジュラー
⎻ ステートレス
⎻ 12 factor/Microservices/Reactive..
サーバレスで難しいことしがち問題
✤ サーバレスはシンプルに使ったほうが効果は⾼い
⎻ 基本は「Aが発⽣したら処理をしてBにアウトプット」
⎻ シンプルに使うべきものを複雑な箇所に適⽤しようとすると難易度は上がる
⎻ 分散環境の考慮、失敗時のリトライなど
✤ サーバレス以外と同じこと
⎻ 標準的なプログラミング⾔語とプロトコル
⎻ 標準的なデプロイとテストのプラクティス
✤ サーバレス特有のこと
⎻ イベント/リクエストドリブン
⎻ モジュラー
⎻ ステートレス
⎻ 12 factor/Microservices/Reactive..
✤ つまり
⎻ モノリスは分解する必要がある
⎻ ファンクションのコミュニケーションをどうするか考え、サービス境界をクリアにする必要がある
⎻ 障害発⽣を前提とした設計の必要性、結果整合性の理解が必要
サーバレスで難しいことしがち問題
✤ サーバレスはシンプルに使ったほうが効果は⾼い
⎻ 基本は「Aが発⽣したら処理をしてBにアウトプット」
⎻ シンプルに使うべきものを複雑な箇所に適⽤しようとすると難易度は上がる
⎻ 分散環境の考慮、失敗時のリトライなど
✤ サーバレス以外と同じこと
⎻ 標準的なプログラミング⾔語とプロトコル
⎻ 標準的なデプロイとテストのプラクティス
✤ サーバレス特有のこと
⎻ イベント/リクエストドリブン
⎻ モジュラー
⎻ ステートレス
⎻ 12 factor/Microservices/Reactive..
✤ つまり
⎻ モノリスは分解する必要がある
⎻ ファンクションのコミュニケーションをどうするか考え、サービス境界をクリアにする必要がある
⎻ 障害発⽣を前提とした設計の必要性、結果整合性の理解が必要
✤ したがって
⎻ シンプルに使うべきものはシンプルに使いましょう
⎻ フルサーバレスにこだわらず、コンテナなども使って適材適所で
アンチパターン⑥
何となくVPC使いがち問題
何となくVPC使いがち問題
✤ VPCは必須でない。必要でない限り使⽤しない
⎻ 使うのはVPC内のリソースにどうしてもアクセスする必要があるときだけ
⎻ VPCアクセスを有効にしているとコールドスタート時に10秒から30秒程度余計
に必要になる
✤ ベストプラクティス
⎻ 同期実⾏が必要な箇所やコールドスタートを許容できない箇所ではなるだけ使
わない
⎻ VPC内のリソースとの通信が必要なのであれば⾮同期にする
⎻ RDBMSのデータ同期が必要なのであればDynamoDB StreamsとLambdaを使って⾮同期に
アンチパターン⑦
Limit Increase通らない問題
Limit Increase通らない問題
✤ イベントソースがAmazon Kinesis / DynamoDBの場合、シャード数と等しくなる
⎻ ストリームのシャードごとに同時に実⾏されるため
⎻ 例:100シャードのAmazon Kinesis ストリームの場合、同時実⾏数はどの時点でも最⼤ 100 件。
そのうちアクティブなシャードが10個だった場合、実際の同時実⾏数は10となる。
✤ それ以外は、(1 秒あたりのイベント数 * 関数の実⾏時間)となる。たとえば、
関数が 1 秒あたりのイベント数が10 件で平均実⾏数が3秒の場合、同時実⾏数は
30となる
1s 2s 3s 4s 5s
10 req/sec
Avg 3s / exec
“同時”に実⾏されているタイミング
Limit Increase通らない問題
✤ 標準では100、実績がない状態でいきなり数千とか数万を申請しても
通らない
⎻ 実際にThrottleされているかどうかの確認を
⎻ Throttleされているかなどはメトリクスで確認可能
✤ Limit Increaseしても性能上のボトルネックは解消しないこともある
⎻ ストリーム系の場合、シャード数を増やしたりバッチサイズを調整したり
⎻ そもそもファンクションの実⾏に時間がかかっている場合、レイテンシは改善
しない
アンチパターン⑧
コールドスタート気にしすぎ問題
コールドスタート気にしすぎ問題
✤ 安定的にトラフィックが発⽣している場合、コールドスタートの発⽣
頻度は多くない
⎻ コールドスタートによる遅延が⼀切許容できないのであればそもそもLambda
をやめることも検討を
⎻ コールドスタートの時間は⾔語の特性と⼤きく関連する
✤ コールドスタートは⼀年前とくらべて半分くらいの時間になっている
⎻ そもそも、基本的にこの領域はお客様でできることは少ない
✤ それでも気になるなら、コールドスタートを頑張って速くするしかな
い
コールドスタートを速くする
コールドスタートを速くする
✤ Lambdaファンクションに対してPingする
⎻ 定期的にInvokeを⾏うことでコンテナが破棄されることを回避する
⎻ 5分間隔程度がオススメ
⎻ API Gatewayを利⽤している場合は該当のAPIへリクエスト
⎻ それ以外は必要な数だけ⾮同期でInvokeする
✤ コンピューティングリソースを増やす
⎻ メモリ設定
⎻ コンピューティングリソースの割当を増やすことで初期化処理⾃体も速くなる
✤ ランタイムを変える
⎻ JVMの起動は遅い
⎻ ただし、⼀度温まるとコンパイル⾔語のほうが速い傾向
コールドスタートを速くする
✤ VPCを使わない
⎻ そもそもLambdaと関係なくENIの⽣成とアタッチ処理は遅い
⎻ コールドスタートを速くしたいならデータストアはDynamoDBが鉄則
⎻ DBの問題でどうしてもVPCを利⽤したい場合はDynamoDB Streamsを利⽤した⾮同期反映を
検討する
✤ パッケージサイズを⼩さくする
⎻ サイズが⼤きくなるとコールドスタート時のコードのロードおよびZipの展開に時間がかかる
⎻ 不要なコードは減らす
⎻ 依存関係を減らす
⎻ 不要なモジュールは含めない
⎻ 特にJavaは肥⼤しがち
⎻ JavaだとProGuardなどのコード最適化ツールを使って減らすという⼿もある
⎻ 他の⾔語でも同様のものはある
コールドスタートを速くする
✤ Javaの場合だけ
⎻ POJOではなくバイトストリームを使う
⎻ 内部で利⽤するJSONシリアライゼーションライブラリは多少時間がかかるので、バイトス
トリームにしてより軽量なJSONライブラリを使ったり最適化することも可能
⎻ https://github.com/FasterXML/jackson-jr
⎻ http://docs.aws.amazon.com/lambda/latest/dg/java-handler-io-type-stream.html
⎻ 匿名クラスをリプレースするようなJava8の機能を利⽤しない(lambda、メソ
ッド参照、コンストラクタ参照など)
コールドスタートを速くする
✤ 初期化処理をハンドラ外に書くとコールドスタートが遅くなるので遅
延ロードを⾏う
import boto3
client = None
def my_handler(event, context):
global client
if not client:
client = boto3.client("s3")
# process
アンチパターン⑨
IP固定したがり問題
IP固定したがり問題
✤ API GatewayやLambdaから別システムや外部APIにアクセスする際のソー
スIPアドレスを固定したい
✤ 実は⽇本固有の事情だったりする
⎻ IPを固定すること⾃体はセキュリティでもなんでもない
⎻ 署名や証明書などで担保すべき
⎻ IPアドレスを固定するということはスケーラビリティを捨てることにもつながる
✤ LambdaではVPCを利⽤してNATインスタンスを使うという⽅法もなくはな
いが…
⎻ VPCのコールドスタート問題
⎻ ⾃前のNATインスタンスの場合、その可⽤性、信頼性、スケーラビリティを考慮する
必要がある
アンチパターン⑩
監視しなくていいと思ってる問題
監視しなくていいと思ってる問題
✤ Serverless != Monitorless
✤ 処理の異常を検知して対応するのはユーザの仕事
⎻ 適切にログ出⼒を⾏い、適切にモニタする
✤ ベストプラクティス
⎻ CloudWatchのメトリクスを利⽤(Errors, Throttles)
⎻ CloudWatch Logsへのログ出⼒とアラーム設定
アンチパターン⑫
信⽤しすぎ問題
信⽤しすぎ問題
✤ Lambdaと⾔えど通常の他のサービスと同様に障害発⽣を前提として
実装をする
⎻ リトライ
⎻ Dead Letter Queueの活⽤(⾮同期の場合)
✤ 冪等性はお客様のコードで確保する必要がある
⎻ AWS Lambdaで保証しているのは最低1回実⾏することであり1回しか実⾏しな
いことではない
⎻ 同⼀イベントで同⼀Lambdaファンクションが2回起動されることがまれに発⽣
する
⎻ DynamoDBを利⽤するなどして冪等性を担保する実装を⾏うこと
その他、今となっては不要なこと
今となっては不要なこと
✤ Descriptionにパラメータを保管する
⎻ 環境変数を利⽤すること
✤ ファンクションのネストや連鎖的な呼び出し
⎻ Step Functionsを使う
最後にもうひとつ
ローカルでテストをしたい
Lambdaのランタイムをエミュレートする
✤ Lambdaでは各ランタイムごとで使われているAMIを公開している
⎻ Amazon Linuxを利⽤
⎻ 使っているランタイムのバージョンも公開している
⎻ 内部的には標準的なコンテナ技術を使っている
✤ ファンクションといってもただのプログラムなのでローカル環境でも
容易に実⾏できる
⎻ ハンドラを呼び出すテストドライバを書くだけ
⎻ Contextとイベントをエミュレーションする必要があるが、単に必要な値を⼊
れたオブジェクトを⽤意するだけいい
⎻ イベントのサンプルは公開されている
テストドライバ例
import json
import lambda_function
f = open(“event.json”)
event = json.load(f)
f.close()
context = "”
lambda_function.lambda_handler(event,context)
テストドライバ例
import json
import lambda_function
f = open(“event.json”)
event = json.load(f)
f.close()
context = "”
lambda_function.lambda_handler(event,context)
イベントを静的ファイルとして⽤意しておき、ロード
<= 必要に応じて設定する(今回は空)
<= ファンクションの実⾏
テストドライバ例
def lambda_handler(event, context):
#Do something
if __name__ == "__main__":
f = open("event.json")
event = json.load(f)
f.close()
context = ""
lambda_handler(event,context)
• Pythonの場合以下のようにすることでも可能。Javaも同様にPublicなmainメ
ソッドを定義して内部で呼び出すことも可能
もしくは
✤ Serverlessのようなローカルテスト機能をもったサードパーティ製フ
レームワークを利⽤する
✤ 各ランタイム⽤のOSSなテストツールを利⽤する
lambda-local on npm
python-lambda-local on pip
aws-lambda-local-runner on maven
もしくは
✤ Serverlessのようなローカルテスト機能をもったサードパーティ製フ
レームワークを利⽤する
✤ 各ランタイム⽤のOSSなテストツールを利⽤する
lambda-local on npm
python-lambda-local on pip
aws-lambda-local-runner on maven
個⼈的なオススメは⾃分でテ
スト⽤のドライバを書くか、
ローカルテストツールを利⽤
まとめ
✤ アンチパターンはなるべく避ける
✤ ただし、絶対悪ではない。いろんな事情で仕⽅ない場合もある
⎻ 外部APIがIP固定を要求しているとか
✤ できるだけ避けることを考えつつ、適当なところで⼿を打つのがいい
Serverless Anti-Patterns

More Related Content

Serverless Anti-Patterns