$30 off During Our Annual Pro Sale. View Details »

サーバーレスアーキテクチャの数理的理解と分析 #devsumi / Developers Summit 2023 Summer

サーバーレスアーキテクチャの数理的理解と分析 #devsumi / Developers Summit 2023 Summer

Developers Summit 2023 Summer で使用したスライドです。

サーバーレスアーキテクチャは強力ですが、同時に冪等性やトランザクションなど特有の考慮事項が必要であり、高い設計力が求められます。ところで、安全なプログラムを書く上で、静的型付き言語は広く利用されていますね。型はいわば実行前に間違いを検出できる仕組みであり、その背後には「プログラムの正しさ」を厳密な数式で記述し分析する理論が存在します。では、同様に「サーバーレスの正しさ」も厳密な数式で記述することは可能でしょうか?本講演ではAWS Lambdaを用いた設計を例として取り上げながら解説します。

イベント概要:https://event.shoeisha.jp/devsumi/20230727/session/4486/
ブログ記事:https://ccvanishing.hateblo.jp/entry/2023/07/27/195634

y_taka_23

July 27, 2023
Tweet

More Decks by y_taka_23

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  5. 例:ローカルキャッシュの導入
    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);
    }
    }

    View Slide

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

    View Slide

  7. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  19. 言語 = 構文 + 意味論

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  41. 言語 = 構文 + 意味論

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  70. 例:ローカルキャッシュの導入(再掲)
    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);
    }
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide