Slide 1

Slide 1 text

サーバーレス アーキテクチャの 数理的理解と分析 #devsumi #devsumiD チェシャ猫 (@y_taka_23) Developers Summit 2023 Summer 27th Jul. 2023

Slide 2

Slide 2 text

Twitter (X) にも投稿よろしく! #devsumi #devsumiD

Slide 3

Slide 3 text

今日お話しすること・しないこと ● 明日からの仕事で役に立ったりはしません ○ How-To の紹介でも設計フレームワークでもない ○ 理論的な計算機科学の入門的内容が中心 ● とはいえ Developer にとって無駄ではない(はず) ○ 普段見るサーバーレス with ガチ理論の面白さ ○ 聞いた後「参考文献読んでみるか」となると嬉しい

Slide 4

Slide 4 text

例:認証用のサーバーレス関数 function auth(req, res) { let (user, pass) = req.body; if (db.get(user) == pass) { res.write(true); } else { res.write(false); } }

Slide 5

Slide 5 text

例:ローカルキャッシュの導入 var cache = new Map(); function auth(req, res) { let (user, pass) = req.body; if (cache.contains(user, pass)) { res.write(true); } else if (db.get(user) == pass) { cache.insert(user, pass); res.write(true); } else { res.write(false); } }

Slide 6

Slide 6 text

DB 上のパスワードが変更されないなら 直感的には正しく動くのでは?

Slide 7

Slide 7 text

AWS Lambda のベストプラクティス ● Take advantage of execution environment reuse ○ SDK や DB コネクションはハンドラ外で初期化 ○ /tmp ディレクトリにキャッシュを保存 ○ ただしセキュリティ情報は保存しないように注意 ● White idempotent code ○ 重複したイベントでも同じように処理されるように https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html

Slide 8

Slide 8 text

サーバーレスの解析困難性 ● 直感的には安全そうだが、どう確認するか ○ 複数の関数が同時に実行されたら? ○ Warm Start でインスタンスが再利用されたら? ○ At-Least-Once により複数回実行されたら? ● 低レベルな「プラットフォームの都合」が露出 ○ 言語の外の話なので Linter 等では役に立たない

Slide 9

Slide 9 text

もっと確実な「裏付け」が欲しい

Slide 10

Slide 10 text

「継続的な発展」に向けて ● サービスの成長に従いアーキテクチャも複雑化する ○ 要件の肥大化やワークアラウンドの追加 ○ 仕様変更、追加時に問題がないことを保証したい ○ 保証が無いと加速度的に手が入れるのが辛くなる ● 人間の理解力や注意力に頼る運用は限界がある ○ 機械的・プログラマブルな記述・判定方法が欲しい

Slide 11

Slide 11 text

理解は全てに先立つ そして、理解とは記述である

Slide 12

Slide 12 text

Formal Foundations of Serverless Computing Jandga A. et al. 2019 https://dl.acm.org/doi/10.1145/3360575

Slide 13

Slide 13 text

本日の解説の流れ ● サーバーレスの動作を厳密に記述したい ● そもそも動作を厳密に記述するとはどういうことか ● 改めて、サーバーレスの動作を厳密に記述する ● 理想化されたサーバーレスの動作はどうあるべきか ● その理想化はどのような条件下で妥当か

Slide 14

Slide 14 text

言語とその意味の定式化 1. Languages and Their Formal Semantics

Slide 15

Slide 15 text

if 0 + 1 < 2 then 3 + (4 + 5) else 6 + 7 = ?

Slide 16

Slide 16 text

言語の定義が与えられていない

Slide 17

Slide 17 text

if 0 + 1 < 2 then 3 + (4 + 5) else 6 + 7 = ?

Slide 18

Slide 18 text

言語の「意味」が与えられていない!

Slide 19

Slide 19 text

言語 = 構文 + 意味論

Slide 20

Slide 20 text

言語の「意味」を定義する方法 ● 実装による定義(かつての Ruby=MRI など) ○ 参照実装を提供:正しさとはその実装との一致 ● 自然言語による定義(C++、Java、ECMAScript など) ○ 仕様書を提供:曖昧性や矛盾の発見は人間の観察力 ● 形式的意味論による定義(Scheme、Standard ML など) ○ 数学的ルールを提供:アルゴリズム的な検証が可能

Slide 21

Slide 21 text

トイ言語のフル仕様 構文 意味論

Slide 22

Slide 22 text

意味論に現れる規則の読み方 ● 便宜上、規則には名前がついていることが多い ● 横線より上は変換に必要な前提 ● 横線より下は前提のもとで可能な変換

Slide 23

Slide 23 text

トイ言語の意味論(1/3) ● 値(真偽値・自然数)は評価しても変わらない ● "e1 + e2" の形の式は、各々の評価値の和に評価される

Slide 24

Slide 24 text

