"時間の流れ"
という無限リストを扱う
AWS Lambda
JAWS-UG 千葉支部 Vol.5

∼秋のAWS Lambda & API Gateway 祭り!!∼
2015-09-08
クラスメソッド株式会社
都元ダイスケ
自己紹介
✦ よく訓練されたアップル信者、都元です。
✦ Webアプリ屋出身のAWS屋
✦ Javaやってます
✦ AWS歴約4年(since 2011夏)
✦ Twitter @daisuke_m
✦ 人間CloudFormer
✦ 自動デプロイ芸人
今日は
✦ 秋のAWS Lambda & API Gateway 祭り!!
✦ ただし、本セッションはAPI Gateway成分ゼロです。
✦ Lambdaのみでがんばります。
✦ Lambdaが出てくるのも遅くぁwせdrftgyふじこ
バッチ処理
✦ リアルタイム処理の対義語。
✦ ここでは、HTTPリクエストに応答するための
処理以外のもの。
✦ 例えばこんなお仕事を担う。
✦ 毎週/毎日、通知のメールを送りたい。
✦ 毎月、締め処理のバッチを走らせたい。
都元の問題提起編
AWS上に、HAでスケーラブルな
バッチサーバを構成してください。
冗長バッチサーバ問題
定期バッチの課題
✦ 障害等で発火できなかったトリガはどうする?
✦ 毎分発火すべきトリガで、0:31までは発火でき
ていた。今、息を吹き返したのが0:33.30。
✦ 0:32と0:33、発火漏れ。
戦略
✦ 何事もなかったように、0:34から再開。
✦ 即座に2回発火し、0:34からは予定通り。
✦ 何度撃ち漏らしていても、即座に1回だけ発火し、
0:34からは予定通り。
✦ etc.
一方AWSは
✦ Design for failure (障害を見越した設計)
✦ EC2インスタンス単品での可用性を担保しよう
としない。
✦ 言い換えると、高可用性(HA)を要求するシステ
ムに対しては、Multi-AZを要求する。
✦ Multi-AZ分散すると、スケーラビリティも。
cronバッチサーバ
✦ 可用性のために2台冗長でバッチサーバを構築。
✦ 2回発火してくれてベンリでオトク!?
✦ バッチ処理が増えたので4台にスケール。
✦ 4サーバで同じ処理を並走してくれるので、

1台当たりの稼働率は変わらないのでオトク!?
バッチサーバの責務を分割
✦ ジョブスケジューラ (JS)
✦ 規定されたリズムに従ってトリガを発火
✦ 発火した結果、何が行われるかは関知しない
✦ ジョブワーカー (JW)
✦ 発火したトリガを受けて、処理を実行
✦ トリガが発火した理由には関知しない
改めてHAとスケーラビリティ
✦ JWのMulti-AZ化は簡単。
✦ SQSを使ったProducer / Consumerパターン
✦ クセモノはJS側だった。
都元の解答編
Solution 1 - Brian
✦ トリガのCRUDを担う
RESTful API
✦ 複数台で冗長化
✦ 多重発火防止はDBを仲介した
セマフォで実現
✦ トリガに従って、SNSトピッ
クにメッセージを投げるだけ。
Brianの実装と問題点
✦ QuartzというJava製OSSジョブスケジューラ。
✦ 複雑だが高機能なので、そこそこ実装は楽。
✦ RDBを利用したセマフォ(クラスタ機能)
✦ 複雑で、RDBからDynamoDBに差し替える等は困難
✦ misfire instruction機能
✦ RDSのfailoverによる可用性の低下がある。
✦ JSに2台、JWに2台。金のバカ食い。
✦ cron + sh-scriptであれば1台で済んでたのに。
Solution 2 - Jimmy
✦ トリガは毎秒で固定
✦ 複数台で冗長化
✦ 多重発火防止はDynamoDBを
仲介したセマフォで実現
✦ トリガに従って、SNSトピッ
クにメッセージを投げるだけ。
Jimmyが吐くメッセージ
{

"timestamp": 1438825770,

"firedTimestamp": 1438825770,

"recovery": false,

"version": "0.1-SNAPSHOT"

}
Jimmyの実装と課題
✦ 中身は実はQuartzを利用。(なんだかんだよく出来てる)
✦ ただしクラスタは利用せず、気ままに毎秒発火。
✦ DynamoDBへのConditional Putを利用して、書き込みに
成功したインスタンスにSNSメッセージ送信の権利を。
✦ 全インスタンス(通常2台)でビーチ・フラッグス!
✦ 欲しいのは毎秒じゃない問題。
✦ "0 0 9-18 ? * MON-FRI"
無限リスト
✦ 無限の大きさを持つリスト。
✦ 手続き型プログラミングで考えると、この手の
リストを処理しようとすると無限ループやメモリ
破綻に繋がる。
✦ 関数型プログラミングで考えると、この手のリ
ストは、最終的にfilterかreduceされる。
無限リスト利用例
✦ [0, 1, 2, 3, 4, 5, …] という無限リスト。

これをサイズN個にフィルタしてからloopすると、

N回ループが自在に作れる。
✦ ↑の無限リストに階乗関数(!n)をmapすると

[1, 1, 2, 6, 24, …]
✦ さらに逆数を返す関数(1/n)をmapして

[1/1, 1/1, 1/2, 1/6, 1/24, …]
✦ 全要素の総和を求めると、ネイピア数(e≠2.718)
時の流れという無限リスト
✦ 太古の昔から、永遠の未来までをつなぐリスト
✦ Jimmyは、その要素を1つ1つ取り出して表現
(represent)しているだけです。
✦ と考えると、Jimmyのメッセージをフィルター
して、SQSに突っ込めば良いのではないか。
✦ という設計思想でJimmyを作ってみました。
ああ、やっと
Lambdaが出てきた
こうだったらいいのにな
✦ パラメータをコンストラクタで受け取って汎用化
✦ 1つのコードパッケージで複数のLambdaを展開
Lambdaに要望
✦ デプロイパラメータを指定できるようにしてくだ
さい。
✦ できればそのパラメータはcontextから読めると
いいです。
小細工チャレンジ (1)
✦ Lambda Functionにタグがあれば…。
✦ GetFunctionとか呼び出してタグの情報をパラ
メータとして利用できるのではないか?
Functionにタグ無かったwww
っうぇwwwっうぇww
小細工チャレンジ (2)
$ aws lambda get-function-configuration --function-name
jimmy
{
"FunctionName": "jimmy",
"CodeSize": 8283395,
"MemorySize": 128,
"FunctionArn": "arn:aws:lambda:xx:xx:function:jimmy",
"Handler": "JimmyMessageFilterHandler",
"Role": "arn:aws:iam::xxxx:role/lambda-poweruser",
"Timeout": 60,
"LastModified": "2015-08-21T01:52:15.348+0000",
"Runtime": "java8",
"Description": "0 0 9-18 ? * MON-FRI"
}
"Description": "0 0 9-18 ? * MON-FRI"
アッー!
という不幸な事件を
起こさないためにも
なにとぞ。

20150908 ”時間の流れ” という無限リストを扱うAWS Lambda