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