Feature Flagを利用したリリース戦略

(エッセンシャル版)

黒曜
@kokuyouwind

$ whoami

  • 森 俊介 / 黒曜

  • @kokuyouwind

  • 株式会社Misoca

  • SRE

本番リリース

スモールリリース

  • アジャイルプラクティス

  • 小さく、高頻度にリリースする
    • 素早く価値を届けられる

    • フィードバックを速く得られる

開発メリット

  • 変更粒度が小さくなることで……

    • コードレビューしやすくなる

    • コードが衝突しづらくなる

    • 問題の原因特定がしやすくなる

😆

とはいえ…

  • 現実にはそう簡単にいかないときもある

    • プレスリリース合わせで全部出す

    • ちょっとずつ出すとデータ不整合

    • 一揃いの機能がないとUXが悪い

    • etc...

🤔

ビッグバンリリース

FeatureFlag

  • 機能を動的にOn/Offできる仕組み

    • ある環境でだけ有効にする

    • あるユーザにだけ有効にする

    • 管理者が全体の有効/無効を切り替える

    • etc...

FeatureFlag

if feature_enabled?
  process_with_feature
else
  process_without_feature
end
  • 実装は簡単

    • 真偽値を返す関数とif文の組み合わせ

feature_enabled?

  • システム全体で共通

    • デプロイ時

    • ホットリロード

  • リクエストごとに判定

    • 特定ユーザにだけ機能を有効化

    • 特定割合のユーザに機能を有効化

    • 特定属性のユーザに機能を有効化

feature_enabled?

  • 設定管理の方法は色々

    • 環境変数

    • 設定ファイル

    • KVS

    • クラウドサービス

    • etc.

FeatureFlagのメリット

  • 一般ユーザに見せないコードを入れられる

    • 一般公開と別の単位でリリースできる

    • 公開前の機能を本番で試せる

  • 様々な目的に利用できる

    • カナリヤリリース

    • A/Bテスト

    • etc...

MisocaでのFeatureFlag

  • リリーストグル

    • リリースせず開発期間が長期に渡る機能

    • 時間合わせでのリリースが必要な機能

  • 実験トグル・Opsトグル

    • パフォーマンス改善
      (A/Bテスト、カナリヤテストを兼ねる)

実装

  • LaunchDarklyを検討したが見送り

    • 高機能だが費用が結構かかる
    • ​機能を使いこなせなさそう
  • ​​​Redisをバックエンドに自作

    • rollout gemとほぼ同じ仕組みに落ちついた
    • 2ファイル200行弱

設定と分岐

# initialize
Misoca.feature_flag = Misoca::FeatureFlag.new
Misoca.feature_flag.add_target(
  :new_feature,
  'なんかすごい新機能'
)

# use
if Misoca.feature_flag.enabled?(:new_feature, current_user)
  Misoca::UseCase::NewFeature.new.call
else
  Misoca::UseCase::CurrentFeature.new.call
end

ユーザごとの有効化

class Misoca::FeatureFlag::Target
  def enable_for_user(user)
    redis.sadd(user_key, user.id)
  end
end

Misoca.feature_flag.enable_for_user(user)

feature_flag:new_feature:users
(有効化したユーザidの集合)

42

123456

114514

user id: 123456

redis.sadd
123456

比率での有効化

feature_flag:new_feature:segments
(有効化したユーザid下2桁の集合)

00

12

33

redis.sadd 04 87

04

87

例: 有効化率を3% から 5% に

元々含まれない
2桁の数を2つ選ぶ
(3%から5%なので+2)

04

87

有効判定

有効化したユーザidの集合

42

123456

114514

user id: 123456

redis.sismember 123456

有効化したユーザid下2桁の集合

00

12

33

redis.sismember 56

04

87

運用

  • 内部ユーザ向けページから有効状況を見れる

  • フラグの切り替え

    • ​内部ユーザ向けページ(自分のみ)

    • Thorタスク実行(比率指定)

実用例

  • 軽減税率対応

  • 電卓機能

  • PDFのS3キャッシュ

軽減税率対応

軽減税率対応

  • スモールリリースの難しい機能

    • 影響範囲が広く、作業量が多い
    • ​プレスリリース合わせでの有効化
  • ​​​リリーストグルを使用

    • コードを適宜masterにマージ
    • 内部ユーザはできたところから本番で動作確認
    • フラグを外して一般リリース

電卓機能

電卓機能

  • ヘルプ更新のため、時間合わせリリース

    • コード量自体はそこまで大きくない​
  • ​​​リリーストグルを使用

    • 事前に内部ユーザで動作確認

    • デプロイせず設定変更のみでリリース

      • ​デプロイ絡みでのトラブルの心配がない

PDFのS3キャッシュ

PDFのS3キャッシュ

  • PDF生成が重いため、S3に2次キャッシュ

    • 初回PDF生成時にS3へ書き込み​
    • 1次キャッシュがない場合、S3から取得
  • ​​​どの程度改善するか見積りづらい

    • S3へのwrite処理が増える

    • S3 Readの重さによっては改善しない可能性も

PDFのS3キャッシュ

10%のユーザにリリース→APMで効果測定

PDF Render: 800ms

S3 PUT: 94ms

S3 GET(miss): 40ms

S3 GET(hit): 72ms

生成時に+134ms,
読み込み時に728ms改善

いける!

気をつけること

  • 汎用のフラグを使わない

    • FeatureFlagを外すときに大変
    • 一緒に有効にしたくない機能まで有効になる
    • ​新しいフラグを簡単に足せると良い
  • ​​​リリースしたらきちんとフラグを消す

    • うっかりすると無限にフラグが増える

    • うっかりするとリリース前に巻き戻る

気をつけること2

  • パフォーマンス影響をチェックする

    • 軽いバックエンドとアルゴリズムにする
      • Redis setはRWともO(1)、1~2ms程度
    • 繰り返し判定しない
      • 1msでも100回呼んだら100msになる
      • 判定結果をキャッシュすると良い

まとめ

  • 大きいリリースはFeatureFlagを使って
    小分けにデプロイすると便利

  • 小さいものでもFeatureFlagを使うと
    デプロイせずにリリースできて便利

  • 簡単にフラグを足せる/消せる仕組みを
    整備するのが必要

Feature Flagを利用したリリース戦略(エッセンシャル版)

By 黒曜

Feature Flagを利用したリリース戦略(エッセンシャル版)

社内交流会

  • 384
Loading comments...

More from 黒曜