Feature Flagを利用したリリース戦略
黒曜
@kokuyouwind
$ whoami
-
森 俊介 / 黒曜
-
@kokuyouwind
-
株式会社Misoca
-
SRE
本番リリース
スモールリリース
-
アジャイルプラクティス
-
小さく、高頻度にリリースする
-
素早く価値を届けられる
-
フィードバックを速く得られる
-
開発メリット
-
変更粒度が小さくなることで……
-
コードレビューしやすくなる
-
コードが衝突しづらくなる
-
問題の原因特定がしやすくなる
-
😆
とはいえ…
-
現実にはそう簡単にいかないときもある
-
プレスリリース合わせで全部出す
-
ちょっとずつ出すとデータ不整合
-
一揃いの機能がないとUXが悪い
-
etc...
-
🤔
ビッグバンリリース
FeatureFlag
-
機能を動的にOn/Offできる仕組み
-
ある環境でだけ有効にする
-
あるユーザにだけ有効にする
-
管理者が全体の有効/無効を切り替える
-
etc...
-
FeatureFlagのメリット
-
一般ユーザに見せないコードを入れられる
-
一般公開と別の単位でリリースできる
-
公開前の機能を本番で試せる
-
-
様々な目的に利用できる
-
カナリヤリリース
-
A/Bテスト
-
etc...
-
というわけで
FeatureFlagの話をします
アジェンダ
-
FeatureFlagの基本と分類
-
MisocaでのFeatureFlagの使い方
-
まとめ
アジェンダ
-
FeatureFlagの基本と分類
-
MisocaでのFeatureFlagの使い方
-
まとめ
FeatureFlag
if feature_enabled?
process_with_feature
else
process_without_feature
end
-
機能を動的にOn/Offする仕組み
- 真偽値を返す関数とif文の組み合わせ
基本はこれだけ
feature_enabled?
-
システム全体で共通
-
デプロイ時
-
ホットリロード
-
-
リクエストごとに判定
-
特定ユーザにだけ機能を有効化
-
特定割合のユーザに機能を有効化
-
特定属性のユーザに機能を有効化
-
feature_enabled?
-
設定管理の方法は色々
-
環境変数
-
設定ファイル
-
KVS
-
クラウドサービス
-
etc.
-
FeatureFlagの分類
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
FeatureFlagの分類
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
リリーストグル(Release Toggls)
-
リリース前機能を隠すための分岐
-
不完全なコードのデプロイ
-
デプロイとリリースの分離
-
-
短期(リリースしたら消される)
-
静的(環境全体の設定)
FeatureFlagの分類
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
実験トグル(Experiment Toggls)
-
実ユーザで機能を実験するための分岐
- マルチバリエイト分析
- A/Bテスト
-
短期〜中期(実験期間による)
-
動的(ユーザコホートごとに振り分ける)
FeatureFlagの分類
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
運用トグル(Ops Toggles)
-
性能をコントロールするための分岐
- パフォーマンス影響を見て機能デグレさせる
- 過負荷時の高負荷機能オフ
-
中期〜永続(上記のいずれの目的かによる)
-
静的(環境全体の設定)
FeatureFlagの分類
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
許可トグル(Permission Toggls)
-
特定のユーザに提供機能を変える分岐
- プレミアム機能
- α テスト / β テスト
-
長期〜永続
-
動的(リクエストごとに振り分ける)
同じバケツで管理しない
-
すべてのFeatureFlagを同じ仕組みで管理するのは危険な道
-
カテゴリごとに異なる設計を要する
-
同じ方法で管理すると、将来の痛みにつながる
-
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
個人的見解
-
短期的なFeatureFlagでの静的/動的の別はさほど重要ではない
-
柔軟に管理できたほうが便利
-
内部ユーザでの動作確認
-
カナリヤリリース
-
-
短いスパンで消えるコードなので管理上のつらさも表面化しない
-
アジェンダ
-
FeatureFlagの基本と分類
-
MisocaでのFeatureFlagの使い方
-
まとめ
MisocaでのFeatureFlag
Feature Toggles (aka Feature Flags) / Pete Hodgson https://martinfowler.com/articles/feature-toggles.html
主にこのへん
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
比率での有効化
class Misoca::FeatureFlag::Target
def enable_percentage(percent)
current_segments = redis.smembers(segment_key)
unused_segments = ALL_SEGMENTS - current_segments
diff_percent = percent - current_segments.count
diff_percent.positive?
? redis.sadd(segment_key,
unused_segments.sample(diff_percent))
: redis.spop(segment_key, diff_percent.abs)
end
end
Misoca.feature_flag.enable_percentage(50)
有効判定
有効化したユーザ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改善
いける!
利用者の声
富山県 30代会社員
H.Mさん
デプロイとリリースが競合しないので
予想外のトラブルを避けられますし、
ロールバックも本当に簡単でした。
分岐処理を後から徐々に外せるのも良いですね。
不満は一切ないです。
FeatureFlag最高!
※効果には個人差があります
気をつけること
-
汎用のフラグを使わない
- FeatureFlagを外すときに大変
- 一緒に有効にしたくない機能まで有効になる
- 新しいフラグを簡単に足せると良い
-
リリースしたらきちんとフラグを消す
-
うっかりすると無限にフラグが増える
-
うっかりするとリリース前に巻き戻る
-
気をつけること2
-
パフォーマンス影響をチェックする
- 軽いバックエンドとアルゴリズムにする
- Redis setはRWともO(1)、1~2ms程度
- 繰り返し判定しない
- 1msでも100回呼んだら100msになる
- 判定結果をキャッシュすると良い
- 軽いバックエンドとアルゴリズムにする
アジェンダ
-
FeatureFlagの基本と分類
-
MisocaでのFeatureFlagの使い方
-
まとめ
まとめ
-
大きいリリースはFeatureFlagを使って
小分けにデプロイすると便利 -
小さいものでもFeatureFlagを使うと
デプロイせずにリリースできて便利 -
簡単にフラグを足せる/消せる仕組みを
整備するのが必要