PERSOL MIRAIZのプロダクト主導によるSLO策定について #PERSOL CAREER Advent Calender2025

はじめに

はじめまして。今年のDeveloper&Designer Advent Calendar 2025の3日目を担当するPERSOL MIRAIZエンジニアリンググループ SREチームの増田です。

PERSOL MIRAIZ(以下、MIRAIZ)は、今後のキャリアや学習についてアドバイスを受けたうえで、実際に学習講座を受講し、キャリア相談および学習結果を踏まえて転職支援を受けるといった一連の体験を、すべて無料でご利用いただけるサービスです。

SREチームでは、開発チーム向けのインフラ構築支援や障害対応、ガバナンス対応など日々幅広く活動をしています。 本記事では、MIRAIZにおいてService Level Objective(SLO)の策定に至った背景や策定までの具体的な進め方、計測部分の技術を紹介したいと思います。

※ 本記事ではSLOなどSREに関連する具体的な用語の説明までは行いませんので、ご了承ください。

SLO策定背景

MIRAIZでは、ユーザーがサービスに対して当然のように期待する品質である当たり前品質を毀損している可能性のある事象が発生していました。 具体的には、以下のような事象が挙げられます。

  • 企画からMIRAIZのページ表示速度が遅くないかとの声
  • ユーザーからのお問い合わせで発覚した機能不具合

当然、ページの表示速度が遅いサービスや大事な機能がエラーになるサービスはユーザーからしたら使いたくありません。そのため、サービス提供者は、これらの当たり前品質を維持する必要があります。

しかし、当たり前品質は人によって基準が全く異なります。ページの表示速度一つをとっても、「何秒なら当たり前品質が守れていると言えるのか」という問いの答えは、部門や担当者によって異なるでしょう。

このように、当たり前品質というものはユーザーにとっては非常に大切であるにもかかわらず、サービス提供者側では非常に曖昧なものといえます。この曖昧さゆえに、当たり前品質に関するチーム間での共通認識の形成が難しく、品質改善のための優先順位付けや判断が後手に回ってしまいます。 後手に回った結果、事業として達成したい目標の未達成やユーザーの離脱などビジネス指標に影響を及ぼす可能性があります。

そこで、当たり前品質に対してサービス提供者側で共通言語となるSLOを策定することで、品質が守られている/守られていない水準を明確にすることが打ち手として有効ではないかと考えました。

SLO策定背景の説明資料

SLO策定の進め方

前述した背景の通り、我々はSLOの策定に動き始めました。 策定にあたっては、Developer&Designer Advent Calendar 2025の1日目に寄稿している品質推進部の吉次さんに相談したり、SREに関連する書籍や他社のSLO策定事例の記事を読むなどして、キャッチアップを行いました。

SLO策定は以下のような流れで進めていくことになりました。

  1. 当たり前品質の洗い出し
  2. SLIの選定と計測
  3. SLOの設定
  4. エラーバジェットに基づいた行動アクション定義

SLOはサービス提供者側の当たり前品質の対する共通言語となるため、エンジニアだけではなく、ビジネスサイドのステークホルダーとも合意をしつつ進める必要があります。

❌うまく行かなかった進め方

SREに関連する書籍などでは、SLOを策定していく過程からエンジニアだけではなく、ビジネスサイドのステークホルダーも巻き込みつつ進めることが推奨されていると思います。 我々も同様に、当たり前品質の言語化からビジネスサイドのステークホルダーを巻き込んでディスカッションしながら進めることを検討していました。 しかし、SLO策定の施策をステークホルダーの方に頭出ししたところ、「施策の価値は認めるものの、叩き台を作成して欲しい」といった要望をいただく形となりました。

この結果は、以下の理由から、ステークホルダーの立場に立って考えると、妥当です。

  • SLOの概念の難しさ: 「SLO策定」というテーマは、SREの専門用語であり、エンジニア以外のステークホルダーにとっては直感的にわかりにくいです。
  • 時間の確保の困難さ: ステークホルダーを議論に巻き込むことは、貴重な業務時間をいただくことに相当します。明確なアウトプットのイメージがない初期段階での議論参加は、負担が大きくなってしまうのではないかと考えます。

この経験を踏まえ、我々の進め方を変更しました。 SREチームが主導でSLOの叩き台を策定し、その具体的な案をもとにステークホルダーとディスカッションするやり方に切り替えました。このアプローチにより、ステークホルダーには、具体的な数値や指標に基づいて、より建設的な議論が可能なのではないかと考えました。

