kashinoki38 blog

something like tech blog

CloudNative Days 2021登壇 継続的な性能担保、DevPerfOpsという考え方

CloudNative Days Spring 2021 ONLINEというイベントに登壇した。

大変遅くなってしまったが書いておく。

event.cloudnativedays.jp

ちょっと登壇資料がまだ社内で手続き中でSlideShareアップロード待ちです。。

継続的な性能担保は必要だが難しい

まず継続的に性能を担保するのはかなり骨の折れることなのだと思っている。

リリースが何度も走るなかで性能品質を追いつかせていくにはちゃんとアプローチを決めて取り組んでいかないといけない。

DevPerfOpsとは

DevOpsの中でどうやって継続的に性能を担保するのだろうという疑問に対して、性能試験とリリース方式の2通りでアプローチを考えてみた。

とりあえずDevPerfOpsという単語を部署で唱え始めているところです。

f:id:kashionki38:20210330193341p:plain

こんなイメージを考えてみた。

f:id:kashionki38:20210330193357p:plain

Progressive Delivery

リリース時の性能リスク低減のアプローチとして期待できるのはProgressive Delivery。

Progressive DeliveryはCDの次のステップとして位置づけられた比較的新しいリリース方式で、従来のリリースに①リリース中の評価と②自動ロールバックを追加したもの。

カナリーリリースで少しずつトラフィックを流していき、問題があれば勝手に切り戻してくれるので、リリース時のリスク低減が可能というイメージ。

具体的なデプロイ時の流れは以下のFlaggerのドキュメントがわかりやすい。

docs.flagger.app

また以下の記事もわかりやすい

speakerdeck.com

qiita.com

medium.com

そして、CNDOでもFlagger, Argo Rolloutsで登壇されている方がいて興味深い。

event.cloudnativedays.jp

ツールとしては以下あたりが俎上に上がる理解。

PipeCDはどうか知らないが、FlaggerとArgo RolloutsはSevice Meshの機能を使ってトラフィック制御を実現している(要はIstioのVirtualService)。 なので、デプロイのされ方自体の機能差分に大きな差はなく、CDツール(FluxなのかArgoCDなのか)との連携やWebUIありなし(Flaggerはない)で選ぶことになると思う。

あとは、ArgoCDだとプライマリ昇格がローリングアップデートではなくServiceのEndpoint切り替えになるという話をCNDOの上記講演で聞いた。

諸々聞くと、Argo Rolloutsが良さそうに見えるが、なぜかFlaggerを最初に知ってしまい、Flaggerで検証してしまったw

結論、以下のようにカナリーリリースと最中の評価(Canary Analysisと呼ぶ)ができるので、ちゃんと事前に評価すべきメトリクスとその閾値を決めておきさえすればリスク低減の防衛戦として機能してくれそうとわかった。

f:id:kashionki38:20210330193518p:plain

もう少し細かいことが以下の記事にある(Podinfoというサンプルを使ったハンズオンを実施してみたの)

kashionki38.hatenablog.com

Progressive Deliveryの課題感

一方でなかなかうまく使うには考えることもあるなあと思っている。

妥当なSLI/SLOに基づいたしきい値使わないとね

サービスごとのSLI/SLOはもちろん事前に決めておく必要がある。

さらにそれは全体のSLAを考慮した上で妥当である必要がある。

これは結構難しいことなのでは、と思っている。

つまり、サービス全体とし決めたSLAを守るため、その構成要素として各サービスが他のサービスとの依存関係や用途を考慮した上で、どれくらいのSLOでないといけないのかを考えておく必要があるということ。

以下の記事が参考になるなと思いつつ、ここでは手に余るトピックなので議論のポイントとしてそっと置いておく笑

blog.newrelic.co.jp

engineering.mercari.com

いずれにしても、なんとなく決めたしきい値でリリースしてProgressive Deliveryの中でOKって出ても妥当じゃないよね、と思うので妥当感は何かしらに根付いて決める必要があるのかなと思った。

カバレッジ見ないとね

カナリーリリースをする際に、よく気になっていたのがいつどれくらいの時間かけてリリースするんですかね、である。

私の会社は大規模エンプラなので、結局本番はBlue/Greenでしょっていう感覚が強く、本番の日中帯にカナリーリリースするイメージがなかなか掴めない。

一方で、夜間帯の使われてないタイミングにカナリーリリースしてもなんの意味もないし、多少使われている時間帯でも数分でリリースしてしまったらそれって結局あんまりカナリーである意味ないのかな(ユーザフィードバック評価できたのかとか)と思うわけである。

ガスで苦しくなる前にカナリア引き上げてきましたwみたいな

Progressive DeliveryだとCanary Analysisが自動化されてしまうので、このリリースタイミングと期間の妥当性についても評価しておかないと、Canary AnalysisしましたOKです!って言われても信用ならないと思った。

CNDOの登壇の中でNewRelicの方がカナリーリリースを活用してリリースリスクを軽減するという話をObservabilityの管理力という文脈で説明されていたので、DIscordで質問してみた。

カバレッジの評価といういい単語をいただけた。なるほど、カバレッジはたしかに評価しないといけない。トラフィック量とURLやサービスベースでのカバレッジProgressive Delivery時の評価指標として取れているとさらに良さそうと思った。またどれくらいの期間かけてリリースしていくのかも普段のトラフィック量に応じて柔軟に決めるのだろう。

