kubell Creator's Note

ビジネスチャット「Chatwork」のエンジニアのブログです。

ビジネスチャット「Chatwork」のエンジニアのブログです。

読者になる

とあるサブシステムにおけるSLOへの登り方

こんにちは。藤井 @yoshiyoshifujii です。

この記事は、 Chatworkのカレンダー | Advent Calendar 2023 - Qiita の 5日目です。

今回は、私が担当しているとあるサブシステムにおいて、SLO ( Service Level Objective ) をどのように設定し、運用に持っていくか、その登り方を紹介したいと思います。

以前、 SRE NEXT 2023 で、 「プロダクトオーナーの視座から見た信頼性とオブザーバビリティ」 というタイトルで発表させていただきました。 当日は、取り組んでいることを事実ベースでお話させていただきました。 この記事では、プロダクトオーナーとしてどう登っていく判断をしていったかの考えのベースのあたりを紹介できればと思います。

  • SLOをどうやって設定するといいのか
  • 運用ってどうやって回すといいのか

と考えておられる方の何か参考になれば幸いです。

私たちも絶賛試行錯誤中ですので、共有し合えるものが何かあればいいですね。

CUJ をチームで理解できたといえる

CUJ ( クリティカルユーザージャーニー ) とは…

特定のユーザーが提供するサービスを利用して目的を達成するために実行する特定の手順

例えば、「ユーザーが購入手続きボタンをクリックし、カートが処理されて領収書が返されるレスポンスを待ちます。」といったことです。

ユーザーにとって最も頻繁に行う作業や、重要な一連の操作をCUJとして選定します。

Chatwork で言いますと、 「ユーザーがグループチャットにメッセージを投稿すると、メンバーに未読メッセージが届いていることをリアルタイムに知らせる」といったあたりが考えられます。

このように CUJ を言語化し、チーム内で浸透するまで議論します。

担当するサブシステムによって、上記の CUJ に対して関心が異なります。

上記の一文にも、「発信者」の関心と「受信者」の関心が同居しています。

「受信者」も「リアルタイム」という概念を実現する手段は異なります。

外出中であれば、モバイルプッシュ通知で受け取りたい、デスクでWebブラウザを開いているなら、デスクトップ通知で受け取りたい、などです。

チームがいま取り扱うサブシステムやコンポーネントにおいて、このCUJの何が満たされないとユーザー満足度の低下に繋るのか。

これを議論し見出していきます。

無数にあるとは思いますが、その中から、まずはこれをやろうといったところに絞り込んでいく決定が必要です。

CUJ の満足度を測定できていると言えるメトリクスが明確になる(SLI)

CUJ をチームで議論する過程で、サブシステム内のどこの何を計測することがユーザー満足度低下を防ぐために必要か、を考えます。

チームが担当する領域が、「受信者」に寄っている場合ですと、受信者の方の視座から見てリアルタイムに受け取れているなーと感じられるには、サブシステム内のどのあたりのコンポーネントが適切な値を記録するのかどうかを考えます。

最初は、チームの担当領域で考えて、徐々に越境していくことを考え、ユーザーから見た満足度に直結していく登り方を取っています。

SLI を計測できる

SLI は、 Open Telemetry に基づいてアプリケーションから収集します。

Span Attributes に高カーディナリティ、高ディメンションの値を埋め込みます。

その中から、 「前段のサブシステムのドメインイベントが書き込まれた日時」 をピックアップします。

この日時を前段のシステムのドメインイベントから取得できるようにしておき、 Consumer にて取り出します。

後続の Write API を呼び出すとき、 Header に埋め込んで連携します。

Write API では、Header からその値を取り出し、Domain Eventに書き出す際に Meta 情報として埋め込みます。

Read Model Updater で値を取り出し、 Span Attributes に 「前段のサブシステムのドメインイベントが書き込まれた日時」として吐き出します。

このような仕込みを一連のコンポーネントにコーディングして、 Honeycomb に Trace として送ります。

Honeycomb 上では、 Derived Column という特定の Span Attributes を計算して、別の Span Attributes として扱える機能があります。