トイ言語の意味論(2/3) ● "e1 < e2" の形の式は、各々の評価値の大小に応じて true または false に評価される

Slide 25

Slide 25 text

トイ言語の意味論(3/3) ● "if e1 then e2 else e3" の形の式は、 e1 の評価値に応じて e2 か e3 の評価値に評価される

Slide 26

Slide 26 text

例:トイ言語の式の評価 ● 部分式に対して規則を適用し、再帰的に計算を行う ● 各ステップでは、複数の部分式を同時に値まで評価する

Slide 27

Slide 27 text

Big-step と Small-step ● ここまでで見た規則は Big-step 意味論と呼ばれる ○ すべての部分式を同時に値まで評価 ● Big-step はサーバーレスと相性が悪い ○ 複数の関数が並列で進行する途中経過こそが重要 ○ イベントドリブンであり「値まで評価」はナンセンス ● もう一つの Small-step 意味論で考える

Slide 28

Slide 28 text

Small-step 意味論(1/3) ● "e1 + e2" の形の式は、左が値の時のみ右を簡約 ● 左右両方が値まで簡約されて初めて和を計算する

Slide 29

Slide 29 text

Small-step 意味論(2/3) ● "e1 < e2" の形の式も、左が値の時のみ右を簡約 ● 左右両方が値まで簡約されて初めて比較を行う

Slide 30

Slide 30 text

Small-step 意味論(3/3) ● "if e1 then e2 else e3" の形の式は条件部分を先に簡約 ● 条件が true / false まで簡約されて初めて選択を行う

Slide 31

Slide 31 text

例:Small-step 意味論による簡約 ● 部分式に対して規則を適用して、逐次的に簡約を行う ● 各ステップでは、1 個の部分式を 1 ステップだけ簡約

Slide 32

Slide 32 text

言語は構文のみに非ず ● 構文が同じでも意味論が違えば別の言語 ○ 例:遅延評価 vs 正格評価 ● 意味論が妥当であることの保証も言語設計の一部 ○ 計算結果が簡約順に依存したり途中で詰まったり ○ 先程の Big / Small-step が等しいことも実は非自明 ○ 理論付けた保証のために厳密な意味論が必要

Slide 33

Slide 33 text

形式的意味論の三分類 ● 操作的意味論(Operational Semantics) ○ 構文に対する書き換え規則により実行方法を定義 ● 表示的意味論(Denotational Semantics) ○ 意味論がより単純な対象への変換方法を定義 ● 公理的意味論(Axiomatic Semantics) ○ パーツごとの事前・事後条件と組み立て規則を定義

Slide 34

Slide 34 text

第 1 章のまとめ ● 操作的意味論による言語の「意味」の定義 ○ 構文と、その構文に対する変換規則を定める ○ 言語の性質に対して厳密な議論が可能に ● 他の方式として、表示的意味論や公理的意味論がある ○ 操作的意味論は実行(インタプリタ)に対応 ○ 表示的意味論は翻訳・変換(コンパイル)に対応

Slide 35

Slide 35 text

本日の解説の流れ ● サーバーレスの動作は非直感的で難しい ● そもそも動作を厳密に記述するとはどういうことか ● 改めて、サーバーレスの動作を厳密に記述する ● 理想化されたサーバーレスの動作はどうあるべきか ● その理想化はどのような条件下で妥当か

Slide 36

Slide 36 text

サーバーレスの意味論 2. Semantics of the Serverless Computation

Slide 37

Slide 37 text

Formal Foundations of Serverless Computing Jandga A. et al. 2019 https://dl.acm.org/doi/10.1145/3360575

Slide 38

Slide 38 text

サーバーレスプラットフォームを 数式を計算するように「実行」する

Slide 39

Slide 39 text

処理待ちリクエスト サーバーレスのライフサイクル概要 何も無い状態 処理待ちリクエスト 関数インスタンス(return) 待機中の関数インスタンス 返却済みレスポンス 関数インスタンス(処理中)

Slide 40

Slide 40 text

トイ言語の “ライフサイクル”

Slide 41

Slide 41 text

言語 = 構文 + 意味論

Slide 42

Slide 42 text

サーバーレスプラットフォーム = 構文(今どのような状態か) + 意味論(状態がどう変化するか)

Slide 43

Slide 43 text

サーバーレスの「言語」 構文 意味論 Fig. 3, Jangda et al. 2019

Slide 44

Slide 44 text

サーバーレスの構文 ● プラットフォーム上に存在する各要素を記号で表す ○ 未処理リクエスト ○ 実行中の関数インスタンス ○ スタンバイ中の関数インスタンス ○ 呼び出し元に返すレスポンス ● 要素を全部並べたものをプラットフォームの状態とする

Slide 45

Slide 45 text

意味論の細部は追わなくて良いので サーバーレスの特性に注目

