HRBrainの人事評価サービスにおけるSLO運用

この記事は HRBrain Advent Calendar 2021 10日目の記事です。

qiita.com

はじめに

こんにちは。主に人事評価サービスのバックエンド開発や運用を担当している@tonarinoheyです。

筆者の2021年ベストバイはMINIクラブマン クーパーSDです。私事ですが、1歳になる長男が無限中耳炎編に突入しており、勤務中に中抜けして通院するのが最近のトレンドです。助けてくれ。

さて、HRBrainにおいて最も運用期間が長いサービスである人事評価サービスにおいて、開発チームは今年度からサービスレベル目標 (SLO) を定めています。運用を始めたばかりなので、今回は主にSLO運用に至った背景や、サービスレベル指標(SLI)・SLOをどのように決めたかご紹介します。

導入経緯

人事評価サービスが今後も利用テナント数を増やし、稼働継続しながら新たな機能追加が続くことを前提とした場合、サービスが信頼性を保ったまま動作していることを定量的に評価する必要があります。その評価なしには、機能追加を続けてよいのか、はたまた信頼性を高めるべきなのか判断ができないからです。

前提

サービスの状態監視を目的として、すでに運用している施策があります。

  • Datadogを用いたメトリクス監視

    • APIエンドポイントごとのリクエスト数、エラー率やレイテンシをはじめ、kubernetesのPodやCloud SQL、Memorystore for Redisの状態、Core Web Vitalsなど各種メトリクスを監視している。
    • Dashboardにグラフを集めて一覧できるようにしている。
  • DatadogとSlackの連携

    • サーバーのレイテンシやエラー率、外形監視の結果などが閾値を越えた場合にSlackへ通知を流す。
  • PagerDutyの導入

    • 営業時間外における障害発生に対応するため、Datadogで異常を検知した際にPagerDutyによって、エンジニアが携帯するスマートフォン端末に発報する。

やったこと

健康診断の実施

かの有名なGiorno Giovanna*1も「自分を知れ……」と言っています。First Stepとして、私たちは現状認識を目的とした人事評価サービスの健康診断を実施しました。健康診断の目的を下記に示します。

  • 可用性の観点において、今後問題に発展しそうな”予兆”を見つける。
  • ”予兆”に対する「次の一歩」を決める。

診断を下すためには判断材料と根拠が必要です。私たちはすでにDatadogでサーバー、クライアントの各種メトリクスを継続的に監視していました。監視対象は多岐にわたります。監視項目すべてを精査すると膨大な時間を消費してしまうため、健康診断は参加者が気になった点を各々提起する方法で進めました。言うなれば、1日がかりの人間ドックでなく、1時間の健康診断といったところです。

その結果、現状のパフォーマンスベースで気になる点がいろいろ洗い出せました。以下はその一例です。

  • 特定の処理を大量に実行するため、数秒間で数百回叩かれているAPIがある。一括で実行できるエンドポイントを生やしてはどうか。
  • 他のAPIと比較して、極端にエラー率が高いエンドポイントがいくつかある。APIのエラー率に閾値を設け、それを上回るエンドポイントは優先的に改善していきたい。
  • context.Canceled*2が500になり、サーバー監視のノイズになっている。クライアントから切断された場合、ステータスコードは5xxでなく、たとえば499*3などに変更したい。

この取組みによって、私たちは自分たちが提供しているサービスの健康状態をある程度理解できました。では、この健康診断で見つかった"予兆"に注目してSLOを決めるべきでしょうか? 

いいえ、現在のパフォーマンスのみに基づいてSLOを定めるべきではありません。Jonathan Mercereau*4によれば、SLOとは「サービスのSLIが仕様から外れてもよい頻度に関するSREとプロダクト所有者との合意」です。SLOにはプロダクトのビジョンやビジネス事情を反映すべきです。

健康診断の結果はSLOを考える材料のひとつになり得ますが、それ自体がただちにSLOを導くわけではありません。

サービスにとって最も品質を維持したい要件を考える

プロダクトのビジョンやビジネス事情をSLOに反映するため、エンジニアとPdMとで卓を囲んでアクティビティを行いました。

アクティビティの目的は「サービスにとって最も品質を維持したい要件を洗い出す」です。機能不具合や低品質なUXがもたらすビジネスインパクトにはグラデーションがあります。参加者はサービスにとって特に重要となる機能やUXを考え、それを記した付箋をオンラインホワイトボードツール上に貼り付けました。その一部を下図に示します。 f:id:tonarinohey:20220316160940p:plain

各自の意見を記した付箋が十分貼り出されたあと、私たちはそれらをいくつかの要件に分類しました。

  1. ユーザーが時間をかけて入力したデータが保存失敗してはならない
  2. 一括処理が中途半端に失敗するようなことはあってはならない
  3. 画面の読み込みに失敗してはならない
  4. 画面のレンダリングはスムーズであるべき
  5. その他

上記は、「サービスにとって最も品質を維持したい」要件の優先順位(1が最高)です。この順位もPdMとエンジニアとで検討して決めました。具体的に説明すると、1は評価保存などの保存系機能、2は催促メールの一括送信などの一括処理系機能、3と4は画面表示機能に関わっています。

SLIを決める

この4要件を満たすために監視が必要な機能を列挙し、それらについてメトリクスを収集します。私たちは、特定条件を満たす機能群の高可用性が保証できれば、各「サービスにとって最も品質を維持したい」要件も満たしうると仮説を立てました。