event.cloudnativedays.jp

f:id:kashionki38:20210330193548p:plain

Kubernetesリソースデプロイ時の自動負荷試験

さてもう一つのアプローチ自動負荷試験について入っていく。

こちらのブログや

amaya382.hatenablog.jp

こちらのブランチ戦略に関するポスト参考に、

qiita.com

GitOpsのブランチ戦略上のどのタイミングに負荷試験を自動で挟むかの想定を以下のように考えた。

f:id:kashionki38:20210330193623p:plain

つまり、機能試験担保済みのブランチでGitOpsのSyncがされたタイミングで自動で負荷試験が走るというイメージ。

で、こういったサンプルを作ってみた。

f:id:kashionki38:20210330193641p:plain

sock-shop をサンプルアプリとして、Observability と負荷試験自動化スタックを追加したもので、若干雑ながらも以下リポジトリに手順含めて置いたのでぜひ使ってみもらえれば。

github.com

残念ながらGitOpsは入れてないので、kubectl等でデプロイした段階からの開始イメージ。(Flux入れたとしても同じ用に動くはず)

フロートしては以下のように動いてくれる。

f:id:kashionki38:20210330193711p:plain

言ってもほとんどFlaggerががんばってくれるのだが、Jmeter化する部分は多少色々やった。

configMapGenerator:
  - name: jmeter-scenario-load-test
    files:
      - scenario.jmx
webhooks:
  ...
  - name: load-test
    url: http://jmeter-flagger-loadtester.jmeter/
    timeout: 5s
    metadata:
      # /jmeter/apache-jmeter-*/bin/jmeter -n -t $1 -Dserver.rmi.ssl.disable=true -JServerName=$2 -JNumOfThreads=$3 -JRampUp=$4 -JDuration=$5 -JTPM=$6
      cmd: '/bin/bash /load_test /scenario.jmx "front-end-canary.sock-shop" "50" "180" "600" "3000"'

これにより、事前にJmeterのシナリオを作っておけばリソースデプロイ後に自動で負荷試験が走って評価も自動で実施してくれるようになった。

実際に、2秒のスリープを仕込んだ上で、2秒しきい値として設定しておくと以下のように失敗(Halt)のメッセージがでて、

f:id:kashionki38:20210330193808p:plain

Slackにも失敗のメッセージが。(そっけないw)

f:id:kashionki38:20210330193816p:plain

これをベースにprdブランチへのマージを判断するようにすれば良い。

自動負荷試験の課題

こちらも同様に課題や考慮すべき点は多い。

リソース効率が悪い

試験環境が一時的にBlue/Greenで更新されたターゲットのPodが2倍用意されてしまうので、更新リソースが多いとリソースを多く消費してしまう。

定期的にどばっとリリースするというユースケースの場合、これだとあまりフィットしないなという率直な感想。その場合は、2週間に1回とかで性能試験用のクラスタを再作成して、そこで負荷試験するというのが自動化されているほうが便利なのではなかろうか、、

そうすると、今回のFlaggerを用いた方式は、リリース頻度が日単位未満でがんがんリリースされるようなユースケースではないか。クラスタをいちいち作るのは時間がかかるので、更新差分があるリソースだけBlue/Greenで立てて性能試験するという感じ。

さらなる自動化が不可欠

上記のそっけないSlackからわかるように、試験結果連携や整理には高度化が必須である(重要グラフ添付、結果のアップロード)

むしろそういった部分をなしにして自動化と歌ってしまっている今回のセッションは乱暴である。。。

また、負荷試験には実施や評価だけでなく、データ準備、負荷モデル、シナリオ作成が非常に重要なウェイトを占めており、この部分をなんとか自動化していかないことには、本質的に性能担保を継続的に回帰的に実施していくことは難しいと思う。

SwaggerによるAPI Documentからシナリオを自動で作る、普段の監視から負荷モデルを自動でつくる(Progressive Deliveryの部分におけるカバレッジと被るだろう)、試験のたびにDBのデータをあるスナップショットにする、といった周辺自動化も合わせて実施してやっと自動負荷試験と呼べる気がしている。

そんなOperator落ちてないですかね、

他のフェーズでの性能担保対応

セッション中の質問でもいただいたが、性能試験は負荷試験だけじゃなく、単体性能試験や長時間負荷試験などのバリエーションがある。

これらにも対応してまるっと性能担保を継続化するというのが最理想なのかなとは思う。

難しくなく実施できそうなのは、CIのコンテナイメージビルド時に単体性能試験(単API試験)をするとかだけど、よく考えるとUnit Test時に時間も測定しておくということのほうがよほど大事なのかもしれないと書きながら思ってしまった。

まとめ

まあ、そんなこんなで相当乱暴ながらDevPerfOpsというものを考えて、アプローチを検討してみた。

まとめると、

といったところ。

上述してきたように課題や考えるべき点はまだまだあるが、継続的な性能担保という考え方(ついでにDevPerfOpsも)が重要なポイントとして議論される日を祈って、その一助となれば嬉しい。

皆さん現場でうまく工夫されていることと思うのであれですが、一部でも参考にしてDevPerfOpsしてもらえると嬉しいです。