Slide 46

Slide 46 text

サーバーレスの意味論(1/6) ● 関数 f が起動リクエスト start を受ける ● プラットフォーム内にリクエスト情報 R が出現 ● まだ関数インスタンス F は起動しない

Slide 47

Slide 47 text

サーバーレスの意味論(2/6) ● リクエスト R に対して Cold Start が発生 ● プラットフォーム内に関数インスタンス F が出現 ● リクエスト R は関数起動後も消えない(二重起動)

Slide 48

Slide 48 text

サーバーレスの意味論(3/6) ● リクエスト R に対して Warm Start が発生 ● idle だった既存の関数インスタンス F が busy に ● リクエスト R はやはり関数起動後も残る(二重起動)

Slide 49

Slide 49 text

サーバーレスの意味論(4/6) ● 関数インスタンス F のプログラム f の実行が σ から σ’ へ 1 ステップ進む ● まだ return しておらず、式全体としては何も増えない

Slide 50

Slide 50 text

サーバーレスの意味論(5/6) ● 関数インスタンス F が return する ● リクエスト R は消えてレスポンス S が出現 ● 関数インスタンス F は busy から idle になり残る(再利用)

Slide 51

Slide 51 text

サーバーレスの意味論(6/6) ● 関数インスタンス F が終了して消滅 ● 規則に前提(横棒の上)がない、つまり終了は無条件に いつでも発生しうる

Slide 52

Slide 52 text

第 2 章のまとめ ● サーバーレスプラットフォームの「構文」 ○ 場に存在する関数インスタンスやリクエスト ● サーバーレスプラットフォームの「意味論」 ○ 関数インスタンスが 1 ステップずつ進む並行性 ○ リトライによる At-least-once 実行 ○ Warm Start による関数インスタンスの再利用

Slide 53

Slide 53 text

本日の解説の流れ ● サーバーレスの動作を厳密に記述したい ● そもそも動作を厳密に記述するとはどういうことか ● 改めて、サーバーレスの動作を厳密に記述する ● 理想化されたサーバーレスの動作はどうあるべきか ● その理想化はどのような条件下で妥当か

Slide 54

Slide 54 text

理想と現実のサーバーレス 3. Abstraction & Refinement via Bisimulation

Slide 55

Slide 55 text

理想的なサーバーレス ● 一度に起動する関数インスタンスは一つのみ ● Warm Start による関数インスタンスの再利用がない ● At-least-once ではなく Exactly-once 実行される ● 関数インスタンスが突然終了したりしない

Slide 56

Slide 56 text

単純化されたサーバーレスの「言語」 構文 意味論 Fig. 4, Jangda et al. 2019

Slide 57

Slide 57 text

単純化されたサーバーレスの構文 ● やはりプラットフォーム全体を「式」で表す ○ 処理中の関数名(高々一つ) ○ 処理中のリクエスト(高々一つ) ○ 内部状態の履歴(直線的な実行) ○ 処理済みレスポンスの集合(順不同)

Slide 58

Slide 58 text

単純化しても問題ないのか?

Slide 59

Slide 59 text

◯の遷移と□の遷移はともに a → b または a → c で「同じ」か? a b c a b c a

Slide 60

Slide 60 text

双模倣による状態遷移系の等価性 ● 無限に動き続ける状態遷移系をどう比較するか ○ 関数のテストのように「結果が等しい」は使えない ● 双模倣(Bisimulation)による比較 ○ お互いの状態の間に対応関係が定義されている ○ 対応した状態から、再度対応した状態に追従できる ○ 内部遷移を無視したものは弱(Weak)双模倣と呼ぶ

Slide 61

Slide 61 text

a a 対応関係 対応関係 ◯の遷移 a に対し □が同じ遷移 a で 追従(模倣)できる

Slide 62

Slide 62 text

◯の遷移 a → b に対し □が遷移 a → b で 追従(模倣)できない 動作パターンが存在 a b c a b c a 「同じ」とは言えない

Slide 63

Slide 63 text

関数インスタンスの内部状態 ● 内部状態をどう扱うか? ○ キャッシュを持つ関数は内部に状態が残る ○ Warm Start 時に「完全に同じ状態」にはならない ○ 外部から観測不能な差なら許容したい ● 状態間に Safety Relation と呼ぶ「許容差」を定義 ○ 処理中に許容差から逸脱しないことを保証したい

Slide 64

Slide 64 text

Safety Relation(1/3) ● 関数インスタンスの状態 σ の上に定義された同値関係 ≒ は 以下の条件を満たすとき Safety Relation であるという ● リクエスト受信前に ≒ が成立すれば、受信後にも成立

Slide 65

Slide 65 text

Safety Relation(2/3) ● return しない場合、処理の直前に ≒ が成立するなら 1 ステップ進んだ直後にも成立 ● return する場合、その戻り値が一致

