「厳密な共通言語」としての形式手法 #devsumi / Developers Summit 2020

332f89cc697355902a817506b6995f2b?s=47 y_taka_23
February 13, 2020
3.9k

「厳密な共通言語」としての形式手法 #devsumi / Developers Summit 2020

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

言葉というものは曖昧です。複数人が「ともにつくる」システムにおいて、メンバ間で仕様を正しく共有することは非常に重要ですが、一方で言葉の裏側に隠された「暗黙の仮定」を見抜くことは簡単ではありません。このような仕様の曖昧性への対抗手段として、本セッションでは「形式手法」を紹介します。形式手法ではシステムの挙動を数学的に記述することにより、自然言語の持つ曖昧性を排除し、仕様が満たされるかどうかを厳密に検証することが可能になります。あなたの頭の中にある仕様がどのように「数学的な記述」に変換されるのか、具体例を通して体験してみませんか?

イベント概要:https://event.shoeisha.jp/devsumi/20200213/session/2380/

332f89cc697355902a817506b6995f2b?s=128

y_taka_23

February 13, 2020
Tweet

Transcript

  1. #devsumi #devsumiF #devsumi #devsumiF 「厳密な共通言語」としての 形式手法 チェシャ猫 (@y_taka_23) Developers Summit

    2020 [F-13-6] (2020/02/13)
  2. #devsumi #devsumiF #devsumi #devsumiF 本日のアジェンダ • システムの仕様と曖昧性 • 形式手法とツールの概要 •

    モデリングを通した仕様の明確化 • 環境と相互作用する複雑な挙動の解析
  3. #devsumi #devsumiF #devsumi #devsumiF 1. 仕様に隠された曖昧性 Ambiguities in the Specification

  4. #devsumi #devsumiF 例:チェスのルール改定 参考文献:https://old.fide.com/fide/handbook.html?id=208&view=article

  5. #devsumi #devsumiF ポーンは最前列に到達した際 クイーン・ビショップ・ルーク・ナイト のいずれかに成ることができる

  6. #devsumi #devsumiF ポーンは最前列に到達した際 クイーン・ビショップ・ルーク・ナイト のいずれかに成らねばならない

  7. #devsumi #devsumiF ポーンは最前列に到達した際 同色のクイーン・ビショップ・ルーク・ナイト のいずれかに成らねばならない

  8. #devsumi #devsumiF 例:最大値関数

  9. #devsumi #devsumiF max(x, y): x と y のうち大きい方を返す

  10. #devsumi #devsumiF max(x, y): x と y のうち小さくない方を返す

  11. #devsumi #devsumiF 例:水位上昇によるポンプの遮断 参考文献:https://www.researchgate.net/publication/242413466_Assessment_of_safety-critical_software_in_nuclear_power_plants

  12. #devsumi #devsumiF 水位が 4 秒以上、100m を上回ったら ポンプを遮断する

  13. #devsumi #devsumiF 過去 4 秒間の水位の最小値が 100m を上回ったらポンプを遮断する

  14. #devsumi #devsumiF 過去 4 秒間の水位の二乗平均平方根が 100m を上回ったらポンプを遮断する

  15. #devsumi #devsumiF #devsumi #devsumiF 曖昧さはイメージの限界から生まれる • 仕様を理解した「つもり」の思い込み ◦ ポーンが成るなら当然、同色の駒である ◦

    比較可能な値なら当然、大きい方が取れる ◦ 基準値を上回るかどうかなら当然、最小値を見ればよい • 最初に思いついたもの以外は見落としがち ◦ 指摘されるまでは見落としていること自体気づかない
  16. #devsumi #devsumiF 単なる「言葉遊び」に見える?

  17. #devsumi #devsumiF 例:統合決済基盤

  18. #devsumi #devsumiF #devsumi #devsumiF とある決済サービスの仕様 • システム横断的な決済基盤 ◦ 複数の EC

    サイトから利用される • 複数の決済手段をサポート ◦ 銀行引き落とし / ポイント払い / ギフト券払い ◦ 各々が別々のマイクロサービスとして稼働 ◦ 複数の手段に按分して支払うことも可能
  19. #devsumi #devsumiF ポイント管理 1000 pt ギフト券管理 1000 円 銀行口座管理 1000

    円 決済サービス
  20. #devsumi #devsumiF ポイント管理 1000 pt ギフト券管理 1000 円 銀行口座管理 1000

    円 決済サービス 1000 円支払
  21. #devsumi #devsumiF ポイント管理 1000 pt ギフト券管理 1000 円 銀行口座管理 1000

    円 決済サービス 1000 円支払 - 500 円 - 500 pt
  22. #devsumi #devsumiF ポイント管理 500 pt ギフト券管理 1000 円 銀行口座管理 500

    円 決済サービス 1000 円支払
  23. #devsumi #devsumiF ポイント管理 500 pt ギフト券管理 1000 円 銀行口座管理 500

    円 決済サービス 1000 円支払 OK OK
  24. #devsumi #devsumiF ポイント管理 500 pt ギフト券管理 1000 円 銀行口座管理 500

    円 決済サービス OK
  25. #devsumi #devsumiF 処理中にエラーが発生した場合

  26. #devsumi #devsumiF ポイント管理 1000 pt ギフト券管理 1000 円 銀行口座管理 500

    円 決済サービス 1000 円支払 OK ERROR
  27. #devsumi #devsumiF ポイント管理 1000 pt ギフト券管理 1000 円 銀行口座管理 500

    円 決済サービス OK or Retry?
  28. #devsumi #devsumiF #devsumi #devsumiF TCC パターン • 全体を二つのフェイズに分割する • Try

    フェイズ ◦ 各メンバーに更新内容を仮登録させる • Confirm / Cancel フェイズ ◦ 全員から準備 OK が返って来たら改めて Confirm ◦ 一人でも失敗した場合には全員に Cancel させる
  29. #devsumi #devsumiF ポイント管理 ギフト券管理 銀行口座管理 決済サービス Try

  30. #devsumi #devsumiF ポイント管理 ギフト券管理 銀行口座管理 Reserved 決済サービス Try OK

  31. #devsumi #devsumiF ポイント管理 Reserved ギフト券管理 銀行口座管理 Reserved 決済サービス Try OK

  32. #devsumi #devsumiF ポイント管理 Reserved ギフト券管理 銀行口座管理 Reserved 決済サービス Confirm

  33. #devsumi #devsumiF ポイント管理 Confirmed ギフト券管理 銀行口座管理 Reserved 決済サービス Confirm OK

  34. #devsumi #devsumiF ポイント管理 Confirmed ギフト券管理 銀行口座管理 Confirmed 決済サービス Confirm OK

  35. #devsumi #devsumiF 処理中にエラーが発生した場合

  36. #devsumi #devsumiF ポイント管理 Error ギフト券管理 銀行口座管理 Reserved 決済サービス Try Error

  37. #devsumi #devsumiF ポイント管理 Error ギフト券管理 銀行口座管理 Reserved 決済サービス Cancel

  38. #devsumi #devsumiF ポイント管理 Canceled ギフト券管理 銀行口座管理 Canceled 決済サービス Cancel

  39. #devsumi #devsumiF 本当に「理解」してますか?

  40. #devsumi #devsumiF #devsumi #devsumiF TCC パターンの「曖昧」な部分 • 未定義動作のないシステムの正確な挙動 ◦ 各コンポーネントの動作と、非同期に動いた系全体の挙動

    • 保証したい仕様の意味 ◦ 不整合とは何か、どういう状況なら許容できるのか • アルゴリズム外の環境との相互作用 ◦ 動作している各サーバの信頼性、ネットワークの状態
  41. #devsumi #devsumiF #devsumi #devsumiF 分散コンピューティングの落とし穴 • ネットワークは信頼できる • レイテンシはゼロである •

    帯域幅は無限である • ネットワークはセキュアである • ネットワークトポロジは不変である • 管理者は一人である • トランスポートコストはゼロである • ネットワークは均質である 参考文献:https://web.archive.org/web/20171107014323/https://blog.fogcreek.com/eight-fallacies-of-distributed-computing-tech-talk/
  42. #devsumi #devsumiF #devsumi #devsumiF 分散コンピューティングの落とし穴 • ネットワークは信頼できる • レイテンシはゼロである •

    帯域幅は無限である • ネットワークはセキュアである • ネットワークトポロジは不変である • 管理者は一人である • トランスポートコストはゼロである • ネットワークは均質である イメージの限界による曖昧さの発生 参考文献:https://web.archive.org/web/20171107014323/https://blog.fogcreek.com/eight-fallacies-of-distributed-computing-tech-talk/
  43. #devsumi #devsumiF #devsumi #devsumiF 曖昧性ハンドリングの重要性 • アーキテクチャの大規模・複雑化 ◦ マイクロサービス間の疎結合性 ◦

    チーム間での仕様や制約の合意のコスト ◦ マネージドインフラにおける変えられない前提条件 • 開発環境やチーム構成の多様化 ◦ 均質な前提知識やイメージを期待できない
  44. #devsumi #devsumiF テストでカバーすべき?

  45. #devsumi #devsumiF #devsumi #devsumiF テストでカバーできない点 • テストケースの網羅性・再現性 ◦ テストケースとして明示的に思いつく必要がある ◦

    非同期性による実行パスのランダム性 • 実装が先行する必要性 ◦ 実際にテスト対象となるシステムの実装が必要 ◦ 暗黙の仮定を仕様バグとして作り込んでしまうと手戻り
  46. #devsumi #devsumiF 複雑さを扱いうる「言葉」の必要性

  47. #devsumi #devsumiF #devsumi #devsumiF 第 1 章のまとめ • 仕様を厳密に表現するのは意外と難しい ◦

    イメージできる範囲の挙動に引きずられる ◦ 知識や前提が共有されている必要がある • 実システムの挙動は大量の曖昧さを含む ◦ テストは曖昧さを排除する方法の一つだが万能ではない ◦ システムの性質をより正確に記述できる方法論が欲しい
  48. #devsumi #devsumiF 何であれば「共通言語」足り得るのか

  49. #devsumi #devsumiF #devsumi #devsumiF 形式手法 Formal Methods

  50. #devsumi #devsumiF #devsumi #devsumiF 2. はじめての形式手法 Hello, Formal Methods!

  51. #devsumi #devsumiF #devsumi #devsumiF 形式手法とは • システムを数学的対象により表現 ◦ その対象の性質に基づいて検証を行う ◦

    対象として何を選ぶかによってツールの性質が決まる • テストに対する優位点 ◦ テストケースの抜けや漏れが生じない ◦ 実装ではなく仕様や設計に対して検査ができる
  52. #devsumi #devsumiF #devsumi #devsumiF 形式手法の分類 • モデル検査 ◦ システムが取りうる状態を列挙して探索 ◦

    有限個の探索に帰着できる範囲で自動化が可能 • 定理証明 ◦ いわゆる数学的な証明をプログラムとして表現 ◦ 本当に無限個のパターンがある対象を扱える
  53. #devsumi #devsumiF

  54. #devsumi #devsumiF #devsumi #devsumiF TLA+ の特徴 • モデル検査系のツール ◦ Eclipse

    ベースの IDE(TLA Toolbox)とセットで提供 ◦ Lamport(Paxos の発案者)が中心となって開発 ◦ Temporal Logic of Actions と呼ばれる論理がベース • システムを状態の列として表現 ◦ 起こり得る動作の前後で成り立つ関係を記述
  55. #devsumi #devsumiF よくある「学者のオモチャ」なのでは?

  56. #devsumi #devsumiF #devsumi #devsumiF TLA+ の採用事例 • AWS DynamoDB、S3 ◦

    https://lamport.azurewebsites.net/tla/formal-methods-amazon.pdf • CockroachDB の並列コミット ◦ https://www.cockroachlabs.com/blog/parallel-commits/ • FINAL FANTASY XV POCKET EDITION ◦ https://d1.awsstatic.com/events/jp/2018/summit/tokyo/customer/37.pdf
  57. #devsumi #devsumiF #devsumi #devsumiF サンプル:LampLighter • まず非常に単純なシステムを考える • 世界にはフラグがひとつだけ存在する ◦

    変数 lamp で表す • プロセスがひとつだけ稼働している ◦ 断続的にフラグを反転させる ◦ 式で書けば lamp = ~lamp
  58. #devsumi #devsumiF lamp: true lamp: false lamp’ = ~ lamp

    lamp’ = ~ lamp
  59. #devsumi #devsumiF VARIABLE lamp (* 初期状態 *) Init == lamp

    = TRUE (* 状態遷移時の関係 *) Next == lamp' = ~lamp
  60. #devsumi #devsumiF #devsumi #devsumiF サンプル:TwinLighter • フラグがふたつ存在する ◦ 変数名は lamp1

    と lamp2 • プロセスがふたつ非同期で稼働している ◦ それぞれ P1 と P2 とする ◦ P1 は lamp1 を、P2 は lamp2 を反転させる ◦ 同時には動かないが、順番はランダムで交互とも限らない
  61. #devsumi #devsumiF lamp1: false lamp2: true lamp1: false lamp2: false

    lamp1: true lamp2: true lamp1: true lamp2: false
  62. #devsumi #devsumiF VARIABLE lamp (* 初期状態 *) Init == lamp1

    = TRUE /\ lamp2 = TRUE (* 状態遷移時の関係 *) Next == lamp1' = ~lamp1 \/ lamp2' = ~lamp2
  63. #devsumi #devsumiF #devsumi #devsumiF PlusCal による生成 • 生の TLA+ を書くのは人間には辛い

    ◦ そもそも直接、遷移を書けるなら最初から曖昧性などない • PlusCal と呼ばれる DSL からコード生成 ◦ Pascal 風の記法と C 言語風の記法がある • AWS の事例論文でも有効性を強調 ◦ 現場のプログラマからの心理的障壁を下げる効果
  64. #devsumi #devsumiF --algorithm LampLighter process P \in { 1, 2

    } variable lamp = TRUE; begin while TRUE do lamp := ~lamp; end while; end process; end algorithm;
  65. #devsumi #devsumiF --algorithm LampLighter process P \in { 1, 2

    } variable lamp = TRUE; begin while TRUE do lamp := ~lamp; end while; end process; end algorithm; ループっぽい記法
  66. #devsumi #devsumiF --algorithm LampLighter process P \in { 1, 2

    } variable lamp = TRUE; begin while TRUE do lamp := ~lamp; end while; end process; end algorithm; 複数プロセスのインスタンス化
  67. #devsumi #devsumiF #devsumi #devsumiF 第 2 章のまとめ • 形式手法によるシステムの表現 ◦

    システムを数学的な対象にマッピング ◦ 厳密な記述を強制し「イメージの外」の余地を残さない • 今回は TLA+ をモデル検査器として使用 ◦ 研究用だけでなく、国内を含めて産業界で実績がある ◦ PlusCal を使用してプログラムっぽく書ける
  68. #devsumi #devsumiF #devsumi #devsumiF 3. モデリングと仕様の明確化 Formal Modeling of the

    Specifications 参考文献:http://muratbuffalo.blogspot.com/2018/12/2-phase-commit-and-beyond.html
  69. #devsumi #devsumiF #devsumi #devsumiF TCC パターンの「曖昧」な部分 • 未定義動作のないシステムの正確な挙動 ◦ 各コンポーネントの動作と、非同期に動いた系全体の挙動

    • 保証したい仕様の意味 ◦ 不整合とは何か、どういう状況なら許容できるのか • アルゴリズム外の環境との相互作用 ◦ 動作している各サーバの信頼性、ネットワークの状態
  70. #devsumi #devsumiF コンポーネントごとに記述 合成は TLA+ に任せる

  71. #devsumi #devsumiF ポイント管理 ギフト券管理 銀行口座管理 決済サービス Payment Methods

  72. #devsumi #devsumiF fair process Payment begin (* 決済サービス側の挙動 *) end

    process; fair process Method \in METHOD begin (* 決済手段側の挙動 *) end process;
  73. #devsumi #devsumiF #devsumi #devsumiF 決済サービス側の挙動 • まず Try リクエストを出す ◦

    モデリングは Try した状態からスタート • 確定なら Confirm リクエストを出す ◦ 全員が OK のレスポンスを返した場合 • 取り消しなら Cancel リクエストを出す ◦ 一人でも OK のレスポンスを返さなかった場合
  74. #devsumi #devsumiF try cancel confirm

  75. #devsumi #devsumiF try cancel confirm 全員 reserved

  76. #devsumi #devsumiF try cancel confirm 一人でも canceled

  77. #devsumi #devsumiF variable paymentState = "try" fair process Payment begin

    either (* Confirm リクエストを発行 *) await confirmable; paymentState = "confirm"; or (* Cancel リクエストを発行 *) await cancerable; paymentState = "cancel": end either; end process;
  78. #devsumi #devsumiF variable paymentState = "try" fair process Payment begin

    either (* Confirm リクエストを発行 *) await confirmable; paymentState = "confirm"; or (* Cancel リクエストを発行 *) await cancerable; paymentState = "cancel": end either; end process; either ... or … で条件分岐
  79. #devsumi #devsumiF define (* 全員が準備 OK なら確定できる *) confirmable ==

    \A m \in METHOD: methodState[m] \in { "reserved" } (* 一人でもキャンセルなら全員キャンセル *) cancerable == \E m \in METHOD: methodState[m] \in { "canceled" } end define;
  80. #devsumi #devsumiF define (* 全員が準備 OK なら確定できる *) confirmable ==

    \A m \in METHOD: methodState[m] \in { "reserved" } (* 一人でもキャンセルなら全員キャンセル *) cancerable == \E m \in METHOD: methodState[m] \in { "canceled" } end define; forall: 任意の ... exists: 少なくとも一つ存在
  81. #devsumi #devsumiF #devsumi #devsumiF 決済手段側の挙動 • Try に対して仮登録を行う ◦ 待機中に

    Try リクエストを受けたら仮登録状態になる • Confirm に対して確定処理を行う ◦ 自分が仮登録状態ならそれを確定状態に変える • Cancel に対してキャンセル処理を行う ◦ さらに自分自身が失敗した場合もキャンセル状態になる
  82. #devsumi #devsumiF idling confirmed reserved canceled

  83. #devsumi #devsumiF idling confirmed reserved canceled try 受信

  84. #devsumi #devsumiF idling confirmed reserved canceled confirm 受信

  85. #devsumi #devsumiF idling confirmed reserved canceled cancel 受信

  86. #devsumi #devsumiF idling confirmed reserved canceled cancel 受信 または自分が失敗

  87. #devsumi #devsumiF fair process Method \in METHOD begin while methodState[self]

    \in { "idling", "reserved" } do either (* 待機 → 仮登録 *) or (* 仮登録 → 確定 *) or (* キャンセル *) end either; end while; end process; either ... or … で 3 通りに分岐
  88. #devsumi #devsumiF either (* 待機 → 仮登録 *) await methodState[self]

    = "idling"; methodState[self] := "reserved"; or (* 仮登録 → 確定 *) await methodState[self] = "reserved" /\ paymentState = "confirm"; methodState[self] := "confirmed"; or (* キャンセル *) ... end either;
  89. #devsumi #devsumiF either (* 待機 → 仮登録 *) await methodState[self]

    = "idling"; methodState[self] := "reserved"; or (* 仮登録 → 確定 *) await methodState[self] = "reserved" /\ paymentState = "confirm"; methodState[self] := "confirmed"; or (* キャンセル *) ... end either; 仮登録状態になる
  90. #devsumi #devsumiF either (* 待機 → 仮登録 *) await methodState[self]

    = "idling"; methodState[self] := "reserved"; or (* 仮登録 → 確定 *) await methodState[self] = "reserved" /\ paymentState = "confirm"; methodState[self] := "confirmed"; or (* キャンセル *) ... end either; 確定状態になる
  91. #devsumi #devsumiF either (* 待機 → 仮登録 *) ... or

    (* 仮登録 → 確定 *) ... or (* キャンセル *) await methodState[self] = "idling" \/ (methodState[self] = "reserved" /\ paymentState = "cancel"); methodState[self] := "canceled"; end either;
  92. #devsumi #devsumiF either (* 待機 → 仮登録 *) ... or

    (* 仮登録 → 確定 *) ... or (* キャンセル *) await methodState[self] = "idling" \/ (methodState[self] = "reserved" /\ paymentState = "cancel"); methodState[self] := "canceled"; end either; キャンセル状態になる
  93. #devsumi #devsumiF #devsumi #devsumiF TCC パターンの「曖昧」な部分 • 未定義動作のないシステムの正確な挙動 ◦ 各コンポーネントの動作と、非同期に動いた系全体の挙動

    • 保証したい仕様の意味 ◦ 不整合とは何か、どういう状況なら許容できるのか • アルゴリズム外の環境との相互作用 ◦ 動作している各サーバの信頼性、ネットワークの状態
  94. #devsumi #devsumiF #devsumi #devsumiF 検証したい TCC の性質 • トランザクションとしての一貫性 ◦

    Confirmed と Canceded が混在しないか? ◦ 混在するとデータに不整合が発生する • 一連の手続きが完了する保証 ◦ いつかは Confirmed もしくは Canceled になる? ◦ デッドロックや無限ループに陥ると困る
  95. #devsumi #devsumiF #devsumi #devsumiF 安全性と活性 • 安全性 (Safety) ◦ 何か悪いことが「起こらない」ことを要求

    ◦ 通常のプログラムでのアサーションに近い • 活性 (Liveness)一連の手続きが完了する保証 ◦ 何か良いことが「起こる」ことを要求 ◦ 何もしないシステムは無意味なので活性は必須
  96. #devsumi #devsumiF A A 「A が成り立つか?」: 「いずれ A が成り立つか? 」:

    A
  97. #devsumi #devsumiF A A 「A が成り立つか?」: 状態に対する条件 「いずれ A が成り立つか?

    」: A true false true false
  98. #devsumi #devsumiF A A 「A が成り立つか?」: 状態に対する条件 「いずれ A が成り立つか?

    」: 状態列に対する条件 A true false true false true false
  99. #devsumi #devsumiF 仕様を表現する「言葉」の必要性

  100. #devsumi #devsumiF #devsumi #devsumiF 時相論理 (Temporal Logic) • 通常の論理式に記号を追加した体系 ◦

    [] A:現時点以降、常に A が成り立つ ◦ <> A:現時点以降、いつかは A が成り立つ • 状態の列に対して真偽を判定 ◦ 時間的に幅がある振る舞いについて性質を記述できる ◦ 式の真偽の与え方は何種類か存在する (LTL、CTL など)
  101. #devsumi #devsumiF <> A : 現時点以降、いずれは A が成り立つ A true

    false [] A : 現時点以降、常に A が成り立つ A A A A A false true
  102. #devsumi #devsumiF (* 確定とキャンセルが混在しない *) Consistency == \A m1, m2

    \in METHOD: ~ (methodState[m1] = "confirmed" /\ methodState[m1] = "canceled") (* どの決済手段もいつかは確定もしくはキャンセルになる *) Completed == <>(\A m \in METHOD: methodState[m] \in { "confirmed", "canceled" })
  103. #devsumi #devsumiF (* 確定とキャンセルが混在しない *) Consistency == \A m1, m2

    \in METHOD: ~ (methodState[m1] = "confirmed" /\ methodState[m1] = "canceled") (* どの決済手段もいつかは確定もしくはキャンセルになる *) Completed == <>(\A m \in METHOD: methodState[m] \in { "confirmed", "canceled" }) 「いつかは」= 時相論理
  104. #devsumi #devsumiF いざ検査!

  105. #devsumi #devsumiF No errors!

  106. #devsumi #devsumiF #devsumi #devsumiF 検証したい TCC の性質(再掲) • トランザクションとしての一貫性 ◦

    Confirmed と Canceded が混在しないか? ◦ 混在するとデータに不整合が発生する • 一連の手続きが完了する保証 ◦ いつかは Confirmed もしくは Canceled になる? ◦ デッドロックや無限ループに陥ると困る
  107. #devsumi #devsumiF #devsumi #devsumiF 第 3 章のまとめ • TLA+ による

    TCC のモデリング ◦ 各遷移が起こりうる条件を分割整理し、漏れをなくす ◦ 各コンポーネントごとに記述すれば合成してくれる • 時相論理による検証 ◦ 安全性と活性の両サイドを検証 ◦ テストでは難しい「一連の振る舞い」が検査可能
  108. #devsumi #devsumiF #devsumi #devsumiF 4. 複雑な実行パスの検証 Check Complicated Behaviour

  109. #devsumi #devsumiF #devsumi #devsumiF TCC パターンの「曖昧」な部分 • 未定義動作のないシステムの正確な挙動 ◦ 各コンポーネントの動作と、非同期に動いた系全体の挙動

    • 保証したい仕様の意味 ◦ 不整合とは何か、どういう状況なら許容できるのか • アルゴリズム外の環境との相互作用 ◦ 動作している各サーバの信頼性、ネットワークの状態
  110. #devsumi #devsumiF #devsumi #devsumiF 決済サービスの故障 • 先ほどのモデリングは故障しない前提 ◦ 直感的なイメージが難しいのはむしろ異常系 ◦

    故障の発生はランダムなので分岐が爆発的に増える • Confirm または Cancel リクエスト後に故障 ◦ 故障後はいかなるリクエストも発しない ◦ 故障後はずっと故障していて、自動で復旧はしない
  111. #devsumi #devsumiF 性質の良いシステム 性質の悪いシステム

  112. #devsumi #devsumiF 故障しない 性質の良いシステム 性質の悪いシステム

  113. #devsumi #devsumiF 故障しない 性質の良いシステム Crash-Stop 故障 : 故障後、完全に沈黙 性質の悪いシステム

  114. #devsumi #devsumiF 故障しない 性質の良いシステム Crash-Stop 故障 : 故障後、完全に沈黙 Crash-Recovery 故障

    : 故障後、復活の可能性 性質の悪いシステム
  115. #devsumi #devsumiF 故障しない 性質の良いシステム Crash-Stop 故障 : 故障後、完全に沈黙 Crash-Recovery 故障

    : 故障後、復活の可能性 ビザンチン故障:サーバが任意の応答を返す 性質の悪いシステム
  116. #devsumi #devsumiF つまり決済サーバの故障モデルとして Crash-Stop 性を仮定

  117. #devsumi #devsumiF try cancel confirm

  118. #devsumi #devsumiF try cancel confirm crash

  119. #devsumi #devsumiF Errors!

  120. #devsumi #devsumiF #devsumi #devsumiF エラートレースの内容 1. 決済手段サーバ 1, 2, 3

    の順に Try が到達し 3 台とも Reserved 状態に 2. 決済サーバが Confirm リクエスト動作中に故障 3. Confirm リクエストは決済手段サーバに到達せず 4. 決済手段サーバは Reserved のまま動けない
  121. #devsumi #devsumiF #devsumi #devsumiF フェイルオーバによる冗長化 • 決済サービスの代替サーバを用意 ◦ 代替サーバは故障しないと仮定する •

    代替サーバの挙動 ◦ 本体が故障していないかを監視 ◦ 本体が正常なら何もしない ◦ 故障していたら代わりに Confirm / Cancel リクエスト
  122. #devsumi #devsumiF ポイント管理 ギフト券管理 銀行口座管理 決済サービス 代替サービス

  123. #devsumi #devsumiF ポイント管理 Reserved ギフト券管理 Reserved 銀行口座管理 Reserved 決済サービス Crash

    代替サービス
  124. #devsumi #devsumiF ポイント管理 Reserved ギフト券管理 Reserved 銀行口座管理 Reserved 決済サービス Confirm

    代替サービス
  125. #devsumi #devsumiF ポイント管理 Confirmed ギフト券管理 Confirmed 銀行口座管理 Confirmed 決済サービス Confirm

    代替サービス
  126. #devsumi #devsumiF crach cancel confirm

  127. #devsumi #devsumiF crach cancel confirm 全員 reserved

  128. #devsumi #devsumiF crach cancel confirm 一人でも canceled

  129. #devsumi #devsumiF Errors!

  130. #devsumi #devsumiF #devsumi #devsumiF エラートレースの内容 1. 決済手段サーバが 3 台とも Reserved

    になる 2. 決済サーバが手段サーバ 1 にのみ Confirm を送った状態で故障 3. 「全員 Reserved」ではないため代替サーバ動作せず
  131. #devsumi #devsumiF crach cancel confirm 全員 reserved か、 もしくは最低一人が confirmed

  132. #devsumi #devsumiF No errors!

  133. #devsumi #devsumiF #devsumi #devsumiF 第 4 章のまとめ • システムが取りうる異常系をあらかじめ記述 ◦

    どのような故障を想定するか ◦ どのような故障であれば耐えられるように設計するか • TLA+ による探索 ◦ 全探索により仕様に合わない挙動を検出 ◦ 人間ではすぐには思いつかないような条件の漏れを指摘
  134. #devsumi #devsumiF #devsumi #devsumiF 5. 本日のまとめ Recup the Session

  135. #devsumi #devsumiF #devsumi #devsumiF 本日のまとめ • 自然言語による仕様は曖昧性を持つ ◦ 理解しているつもりで意外な見落としの原因になる •

    形式手法によるモデリング ◦ 数学的な表現を用いることで厳密な表現が可能に • より複雑な状況における解析の自動化 ◦ 長く複雑な実行パスであっても自動で網羅される