Save 37% off PRO during our Black Friday Sale! »

FastlyとTypeScriptで実現するカナリアリリース / yamagoya2020

96030bc60c6fc8a91f25ccda9b413b24?s=47 Sho Miyamoto
November 25, 2020

FastlyとTypeScriptで実現するカナリアリリース / yamagoya2020

#yamagoya2020 で 2020/11/25 に登壇させていただいたセッションの資料です。

96030bc60c6fc8a91f25ccda9b413b24?s=128

Sho Miyamoto

November 25, 2020
Tweet

Transcript

  1. FastlyとTypeScriptで 実現する カナリアリリースと A / Bテスト Sho Miyamoto (日本経済新聞社)

  2. - 名前 Sho Miyamoto - 所属 日本経済新聞社 - 領域 -

    web - front-end - {client,server,edge}-side - GitHub https://github.com/shqld 自己紹介 2
  3. ⚠ 今日の発表では実装の詳細に (なるべく)深入りしないようにします 3 代わりに、発表後に公開されるこの資料をご覧いただけると嬉しいです

  4. (ダーク)カナリアリリースを ご存知でしょうか? 4

  5. カナリアリリース 5 - 一部のユーザだけに新機 能を見せる - ランダムに絞ることが多い - 問題がなければ、その後 100%のユーザに展開

  6. - 開発者・社内のユーザな ど、特定の条件に合う ユーザだけに新機能を見 せる - 本番環境での確認やQA を通した上でユーザへ展 開 ダークカナリアリリース

    6
  7. - 絞った数のユーザだけで、画面やシステムへの影響度を見ることができる - 問題があったときに全体に波及させない - ダークカナリアリリースの場合、そもそもユーザには見えないのでより安全 - 公開前の機能・ページを予め本番に出しておいて社内で確認、指定日時に自動リ リース、ということも可能 カナリアリリースの利点

    7
  8. A / B テスト 8 - いわずとしれた 分析手法

  9. Feature Toggles で 実現できる 9

  10. Feature Toggles 10

  11. Feature Toggles 11 https://laptrinhx.com/1-minute-feature-toggle-1686812105/ - 機能のオンオフ状態を示す - イメージはスイッチボタン

  12. - 実際にコード内で行っているのは分 岐を作ることだけ - コードを書き換えるのではなく、分 岐させる - 分岐先はランタイムで判定 Feature Toggles

    12
  13. Feature Toggles - ここに全てが記されている - Feature Toggles (aka Feature Flags)

    by Martin Fowler 13
  14. 14 ポイント リリースとデプロイの タイミングをずらす → ユーザからの見え方や挙動を より柔軟にコントロールできる

  15. - 機能リリースが安全になる - 一度本番で確認してから全体へリリー ス、ということができる - QAテストが容易になる - 他部署・非エンジニアでも、スイッチを 切り替えるだけで検証できる

    15 Feature Toggles の利点 - 非常時の対応が素早い - 何かあればスイッチを切り戻すだけで デプロイせずに対応できる - 非機能要件の検証がしやすい - パフォーマンス施策の効果検証など
  16. 16 問題があったときに、 いかに素早く切り戻せるかも重要 Toggle経由ならデプロイも待たずに即反映できる

  17. 電子版と Feature Toggles 17

  18. - 新しい機能やページは基本的に ダークカナリアリリース - 実際に開発者が本番で確認してから 全てのユーザに展開 - 指定の日時に自動リリース - e.g.

    大統領選の始まる時間に合わせ て特設ページをリリース 18 Feature Toggles の用途 - マーケティング施策のA/Bテストを 行う - e.g. ペイウォール(有料登録動線)の 文言変更 - 技術的な施策の効果検証を行う - e.g. Dynamic Critical CSSを本番に反 映しても問題ないか検証、確認が取れ るまでは反映しない
  19. - JSONで管理 - defaultValue を決めて おく - A / B

    テストを行うときは candidates を定義 実際の Toggle 定義 19
  20. - 基本的に boolean なの で、ただの分岐として書く だけ ダーク カナリアリリース 20

  21. - カナリアリリースのときと 特に変わらない - この例ではコンポーネント ごと出し分けている - これらのTogglesは全て 計測システムに送ってい るので、この機能を見た

    ユーザを判別できる A / B テスト 21
  22. 22 社内の非開発者でも簡単に オンオフできるUIもある

  23. Feature Toggles の 実装 23

  24. Default / Static - 既定値 - Toggle の定義時に人間が決定 - リリース用

    - 例 - 「このToggleはもうリリースできるのでオン」 Override / Dynamic - 上書き値 - 定義された条件から機械的に決定 - スケジュール用、セグメンテーション用 - 例 - 「11/25になったからオン」 - 「このユーザのセグメントが10%内だからオ ン」 24 Toggle の2つの側面
  25. 25 Toggle の2つの側面

  26. 26 Feature Toggles の材料

  27. 基盤の構成 27

  28. - dynamic toggles の計算のため に別のサーバを必要としている - 運用・ケアが必要 - Toggles サーバにリクエストする

    ために VCL内で restart している - restart - static toggles の同期のために サービス側で5分おきにAPIへ ポーリングしている - メモリに暗黙的な状態が存 在する 28
  29. - HTTPヘッダに Toggles を詰めて オリジンへリクエスト - キャッシュが混らないように`Vary` ヘッダを付けてレスポンス メッセージの やりとり

    29
  30. 旧基盤 (Nikkei-Flags) についての詳しい解説はFastlyの記事で How to solve anything in VCL, part

    3: authentication and feature flags at the edge https://www.fastly.com/blog/how-solve-anything-vcl-part-3-authentication-and- feature-flags-edge 30
  31. Feature Toggles システムの リプレース 31

  32. リプレースの要件・ゴール (1) 32 - インフラ - 状態や計算も全てVCLで完結 - 完全サーバーレス -

    転送量 - 各リクエスト毎に送られるデータはなるべく小さく - できるものは全て静的に解決しておく - 複雑性 - 暗黙的・非透過的な状態はなるべく排除 - 「いま何がメモリにあって何がどうなっているのか」という懸念がない
  33. - 運用性 - 更新反映が速い - 終了した・不要な toggle の分岐がコードに残らない - Toggleの定義

    - 定義が簡潔 - 個々の存在目的が明確 リプレースの要件・ゴール (2) 33
  34. 34 まずToggleの概念を再考した

  35. 35 https://martinfowler.com/articles/feature-toggles.html

  36. - Toggleの種類は4つ - Release: (ダーク)カナリーリリース - Experiment: ダークローンチやA/Bテスト - Ops:

    状況に応じてインフラなどを切り替える - Permission 権限別に処理をスイッチ - → 本当に必要なのは Release と Experiment - それ以外はどちらも Longevity(寿命)が長く消しづらい - Opsはユースケースが限定的 で頻度が少ない - Permissionはアプリケーションの一部として 依存されてしまう可能性が高い Toggle 再考 36
  37. - 存在意義・目的が明確 - ある機能をスイッチ(オン /オフ)するだけ - → 値は True /

    False の2値のみ - 1つのToggleに複数の用途を持たせない - 寿命が短く疎結合 - 短い役目を終えたら すぐに消せる - コードから剥がしやすい - 存在が透過的 - Toggleの存在を前提としない - Toggleにアプリケーションの 実装が依存しない あるべき理想のToggle 37
  38. 38 色々な議論・紆余曲折あったが... 最終的にできたもの (設計に半年以上かかった)

  39. 39 Feature Toggles の材料

  40. 新基盤の構成 40

  41. - エッジで dynamic toggles の計 算を行う - サーバレス、VCLで完結 - restart

    / polling も消えた - 最初から bereq に toggles が入っている - 各bereqごとに CDN へリクエスト して static toggles を取得 - 常に最新の toggles を同 期できる - 暗黙的な状態を持たない 41
  42. - 誰にでも書ける簡単・簡潔な インターフェース - 名前と概要、各タイプのオプション を記述 - JSONとは異なり、オプションの チェックや補完が効く トグルの定義

    42
  43. - Fastify の `req` オブジェクトに APIを生やす - TypeScriptで実装 - できるだけ型で縛れるように型推

    論多め - 返る値は必ずBoolean アプリケーション コード 43 (文字列の位置が下がっているのはVSCodeのプラグインの関係)
  44. デプロイフロー - Toggles を別のリポジトリの切り 出した - npmの`prepublishOnly` フックでデプロイが実行さ れる -

    npm publishとVCLのdeployが終 わったあとに Fastly API でソフト パージ - toggles 周りのVCLは VCL Snippets として作っており、本体 のVCLとは別軸・別レポでデプロ イが可能 44
  45. 45 VCL Snippets - メインとなるCustom VCLと は別サイクルで更新ができ る - サブルーチン単位でデプロ

    イ可能 - https://docs.fastly.com/en/g uides/using-dynamic-vcl-sn ippets
  46. 46 実装上の各ポイント

  47. ✏ Toggles API の処理を VCLで実装 47

  48. - JSで定義されたToggleを読んで、 dynamic toggles 用のVCLを生 成している - Scheduling - リクエストされた時間と定

    義ルールの時間を比較し てオンオフを決める - Segmentation - 何かしらのリクエストIDを 使いユーザのセグメントを 決定し定義ルールの範囲 と比較してオンオフを決め る 48
  49. - 上の定義から、下の dynamic toggles 用の条件分岐を生成し ている - セグメンテーションで同じユーザが 複数の Toggle

    で似たような判定 にならないように、条件範囲に random offset を含めている 49
  50. 50 ✏ 転送量を抑えた

  51. 51 Toggleの数や名前によって数が重くなる

  52. 52 長いキーを4 bytesのハッシュに変換

  53. 53 ハッシュをToggle定義とマッピング

  54. 54 リクエストごとに発生するこの部分を減らしたい

  55. 55 先頭にversionをつけ、toggle コンテンツのversioningをする

  56. 56 versioningされていることで、static toggles のメモ化ができる

  57. 57 ✏ TypeScriptで Toggle の取り扱いを安全に

  58. 58 型で toggle の名前を補完

  59. 59 消した toggle が使われていたら型エラー

  60. 60 ‘ xxx‘ で検索できる - 抽象化されているとtoggle がどこで使われているか追 えなくなる - toggle

    のキーは必ず ‘ ‘ で始まるように強制(それ以 外を弾いている) - string literal タイプなので キーを抽象化できない - ✖ get(‘ ‘ + name)
  61. - toggle を生成する関数を経由 - ここで name を string literal タイ

    プで受け取る - string literal の name を返す Toggle オブジェクトの型引数に 渡して保持 型の推論 61
  62. - 集めた toggles を Object.freeze で readonly に - typeof

    で型に変えた toggles の name を ユニオンとして取り出す 型の推論 (2) 62
  63. まとめ

  64. - (ダーク)カナリアリリースは便利 - リリースの安全性が高まる - Feature Toggles で実現できることが多い - デプロイとリリースのタイミングをずらすことで色々できる

    - 電子版では Feature Toggles を(結構)活用している - ダークカナリアリリース、スケジューリング、 A/Bテスト、... まとめ 64
  65. まとめ (2) - Feature Toggles の運用を見返してシンプルに - 何でもできてしまう toggles は禁止、制約を強めに

    - VCLを駆使すれば 外部のサーバは必要ない - VCL Snippets でデプロイフローも簡潔に - TypeScript でアプリケーションコードを安全に - 補完や検索、エラー検知も容易に 65
  66. ありがとうございました 66

  67. 余談: restart_and_you_will_be_fired

  68. VCL restart; 68

  69. - 人類にはまだ早い - 使わずに済むなら使わない方が良い - これを消したかった、というのも今回のリプレースの動機の大きな一つ - 中々解決できない問題は大体 restart 起因であることが多い(個人の経験上)

    - 様々なパターンを網羅的に知っておかないと思わぬ事故に繋がってしまう - 一度目のリクエストで( restartまでに)何が行われたのか - どんなHTTP ヘッダが付いてどう影響するのか - 次のリクエストでどうなるか ...etc. - もちろん必要なとき、有用なときはある - e.g. フレンドリーなエラーページに差し替えるとき VCL restart; 69