Slide 66

Slide 66 text

Safety Relation(3/3) ● プログラム f が return した直後の状態と、 f の初期状態との間に ≒ が成立(つまり ”ほぼ” 最初に戻る)

Slide 67

Slide 67 text

単純化した構文との対応(概要) ● 単純化側のレスポンスは元の側のリクエストに起因 ● 関数インスタンスの状態は Safety Relation を除き対応 ● この対応関係を A ≈ C で表す ○ A は単純化された構文の式、C は元の構文の式 ○ 論文だとちゃんと構成が書いてあるが今回は割愛 ○ ≈ が Safety Relation を用いて定義される点が重要

Slide 68

Slide 68 text

本日の解説の流れ ● サーバーレスの動作を厳密に記述したい ● そもそも動作を厳密に記述するとはどういうことか ● 改めて、サーバーレスの動作を厳密に記述する ● 理想化されたサーバーレスの動作はどうあるべきか ● その理想化はどのような条件下で妥当か

Slide 69

Slide 69 text

単純化の正当性(Theorem 4.3) ● 単純化側 A と元の側 C は、関係 ≈ を介し弱双模倣同値 ● 要するに、もし Safety Relation が存在するならば 関係 ≈ が定義でき、両者は外から見て区別できない

Slide 70

Slide 70 text

例:ローカルキャッシュの導入(再掲) var cache = new Map(); function auth(req, res) { let (user, pass) = req.body; if (cache.contains(user, pass)) { res.write(true); } else if (db.get(user) == pass) { cache.insert(user, pass); res.write(true); } else { res.write(false); } }

Slide 71

Slide 71 text

例:キャッシュ実装の理論的正当性 ● 考慮したい状態:変数の値 + キャッシュ + DB 上の値 ● キャッシュの差を無視した同一視は Safety Relation の 条件を満たす ○ 数式で書くと「DB が変更されない」条件が現れる ● 従ってこの実装は単純化された意味論で考えても OK で サーバーレス特有の事情の影響は受けない

Slide 72

Slide 72 text

それは最初から言ってたじゃん

Slide 73

Slide 73 text

理論は結局「オモチャ」なのか? ● 今回の例は確かに自明に見えるけど ○ 論文中のサンプルなので簡略化されている ○ 機械的な判定手順が厳密に定式化されることが嬉しい ○ 「継続的な発展」に伴い人間の認識はどんどん腐る ● DB が更新できないと実用上意味ないのでは? ○ 論文後半で更新可能な永続層も含めた意味論が登場

Slide 74

Slide 74 text

参考:Key-Value Store を含む意味論 構文 意味論 Fig. 7, Jangda et al. 2019

Slide 75

Slide 75 text

理解は全てに先立つ そして、理解とは記述である

Slide 76

Slide 76 text

第 3 章のまとめ ● サーバーレスの意味論の単純化 ○ 一旦サーバーレス特有の挙動を無視して単純化 ○ 実行は一度に一つの関数のみ、Warm Start も無し ● 元の意味論との対応関係 ○ Safety Relation により特有の挙動による差を吸収 ○ 元の意味論との間に弱双模倣の関係が成立する

Slide 77

Slide 77 text

まとめと読書案内 4. Wrap-up & Guide to Further Reading

Slide 78

Slide 78 text

本日のまとめ ● サーバーレス特有の複雑性 ○ 低レベルなプラットフォームの都合が露出 ● プログラミング言語と意味論 ○ 厳密な数学的記述を用いて「意味」を定式化 ● Jangda らによるサーバーレスの形式化 ○ 低レベルの都合が無視できる条件を理論的に定義

Slide 79

Slide 79 text

あなたが次に読む本(1/3) ● プログラム意味論の基礎 ○ 小林直樹・住井英二郎 著 ○ サイエンス社(2020) ● 理論含むプログラム意味論の入門向け ○ 数学的準備にも 1 章が割かれている ○ 操作的・表示的・公理的意味論を一通り

Slide 80

Slide 80 text

あなたが次に読む本(2/3) ● プログラミング言語の基礎概念 ○ 五十嵐淳 著 ○ サイエンス社(2011) ● 言語の中でも特に型システムがテーマ ○ 意味論は操作的意味論のみ ○ 言語や型システムの性質の証明に主眼

Slide 81

Slide 81 text

あなたが次に読む本(3/3) ● アンダースタンディング・コンピュテーション ○ Tom Stuart 著・笹田耕一 監訳・笹井崇司 訳 ○ オライリージャパン(2014) ● Ruby で実装しながら計算機科学を学ぶ ○ 手を動かして勘をつかむスタンス ○ Chomsky 階層や停止性問題なども登場

Slide 82

Slide 82 text

You CAN Handle the Truth, With the Semantics! Presented By チェシャ猫 (@y_taka_23)