下記は、「サービスにとって最も品質を維持したい」要件と、各要件を満たすために監視する必要がある機能の条件を示しています。

  • 要件1:ユーザーが時間をかけて入力したデータが保存失敗してはならない

    • 条件:画面から入力されたデータを保存する機能である
    • 条件:入力されるデータ量が大きい
    • 条件:作業の認知負荷が大きい
    • 条件:人事評価サービスに固有の機能である(HRBrainが提供している別のサービスで実現できない)
  • 要件2:一括処理が中途半端に失敗するようなことはあってはならない

    • 条件:一括処理を担う機能である
    • 条件:失敗のリカバリコストが大きい
    • 条件:人事評価サービスに固有の機能である(HRBrainが提供している別のサービスで実現できない)
  • 要件3:画面の読み込みに失敗してはならない

    • 条件:画面表示機能である
  • 要件4:画面のレンダリングはスムーズであるべき

    • 条件:画面表示機能である

私たちは人事評価サービスの全機能を網羅したリストを用意し、これを星取り表として上記条件を満たす機能を洗い出しました。条件を満たすかどうかの閾値はある程度定性的に設定せざるを得ませんでしたが、それを差し引いても星取り表の存在は、監視対象の機能がMECEに導かれていることを示す資料になり得ると考えています。

星取り表のイメージを下図に示します。 f:id:tonarinohey:20220316161139p:plain

洗い出しの結果、SLIは下記のように定めました。

  • 更新系エンドポイントそれぞれのエラー率
    • 条件を満たしたエンドポイントは約10種類。
    • エンドポイントはワイルドカード等で集約せず、1つずつ監視する。「ユーザーが時間をかけて入力したデータが保存失敗してはならない」が最も品質優先度の高い要件であり、集約してしまうことでエラー検出の偽陰性を避けたいから。
  • 参照系エンドポイントを集約したエラー率
    • 参照系エンドポイントの多くは何らかの画面表示時に叩かれている。画面表示関連の要件は品質優先度が相対的に低いため、一旦集約し全画面平均として扱う。
    • SLO違反の主原因となりうるエンドポイントを認めた場合、そのエンドポイントを切り出して別途監視する想定。
  • LCP(Largest Contentful Paint)
    • 実際にユーザーが開いたWebページのメインコンテンツが読み込まれるまでを計測したRUM(Real User Monitoring)。
    • Googleが公開している基準*5に準拠し、全ページビューの75パーセンタイル値が4secを越えた場合を「悪い」と判定する。

私見としてSLIの数がやや多い点に運用懸念があるものの、品質優先順に基づくSLOのPriorityによってエラーバジェットポリシーを調整すれば良いと考えています。結果的にサーバーの性能監視に閉じることなくUXも考慮したバランスの良いSLI設計ができたと言えるのではないでしょうか。

SLOを決める

各SLIにターゲット値(SLO)を設定します。各SLOのローリングウインドウは7日間と定めましたが強い根拠はありません。ターゲット値とあわせて定期的に見直していく予定です。

  • 各更新系エンドポイントのエラー率

    • SLO:99.5%
    • リクエスト200回あたり1回の更新失敗を許容する計算となるが、まずは達成することを目標とし、低めに設定している。
    • 将来的に99.9%までの引き上げを目標とする。
  • 参照系エンドポイントを集約したエラー率、LCP

    • SLO:99.0%
    • これらについても、達成を目的として初回は低く設定した。

これからやること

Datadog上におけるLCPのSLO運用

2021年12月現在、DatadogのSLO MonitorはRUMをソースとして選択できないため、APMや外形監視と異なりLCPに対してターゲット値を設定してSLO運用できません。UXを考慮した指標であるLCPのSLO運用は断念したくないので、何か方法を考えたいと思っています。Lighthouseを利用してLCPを取得しカスタムメトリクスをDatadogに送信する方法*6など検討してみるつもりです。いえ、SLO MonitorでRUMを扱えるリリースが来れば全部解決するのですが……。

エラーバジェットポリシーの作成

この記事を執筆している時点では、まだエラーバジェットポリシーを策定できていません。SLO違反にともなうエラーバジェットの消費状況に応じて、開発チームがリリース頻度を下げるか一時的に停止した上でパフォーマンス改善にリソースを割く取り決めを定め、チーム内で合意形成しておきたいです。

開発チームを巻き込んだSLOの活用とフィードバックループ

人事評価サービスは開発チームが新規機能開発と運用を担当しています。本サービスのSLO運用は筆者が単独で進めており、チームへの十分な共有や、上述のエラーバジェットポリシーに関する合意形成ができていません。これから、SLOをチームで意識し、定期的にSLIとあわせて見直していくフィードバックループを回していきます。

おわりに

SRE本かじった程度の初期アバターも同然な筆者が、曲がりなりにもSLOを定めて運用を始められたのは、弊社がトライドリブンで物事を進められる環境だと思います。SRE経験豊富なエンジニア*7も在籍するHRBrainで、一緒にデータドリブンな開発をしませんか? 

もしご興味があれば下記ページからご応募ください!! www.hrbrain.co.jp

*1:『ジョジョの奇妙な冒険』第5部参照。

*2:右記リンク先を参照。 https://zenn.dev/bellwood4486/articles/grpc-cancel-timeout

*3:ステータスコード499はnginxの独自ステータスコードであり、RFCによって定義されたものではありません。詳しくは右記リンク先を参照。 https://stackoverflow.com/questions/46234679/what-is-the-correct-http-status-code-for-a-cancelled-request

*4:『SREの探求』5章参照。

*5:右記リンク先を参照。 https://web.dev/i18n/ja/defining-core-web-vitals-thresholds/

*6:右記リンク先を参照。 https://zenn.dev/ryo_kawamata/articles/webperf-watcher

*7:残念ながら筆者ではありません。