Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Sho Miyamoto
November 25, 2020

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

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

Sho Miyamoto

November 25, 2020
Tweet

More Decks by Sho Miyamoto

Other Decks in Technology

Transcript

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

    View Slide

  2. - 名前
    Sho Miyamoto
    - 所属
    日本経済新聞社
    - 領域
    - web
    - front-end
    - {client,server,edge}-side
    - GitHub
    https://github.com/shqld
    自己紹介
    2

    View Slide

  3. ⚠ 今日の発表では実装の詳細に
    (なるべく)深入りしないようにします
    3
    代わりに、発表後に公開されるこの資料をご覧いただけると嬉しいです

    View Slide

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

    View Slide

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

    View Slide

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

    ダークカナリアリリース
    6

    View Slide

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

    View Slide

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

    View Slide

  9. Feature Toggles で
    実現できる
    9

    View Slide

  10. Feature Toggles
    10

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  15. - 機能リリースが安全になる
    - 一度本番で確認してから全体へリリー
    ス、ということができる
    - QAテストが容易になる
    - 他部署・非エンジニアでも、スイッチを
    切り替えるだけで検証できる
    15
    Feature Toggles の利点
    - 非常時の対応が素早い
    - 何かあればスイッチを切り戻すだけで
    デプロイせずに対応できる
    - 非機能要件の検証がしやすい
    - パフォーマンス施策の効果検証など

    View Slide

  16. 16
    問題があったときに、
    いかに素早く切り戻せるかも重要
    Toggle経由ならデプロイも待たずに即反映できる

    View Slide

  17. 電子版と
    Feature Toggles
    17

    View Slide

  18. - 新しい機能やページは基本的に
    ダークカナリアリリース
    - 実際に開発者が本番で確認してから
    全てのユーザに展開
    - 指定の日時に自動リリース
    - e.g. 大統領選の始まる時間に合わせ
    て特設ページをリリース
    18
    Feature Toggles の用途
    - マーケティング施策のA/Bテストを
    行う
    - e.g. ペイウォール(有料登録動線)の
    文言変更
    - 技術的な施策の効果検証を行う
    - e.g. Dynamic Critical CSSを本番に反
    映しても問題ないか検証、確認が取れ
    るまでは反映しない

    View Slide

  19. - JSONで管理
    - defaultValue を決めて
    おく
    - A / B テストを行うときは
    candidates を定義
    実際の Toggle 定義
    19

    View Slide

  20. - 基本的に boolean なの
    で、ただの分岐として書く
    だけ
    ダーク
    カナリアリリース
    20

    View Slide

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

    View Slide

  22. 22
    社内の非開発者でも簡単に
    オンオフできるUIもある

    View Slide

  23. Feature Toggles の
    実装
    23

    View Slide

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

    View Slide

  25. 25
    Toggle の2つの側面

    View Slide

  26. 26
    Feature Toggles の材料

    View Slide

  27. 基盤の構成
    27

    View Slide

  28. - dynamic toggles の計算のため
    に別のサーバを必要としている
    - 運用・ケアが必要
    - Toggles サーバにリクエストする
    ために VCL内で restart している
    - restart
    - static toggles の同期のために
    サービス側で5分おきにAPIへ
    ポーリングしている
    - メモリに暗黙的な状態が存
    在する
    28

    View Slide

  29. - HTTPヘッダに Toggles を詰めて
    オリジンへリクエスト
    - キャッシュが混らないように`Vary`
    ヘッダを付けてレスポンス
    メッセージの
    やりとり
    29

    View Slide

  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

    View Slide

  31. Feature Toggles システムの
    リプレース
    31

    View Slide

  32. リプレースの要件・ゴール (1)
    32
    - インフラ
    - 状態や計算も全てVCLで完結
    - 完全サーバーレス
    - 転送量
    - 各リクエスト毎に送られるデータはなるべく小さく
    - できるものは全て静的に解決しておく
    - 複雑性
    - 暗黙的・非透過的な状態はなるべく排除
    - 「いま何がメモリにあって何がどうなっているのか」という懸念がない

    View Slide

  33. - 運用性
    - 更新反映が速い
    - 終了した・不要な toggle の分岐がコードに残らない
    - Toggleの定義
    - 定義が簡潔
    - 個々の存在目的が明確
    リプレースの要件・ゴール (2)
    33

    View Slide

  34. 34
    まずToggleの概念を再考した

    View Slide

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

    View Slide

  36. - Toggleの種類は4つ
    - Release: (ダーク)カナリーリリース
    - Experiment: ダークローンチやA/Bテスト
    - Ops: 状況に応じてインフラなどを切り替える
    - Permission 権限別に処理をスイッチ
    - → 本当に必要なのは Release と Experiment
    - それ以外はどちらも Longevity(寿命)が長く消しづらい
    - Opsはユースケースが限定的 で頻度が少ない
    - Permissionはアプリケーションの一部として 依存されてしまう可能性が高い
    Toggle 再考
    36

    View Slide

  37. - 存在意義・目的が明確
    - ある機能をスイッチ(オン /オフ)するだけ
    - → 値は True / False の2値のみ
    - 1つのToggleに複数の用途を持たせない
    - 寿命が短く疎結合
    - 短い役目を終えたら すぐに消せる
    - コードから剥がしやすい
    - 存在が透過的
    - Toggleの存在を前提としない
    - Toggleにアプリケーションの 実装が依存しない
    あるべき理想のToggle
    37

    View Slide

  38. 38
    色々な議論・紆余曲折あったが...
    最終的にできたもの
    (設計に半年以上かかった)

    View Slide

  39. 39
    Feature Toggles の材料

    View Slide

  40. 新基盤の構成
    40

    View Slide

  41. - エッジで dynamic toggles の計
    算を行う
    - サーバレス、VCLで完結
    - restart / polling も消えた
    - 最初から bereq に
    toggles が入っている
    - 各bereqごとに CDN へリクエスト
    して static toggles を取得
    - 常に最新の toggles を同
    期できる
    - 暗黙的な状態を持たない
    41

    View Slide

  42. - 誰にでも書ける簡単・簡潔な
    インターフェース
    - 名前と概要、各タイプのオプション
    を記述
    - JSONとは異なり、オプションの
    チェックや補完が効く
    トグルの定義
    42

    View Slide

  43. - Fastify の `req` オブジェクトに
    APIを生やす
    - TypeScriptで実装
    - できるだけ型で縛れるように型推
    論多め
    - 返る値は必ずBoolean
    アプリケーション
    コード
    43
    (文字列の位置が下がっているのはVSCodeのプラグインの関係)

    View Slide

  44. デプロイフロー
    - Toggles を別のリポジトリの切り
    出した
    - npmの`prepublishOnly`
    フックでデプロイが実行さ
    れる
    - npm publishとVCLのdeployが終
    わったあとに Fastly API でソフト
    パージ
    - toggles 周りのVCLは VCL
    Snippets として作っており、本体
    のVCLとは別軸・別レポでデプロ
    イが可能
    44

    View Slide

  45. 45
    VCL Snippets
    - メインとなるCustom VCLと
    は別サイクルで更新ができ

    - サブルーチン単位でデプロ
    イ可能
    - https://docs.fastly.com/en/g
    uides/using-dynamic-vcl-sn
    ippets

    View Slide

  46. 46
    実装上の各ポイント

    View Slide

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

    View Slide

  48. - JSで定義されたToggleを読んで、
    dynamic toggles 用のVCLを生
    成している
    - Scheduling
    - リクエストされた時間と定
    義ルールの時間を比較し
    てオンオフを決める
    - Segmentation
    - 何かしらのリクエストIDを
    使いユーザのセグメントを
    決定し定義ルールの範囲
    と比較してオンオフを決め

    48

    View Slide

  49. - 上の定義から、下の dynamic
    toggles 用の条件分岐を生成し
    ている
    - セグメンテーションで同じユーザが
    複数の Toggle で似たような判定
    にならないように、条件範囲に
    random offset を含めている
    49

    View Slide

  50. 50
    ✏ 転送量を抑えた

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  60. 60
    ‘ xxx‘ で検索できる
    - 抽象化されているとtoggle
    がどこで使われているか追
    えなくなる
    - toggle のキーは必ず ‘ ‘
    で始まるように強制(それ以
    外を弾いている)
    - string literal タイプなので
    キーを抽象化できない
    - ✖ get(‘ ‘ + name)

    View Slide

  61. - toggle を生成する関数を経由
    - ここで name を string literal タイ
    プで受け取る
    - string literal の name を返す
    Toggle オブジェクトの型引数に
    渡して保持
    型の推論
    61

    View Slide

  62. - 集めた toggles を Object.freeze
    で readonly に
    - typeof で型に変えた toggles の
    name を ユニオンとして取り出す
    型の推論 (2)
    62

    View Slide

  63. まとめ

    View Slide

  64. - (ダーク)カナリアリリースは便利
    - リリースの安全性が高まる
    - Feature Toggles で実現できることが多い
    - デプロイとリリースのタイミングをずらすことで色々できる
    - 電子版では Feature Toggles を(結構)活用している
    - ダークカナリアリリース、スケジューリング、 A/Bテスト、...
    まとめ
    64

    View Slide

  65. まとめ (2)
    - Feature Toggles の運用を見返してシンプルに
    - 何でもできてしまう toggles は禁止、制約を強めに
    - VCLを駆使すれば 外部のサーバは必要ない
    - VCL Snippets でデプロイフローも簡潔に
    - TypeScript でアプリケーションコードを安全に
    - 補完や検索、エラー検知も容易に
    65

    View Slide

  66. ありがとうございました
    66

    View Slide

  67. 余談:
    restart_and_you_will_be_fired

    View Slide

  68. VCL restart;
    68

    View Slide

  69. - 人類にはまだ早い
    - 使わずに済むなら使わない方が良い
    - これを消したかった、というのも今回のリプレースの動機の大きな一つ
    - 中々解決できない問題は大体 restart 起因であることが多い(個人の経験上)
    - 様々なパターンを網羅的に知っておかないと思わぬ事故に繋がってしまう
    - 一度目のリクエストで( restartまでに)何が行われたのか
    - どんなHTTP ヘッダが付いてどう影響するのか
    - 次のリクエストでどうなるか ...etc.
    - もちろん必要なとき、有用なときはある
    - e.g. フレンドリーなエラーページに差し替えるとき
    VCL restart;
    69

    View Slide