✅叩き台ベースの進め方

叩き台の作成

SREチームでは、以下の4ステップで叩き台を作成しました。

1. 当たり前品質の洗い出し

SREチームでは、まずはじめに、MIRAIZにとっての当たり前品質とは何かを洗い出しました。 ビジネスサイドの方がすでに作成してくださっていたカスタマージャーニーマップをベースに、ユーザー視点で〇〇ができないとサービス利用ユーザーは不満に感じるのではないかという観点でいくつか洗い出しました。

ユーザーにとってのゴール ユーザーのタスク ユーザーにとって特に重要なこと
TOPページでコンテンツとサービスを理解する 外部からTOPにアクセスする TOPページが快適に見れること
キャリア相談に予約を行う ・キャリア相談予約ページにアクセス
・フォームに相談情報を入力して予約ボタンを押下する
キャリア相談に予約ができていること

2. SLIの選定と計測

次に、洗い出した当たり前品質の中で、ユーザーにとって特に重要なことをService Level Indicator(SLI)として、どのようにシステム上で計測するかを考えます。 我々の場合、オブザーバビリティツールとして、Datadogを導入しているので、計測はDatadogをベースに考えます。

ユーザーにとって特に重要なこと SLIの項目 SLI計測方法
TOPページが快適に見れること 可用性 特定のURLに対するDatadog Syntheticsテストにおいて、5分間の中で一度も失敗しなかったタイムスライスの割合
ページ表示速度 特定のページをDatadog Real User Monitoring(RUM)で計測したLCP75パーセンタイルが5分間の中で2.5秒以下のタイムスライスの割合(LCPについてはこちらを参考にしました)
キャリア相談に予約ができていること 可用性 APIに対する全体リクエストに対し、HTTPステータスコード5xx(サーバーエラー)でないレスポンスの割合

これらをDatadog上で計測可能な状態にし、30日間程度計測を行いました。 なお、具体的な計測するための技術部分については後述しますので、ここでは割愛します。

3. SLOの設定

次に、SLOの設定を行います。SLIの計測結果をもとに、現実的なラインでSLOを設定しています。 例えば、100%のSLOを設定したり、30日間のリクエスト数が100件しかないAPIのリクエスト成功率SLOを99.99%に設定するのは現実的ではありません。

我々の場合、以下のようなコミュニケーションを行い、SLOを設定しました。 - 既存の非機能要件と照らし合わせて妥当な値を設定 → 例: 非機能要件で可用性が99.9%と定義されているので、SLOも99.9%と定義する - 直近1ヶ月間で計測された現状の成功率を「守られている水準」と仮定し、そこから少し余裕を持たせた現実的な値を設定 → 例: 直近1ヶ月間の成功率が97.5%なので、SLOを少し余裕を持たせて97%と定義する

正直、SLOの設定値はどの値が妥当なのかはすごく悩むポイントでした。 ただ、ここで時間をかけるよりも、一旦SLOを決めた後、定期的な振り返りを行い、実際のサービス運用状況に応じて変更していくことの方が大切だと考えています。

加えてこの段階で、Datadog上のSLOダッシュボードも作成しました。

4. エラーバジェットに基づいた行動アクション定義

最後に、エラーバジェットの考え方に基づいて、行動アクションを定義します。 例えば、エラーバジェット枯渇時にリリースを一時停止するといったやり方があります。 ただ、我々の場合、SLOの文化がステークホルダー間を通して浸透していない中で厳しめのルールを課すことは初期段階では現実的ではないと判断しました。 まずは、枯渇の有無ではなく、消費スピードであるバーンレートに着目し、行動アクションを定義することとしました。

アラート 目的 緊急性 行動アクション
Fast Burnアラート 短期間での急激なエラーバジェット消費を検知する。 高: 「数日でバジェットが尽きる」状況 SREチームが即座に一次調査を実施。必要に応じて開発チームへの対応依頼やビジネスサイドへの事象連携を行う。
Slow Burnアラート 長期間にわたる緩やかなエラーバジェット消費を検知する。 低: 「このペースでは期間の終わりにバジェットが足りなくなる」状況 SREチームが調査を計画・立案し、将来的な品質改善計画に組み込む。

※ アラート設定時のバーンレートはこちらを参考にしました。