これらの機能を駆使して、「前段のサブシステムのドメインイベントが書き込まれてから、Read Model Updater が処理を終えるまでの経過時間」を見える化します。

さらに、この経過時間について、目標値を設定し、その目標値以内であればtrue、越えていたらfalseとなるような Boolean を返す Derived Column を作ります。

これらの経過時間と Boolean を用いて、 SLO を設定します。

とりあえずSLOを設定する

SLI をしばらく観察して、 なんとかなりそうなレベルで SLO を設定します。

最初は、ゆるくていいと考えています。

SLI を 「3000ms以内 であればtrueとする」 としたり、その率が 95% におさまるようにするといったあたりで設定します。

さらに1週間なり、2週間なり、いったん設定した SLO を観測し続けます。

その中で、 エラーバジェットの減り方の傾向を見たり、外れ値がどの頻度で発生するのか見たり、ボトルネックになっている箇所を特定したりと、分析を繰り返します。

ある程度、ここが怪しいと目星をつけたら、 「品質スプリント」 を計画します。

SLOの確率を上げる

書籍 アジャイル品質パターン「QA to AQ」 伝統的な品質保証からアジャイル品質への変革(CodeZine Digital First) 電子書籍(Joseph Yoder Rebecca Wirfs-Brock Ademar Aguiar 鷲崎 弘宜 鷲崎 弘宜 長谷川 裕一 濱井 和夫 小林 浩 長田 武徳 陳 凌峰)|翔泳社の本 の中で 「品質スプリント」が紹介されています。

ソフトウェアの品質に焦点を当てる時間を取り、品質特性の測定と改善に特化したスプリントにします。

ボトルネックに対して、仮説を立てて、それを解消することのみに焦点を当ててスプリントを実施します。

ゆるいSLOでも達成できていない (たとえば、95%を設定しているのに、90%になっているとか) のであれば、なんとか、95%になるためにいろいろと取り組みます。

SLIの計測に問題があるなら見直します。

アプリケーションのロジックや、そもそものアーキテクチャ上の検討不足なら、それを解消することを目指します。

チューニングになってくると、際限ないラインが出てきますので、期間を決めて取り組みます。

3スプリントと決めたら、その範囲で出来ることに焦点を当てます。

目的は、SLOの確率を上げることとし、そのことに必要なことを、期間を決めて取り組みます。

SLIを厳しくする

95%を目標にしているのが、99%まで改善できたとしたら、次は、SLIを厳しくします。

「3000ms以内であればtrueとする」条件について、「1500ms以内であればtrueとする」といったSLIに変更します。

そのうえで、99%から、95%まで下がるあたりの下げ幅を見たり、エラーバジェットの消費傾向を確認したり、次のボトルネックを見出していきます。

週に1回みんなで眺める

監視から気付くことができれば御の字ですが、それでも特定が困難であるなら、チームのみんなで、SLOを入口にして色んな視座で眺めてみましょう。

JVMはどうだろうか。スレッドは枯渇していないだろうか。ネットワークが不調な時間帯とかだったのだろうか。AWSのメトリクスで跳ねていることはないか。

あらゆる可能性について、様々なメトリクスやログを見ていきます。

このとき、取れていない情報があるならば、追加していきましょう。

そうやって、SLOをベースに改善のサイクルを回していくことが、ユーザー満足度を低下させないシステム作りに欠かせないのではないかと思います。

まとめ

CUJからSLIを出して、まずはゆるくSLOを設定し、確率を上げてから、SLIを厳しくして、SLOの変化を観測しようね、ということを書いてみました。

いまのところ、この取り組みを、1つのサブシステムにおける、1つのCUJについてSLIを1つ設定し、取り組んでいるところです。

ここが安定してきたら、CUJをそのままに別のSLIを検討するか、別のCUJを取り上げるかといったことで、観測するSLOを増やしていき、ユーザー満足度を保ちながら、生産性の維持・安定にアプローチしていきたいと考えています。

このような信頼性について一緒にチャレンジしていただけるエンジニアを広く募集しております。

recruit.chatwork.com

ぜひぜひよろしくお願いいたしますー