ステークホルダー連携/合意

SREチームで策定したSLOの叩き台をベースにして、ステークホルダーに連携し合意を得ます。 約1時間の会議を設け、SREチームからPdM(プロダクトマネージャー)や開発チームのメンバーに対し、SLOの策定背景、具体的な計測手法、そして提案する目標値(SLO)とアクションプランについて説明・ディスカッションを行いました。 叩き台として、一通りのモノが出来上がっていたので、ディスカッションは非常にやり易く、スムーズに進みました。 ディスカッションでは、参加者側から以下のような意見がでてきました。

  • 〇〇の機能は事業としての優先度が下がっているので、今後はSLOから外しても良いかもしれない → ユーザーには利用されている機能のため、現状は残しておき、今後の振り返りで再度検討していく
  • APIのリクエスト成功率に加えて、レイテンシーもSLOとして定めても良いのではないか → 該当機能はユーザー視点において、レイテンシーよりも可用性が重要であると判断したため、今回はレイテンシーのSLO設定は見送る

SREチームにはなかった視点で意見をいただくことができ、非常に有意義な時間となりました。 最終的には提示した内容で合意をいただけ、有事の際にははPdMや開発チームにも協力いただけることとなりました。

全体向けの宣伝活動

SLOの取り組みを広く浸透させるため、月次で開催される全体定例を活用して宣伝活動を行いました。 宣伝する際は、多様なステークホルダー(職種や専門性が異なる参加者)に向けて、SLOという専門用語を使わずに、この施策が事業にどのような価値をもたらすのかを伝えることに重点を置きました。

レストランの当たり前品質を例にSLOについて翻訳しながら伝えたスライド例

SLOs as Code

SLO計測部分の技術観点について扱います。 計測する指標やSLOを全てTerraformで管理しています。 設定の変更は必ずGitHubのPull Request(PR)を経由します。PRには値の変更背景や意図を記述し、SLOが変更された経緯を後から容易に追跡できるようにしています。

可用性(APIのリクエスト成功率)

ログパイプライン

APIのリクエスト成功率は、Application Load Balancer(ALB)のログをベースに算出することとしました。 Google Cloud側のLog SinkからPub/Subを経由し、ALBのログをDatadogに送信する流れになっています。

ALBのログをDatadogに送信する流れ

ログベースのカスタムメトリクス

Datadogに送信後、 datadog_logs_metric を用いてログベースのカスタムメトリクスを作成します。 ログベースのカスタムメトリクスを作成することで、特定のディメンションに基づいて集計が可能になります。 今回の場合、ステータスコードでの集計を行いたいので、 group_by にステータスコードを指定します。

resource "datadog_logs_metric" "sample" {
  name  = "sample"
  compute {
    aggregation_type    = "count"
    include_percentiles = false
  }
  filter {
    query = "source:gcp.http.load.balancer @data.httpRequest.requestUrl:xxx @http.method:POST"
  }
  group_by {
    path     = "@http.status_code"
    tag_name = "http.status_code"
  }
}

SLOの設定例

APIのリクエスト成功率のSLOを設定するため、DatadogのメトリクスベースのSLOを利用します。ここでは、先に定義したカスタムメトリクスを利用します。

resource "datadog_service_level_objective" "sample" {
  name     = "sample"
  type     = "metric" 
  # SLI: APIに対する全体リクエストに対し、HTTPステータスコード5xx(サーバーエラー)でないレスポンスの割合
  query {
    # denominator: 全てのリクエスト数(合計)
    denominator = "sum:sample{*}.as_count()"
    # numerator: サーバーエラーを除いたリクエスト数(良いイベント)
    numerator   = "sum:sample{not(http.status_code:5*)}.as_count()"
  }
  thresholds {
    # target: SLO (この例では99%の成功率)
    target    = 99
    timeframe = "30d"
    warning   = 0
  }

}

可用性 (稼働率)

SLO設定例

Synthetics Monitoringを行っている場合、メトリクスとして、 synthetics.test_runs が利用可能になります。 この synthetics.test_runsを用いて、タイムスライスベースのSLOを設定します。

resource "datadog_service_level_objective" "sample" {
  name     = "sample"
  type     = "time_slice"
  
  # SLI: 特定のURLに対するDatadog Syntheticsテストにおいて、5分間の中で一度も失敗しなかったタイムスライスの割合
  sli_specification {
    time_slice {
      # query_interval_seconds: タイムスライスの間隔(この例では5分間隔)
      query_interval_seconds = 300
      # threshold: queryに対する閾値
      threshold              = 0
      # comparator: thresholdに対する条件
      comparator             = "<="
      query {
        formula {
          formula_expression = "query1"
        }
        query {
          metric_query {
            data_source = "metrics"
            name        = "query1"
            # query: タイムスライスで評価するためのクエリ(この例ではURLが "xxx" で、ステータスが "failure" のSyntheticsテスト実行の平均回数)
            query       = "avg:synthetics.test_runs{url:xxx, status:failure}.as_count()"
          }
        }
      }
    }
  }
  thresholds {
    # target: SLO (この例では99%の成功率)
    target    = 99
    timeframe = "30d"
    warning   = 0
  }
}

ページ表示速度

SLO設定例

RUMを利用している場合、メトリクスとして、 rum.measure.view.largest_contentful_paint が利用可能になります。 この rum.measure.view.largest_contentful_paint を用いて、タイムスライスベースのSLOを設定します。

resource "datadog_service_level_objective" "sample" {
  name     = "sample"
  type     = "time_slice"
  
  # SLI: 特定のページのRUMで計測したLCP75パーセンタイルが5分間の中で2.5s以下のタイムスライスの割合
  sli_specification {
    time_slice {
      # query_interval_seconds: タイムスライスの間隔(この例では5分間隔)
      query_interval_seconds = 300
      # threshold: queryに対する閾値(この例では2.5sをDatadog側の仕様に基づいてnanoseconds表記)
      threshold              = 2500000000
      # comparator: thresholdに対する条件
      comparator             = "<="
      query {
        formula {
          formula_expression = "query1"
        }
        query {
          metric_query {
            data_source = "metrics"
            name        = "query1"
            # query: タイムスライスで評価するためのクエリ(この例では特定アプリかつ特定ページのRUMの75%タイルLCP)
            query       = "p75:rum.measure.view.largest_contentful_paint{application.name:xxx AND service:xxx AND view.name:xxx}"
          }
        }
      }
    }
  }
  thresholds {
    # target: SLO (この例では99%の成功率)
    target    = 99
    timeframe = "30d"
    warning   = 0
  }
}

実際にSLO策定をやってみた感想

相手に合わせた説明を意識する

SLO策定は、エンジニアだけでは完結しない施策です。PdMなど、ビジネスサイドのステークホルダーとも連携する必要があります。 エンジニアでよくありがちなのが、技術的な用語をストレートに利用してしまうことです。 今回の例でいくと、エンジニアが直接「SLO入れたいです!」といっても、 ビジネスサイドのステークホルダーからしたら「SLO?なにそれ...」となると思います。 そこで、解決策としては、身近な例に例えながらSLOという言葉を意識させずに、翻訳を行い、「どんな施策か、なぜ必要なのか」を伝えることが重要だと思います。

書籍の通りうまくはいかない

SRE関連書籍や他の会社さんの事例を見ていると、すぐにSLO策定ができるのではないかと思ってしまいますが、実際はそうはいきません。 我々も、最初からステークホルダーを巻き込んで進めようとしましたが、うまくいきませんでした。結果として、先にエンジニアだけで叩き台のSLOを策定し、その叩き台をベースにビジネスサイドのステークホルダーと連携/合意を行いました。このように、書籍のやり方だけに固執せず、組織の状況に応じてカスタマイズした進め方が重要だと思います。

まとめ

本記事では、MIRAIZにおけるSLO策定事例を紹介しました。 進める中では、SREチームであらかじめ作成した叩き台をベースに、ステークホルダーに対して説明し、連携/合意を進めました。 加えて、全体共有会で多様なステークホルダーにもわかり易くどういった価値があるか伝わるように、SLOという言葉を翻訳しながら宣伝活動を行いました。

これらの一連の活動を経て、ようやく当たり前品質に対して共通言語がある状態になりました。 しかし、あくまでも今の状態はスタートラインです。継続的な振り返りを通して、事業の変化に即したSLOや文化醸成をしていきたいと思います。

*

増田 圭佑 Keisuke Masuda

PERSOL MIRAIZエンジニアリンググループ

大学時代は情報科学を専攻し、2023年にパーソルキャリア株式会社に新卒入社。現在はMIRAIZのSREチームで主に運用を担当している。

※2025年12月現在の情報です。