品質と提供SLA|データエンジニアリング実践

このページはプロモーション(広告)を含みます。

データエンジニアリング実践(上級・読む35分+演習45分)

この授業のゴール

仕事でどう使うか

ここまでの授業で、契約で入口を守り(L01)、変更と時刻を正しく扱い(L02)、枠を確定し(L03)、照合と再処理で訂正できる(L04)ようになりました。残る問いは「今日の数字を、利用者に出してよいか」と「どのくらいの品質を約束できるか」です。これを数値で決めて記録するのが、この授業の内容です。

路線 この授業が使われる成果物・意思決定
DS(データサイエンティスト) 分析に使う表の鮮度と完全性を確認し、条件を満たさない日は報告書に注記する
ML(機械学習エンジニア) 学習・推論に使う特徴量の品質ゲートを置き、条件を満たさない日はモデルの更新を止める
DX(DX推進・AI企画) 業務部門とデータ提供の約束(SLA)を結び、毎月の達成状況を報告して改善の優先順位を決める
RS(研究者) 計測データの欠落率・遅延を記録し、解析から除外する基準を事前に決めておく

品質の約束は「速いほどよい」「完璧であるべき」ではありません。利用者の意思決定に必要な水準を数値で決め、それを守るための運用費と釣り合わせます。

前提

次の言葉を使います。不安があれば先に戻ってください。

割合(0〜1の値)とパーセント(割合×100)、2つのパーセントの差を表すパーセントポイント(pt)を区別します。95%から97%への変化は「2pt上昇」で、「2%上昇」(95%×1.02=96.9%)とは違います。

身近な状況:「毎朝9時までに出す」と約束したら、何を測るか

販促部と経理に、前日の日次売上表を毎朝提供しています。ある月の終わりに、次の3つの声が届きました。

誰が 声
販促部 「たまに9時に間に合わない。平均は8時50分だと言われたが、遅い日に限って会議がある」
経理 「18日の数字は1.8%少なかった。翌日に直っていたが、その間に部長へ報告してしまった」
データ基盤の担当 「処理はすべて成功している。何が悪いのかわからない」

担当者の言う「成功」は、処理がエラーなく終わったことです。利用者が気にしているのは、(1) 期限に間に合ったか(鮮度)、(2) 欠けていないか(完全性)、(3) 正しいか(正確さ)です。処理の成功と、利用者にとっての品質は別物です。

この授業では、利用者が気にしている品質を指標にし、目標を決め、目標を満たさない日は数字を出さずに前回版を「前回版」と明示して表示する提供判定を作ります。さらに、利用者との約束(SLA)として文書にします。

直感的な説明:宅配便の「お届け予定」と「お届け率」

宅配便にたとえます。

ポイントは、SLO を SLA より厳しくすることです。社内の目標(95%)を少し厳しめに置き、お客さまとの約束(90%)には余裕を残しておくと、約束を破る前に気づいて直せます。

たとえ話の限界:宅配便の遅れは目で見えますが、データの欠けは見えません。1.8%欠けた売上表も、見た目は普通の表です。だからこそ、照合の結果を使って機械的に判定します。

正確な定義:SLI・SLO・SLA・エラー予算・提供判定

SLI(Service Level Indicator:サービスレベル指標):利用者が感じる品質を数値にしたもの。データ提供では次の3つが基本です。

指標 定義(日次の売上表の例) 正の値(分母)の取り方
鮮度 前日分の確定版が、期限(9:00)までに提供されたか(日ごとに達成/未達) 提供時刻は「処理の終了」ではなく「判定に合格して利用者が見られるようになった時刻」
完全性 提供件数 ÷ 正の件数 業務システムの確定記録や、送信側が通知する件数(制御合計)
正確さ $\lvert \text{提供金額} - \text{正の金額} \rvert \div \text{正の金額}$ 同上

ストリームの場合の鮮度は「確認した時刻 − 提供済みの最新の確定枠の終わり」(分)のように、遅れの長さで測ります(バッチとストリーム)。

SLO(Service Level Objective:サービスレベル目標):SLI の目標と、測る期間。例:「30日間で、鮮度を満たす日の割合が95%以上」。

SLA(Service Level Agreement:サービスレベル合意):利用者との約束。SLO より緩い目標と、違反時の対応(連絡・報告・補償など)を含みます。契約上の補償を伴う SLA の扱いは組織や契約で異なります(執筆時点(2026年)の一般的な説明。実際の契約は法務・調達の担当と確認)。

エラー予算:期間中に許される未達の量。

$$\text{エラー予算} = (1 - \text{SLO}) \times \text{期間の日数}$$

記号の意味:SLO は目標の割合(0〜1、単位なし)、期間の日数の単位は日。SLO=0.95、30日なら $(1 - 0.95) \times 30 = 1.5$ 日です。未達が1日なら残り0.5日、2日なら残り $-0.5$ 日(超過)です。

達成率:$\text{期限内の日数} \div \text{全日数}$。未提供(保留して前回版を出した日)は未達に数えます。

提供判定(品質ゲート):区画ごとに次の3値で判定します。この授業で使う閾値は架空の例です。

判定 条件(いずれか1つでも当てはまれば) 利用者に見えるもの
hold(保留) 件数の差 > 1%、金額の差 > 0.5%、隔離率 > 2% 前回版を「前回版・○日分は確認中」と明示して表示
note(注記つき提供) 件数の差 > 0.1%、金額の差 > 0.1%、隔離率 > 0.5% 今回の版を「暫定・差○%」と注記して表示
publish(提供) 上のどれにも当てはまらない 今回の版

件数・金額の差は $\lvert \text{提供} - \text{正} \rvert \div \text{正}$ で測ります。絶対値なので、欠け(少ない)も二重計上(多い)も同じように捕まえます。隔離率は契約違反で隔離した行 ÷ 受信した行です(取込契約と粒度)。

段階付き例題:18日の判定と、月の達成率

入力:18日の照合結果は、正の件数1,000件・金額520,000円、提供側982件・510,640円。受信1,010件のうち隔離0件。

ステップ1:差を計算。件数の差 $\lvert 982 - 1000 \rvert \div 1000 = 0.018$(1.8%)。金額の差 $\lvert 510640 - 520000 \rvert \div 520000 = 9360 \div 520000 = 0.018$(1.8%)。

ステップ2:判定。件数の差1.8% > 1% なので hold。利用者には17日までの前回版を「18日分は確認中」と表示し、担当者に通知します。経理が欠けた数字を部長に報告する事故はこれで防げます。

ステップ3:月の記録。この月は、7日に上流の遅れで9:20提供、18日は保留で未提供(翌日に再処理して提供)、他の28日は9:00までに提供でした。

ステップ4:達成率とエラー予算。達成率 $28 \div 30 = 0.933$(93.3%)。SLO 95% に対して 1.7pt 不足です。エラー予算は1.5日、使ったのは2日なので、残りは $1.5 - 2 = -0.5$ 日(超過)。

ステップ5:意味。予算を超過したので、来月は新しいデータ源の追加を後回しにし、7日の遅れ(上流)と18日の欠け(原因の調査)への対策を優先する、という判断の根拠になります。

def gap(served, expected):
    """提供値と正の値の差の割合(両方0なら0、正が0で提供が正なら無限大)"""
    if expected == 0:
        return 0.0 if served == 0 else float("inf")
    return abs(served - expected) / expected

def gate(c):
    """提供判定。'publish'(提供)・'note'(注記つき提供)・'hold'(保留して前回版を表示)を返す"""
    n_gap = gap(c["served_n"], c["expected_n"])
    t_gap = gap(c["served_total"], c["expected_total"])
    q_rate = c["quarantined"] / c["received"] if c["received"] else 0.0
    if n_gap > 0.01 or t_gap > 0.005 or q_rate > 0.02:
        return "hold"
    if n_gap > 0.001 or t_gap > 0.001 or q_rate > 0.005:
        return "note"
    return "publish"

def slo_report(records, deadline="09:00", target=0.95):
    """日ごとの提供時刻から、期限内の提供率とエラー予算の残りを計算する"""
    n = len(records)
    met = sum(1 for r in records if r["published_at"] is not None and r["published_at"] <= deadline)
    budget = (1 - target) * n
    return {"days": n, "met": met, "rate": met / n if n else 1.0,
            "budget": budget, "used": n - met, "left": budget - (n - met)}

day18 = dict(expected_n=1000, served_n=982, expected_total=520000, served_total=510640, received=1010, quarantined=0)
print("18日の判定:", gate(day18))
times = ["08:40"] * 30
times[6] = "09:20"      # 7日:上流の遅れ
times[17] = None        # 18日:保留(未提供)
records = [{"day": d + 1, "published_at": t} for d, t in enumerate(times)]
r = slo_report(records)
print(f"達成率 {r['rate']:.1%}({r['met']}/{r['days']}日)")
print(f"エラー予算 {r['budget']:.1f}日、使用 {r['used']}日、残り {r['left']:.1f}日")
print(f"SLOとの差 {(r['rate'] - 0.95) * 100:+.1f}pt")

関数の説明:gap(served, expected) は差の割合(float)を返します。gate(c) は照合結果の辞書 c を受け取り、'publish'・'note'・'hold' のいずれか(str)を返します。slo_report(records, deadline, target) は日ごとの提供時刻('HH:MM' の文字列、未提供は None)のリストから、日数・期限内の日数・達成率・エラー予算・使用・残りの辞書を返します。

操作して理解する:平均では見えない遅れと、閾値の効き方

鮮度を「平均の遅れ」で測ると何が起きるかを確かめます。下は、ある月の30日分の「日次処理の開始(8:00)から提供までの所要時間」(分)です。60分以内なら 9:00 の期限に間に合います。

lags = [40] * 28 + [180, 200]   # 28日は40分、2日だけ3時間以上かかった
mean = sum(lags) / len(lags)
within = sum(1 for x in lags if x <= 60) / len(lags)
print(f"平均 {mean:.0f}分(目標60分以内なら「達成」に見える)")
print(f"60分以内に提供できた日の割合 {within:.1%}")
print("最も遅い2日:", sorted(lags)[-2:], "分")

平均は50分で目標60分を下回りますが、60分以内に間に合った日は93.3%しかありません。利用者が困るのは「遅い日」なので、SLO は平均ではなく割合(または95パーセンタイルのような上位の値)で書きます。

次に、提供判定の閾値を変えて考えてみましょう(本文の例題の gate を使います)。

  1. 18日の提供側が 995件・517,400円 なら? → 件数の差0.5%、金額の差0.5% なので hold の閾値(1%・0.5%)を超えず、note になります。
  2. 二重計上で 1,020件・530,400円 なら? → 件数の差2%で hold。差を絶対値で測るので、多すぎる場合も捕まります。
  3. hold の閾値を「件数の差 > 5%」に緩めると、18日の1.8%の欠けは note として提供されます。経理がそれを見て報告したら? 閾値は「利用者がその差で判断を誤るか」で決め、利用者と合意します。

注意:閾値を厳しくするほど hold が増え、鮮度の SLO を食いつぶします。品質の SLO と鮮度の SLO は引っ張り合う関係です。両方を同時に満たせないときにどちらを優先するか(経理なら正確さ、販促の速報なら鮮度)を、SLA に書いておきます。

発展:SLAの書き方、除外、測定そのものの品質

SLA の項目(日次売上表の例。数値は架空)

項目 例
対象 日次売上表(売上日ごと、税抜、取消・返金を除く確定値)
指標と目標 鮮度:前日分を 9:00 までに提供する日が月90%以上。正確さ:業務システムとの金額の差0.5%以内
測定方法 提供判定の合格時刻を記録。照合は業務システムの確定記録と日ごとに実施
除外 事前に通知した計画停止、業務システム側の障害で正のデータが届かない日
違反時の対応 9:00 に間に合わない場合は 8:45 までに見込み時刻を連絡。月の目標を下回ったら翌月5営業日以内に原因と対策を報告
訂正の通知 確定値を版2以降に訂正したら、差と理由を当日中に通知(整合性と再処理)
連絡先と責任者 データ基盤担当(一次)、データ基盤責任者(エスカレーション)

除外を広げすぎない:除外が多い SLA は、数字上は達成していても利用者の不満を減らしません。除外した日数も一緒に報告します。

測定の品質:SLI を測る仕組み自体が止まると、「未達がない」ように見えます。提供判定のログが1日分欠けたら「未達」として数える(記録がない=確認できない)規則にしておくと、測定の停止を見逃しません。

SLO を100%にしない:100%は1日の未達も許さないので、エラー予算がゼロになり、改善のための変更(新しいデータ源の追加、規則の修正)が一切できなくなります。また上流の業務システムが100%でない限り、達成もできません。

限界:照合の「正」が当日中に確定しないデータ(返品が数日後に確定する売上など)では、当日の完全性は測れません。その場合は「暫定の完全性」(送信側の制御合計との比較)と「確定後の完全性」(数日後の照合)を分けて SLI にします。

よくある失敗

失敗1:処理の終了時刻で鮮度を測り、古いデータを「新鮮」と報告する

# 処理は毎朝 8:30 に終わっている。しかし上流が止まり、データは3日前のまま
jobs = [{"day": "05-10", "finished": "08:30", "latest_data_day": "05-07"}]
for j in jobs:
    print("処理の終了で測ると:", "達成" if j["finished"] <= "09:00" else "未達")
    print("データの日付で測ると:", "達成" if j["latest_data_day"] == "05-09" else "未達",
          f"(前日 05-09 のはずが {j['latest_data_day']})")

処理が毎日成功していても、上流からデータが届いていなければ、同じ古い数字を毎日作り直しているだけです。直し方:鮮度は「提供しているデータの中身がいつの分か」(最新の確定区画、最大のイベント時刻)で測る。処理の成功・失敗は運用の監視(「監視と通知」(有料版))で別に見る。

失敗2:平均で SLO を書き、遅い日を見逃す

「平均の提供時刻が 9:00 より前」という SLO は、本文の例のように平均50分でも、2日は3時間以上遅れていることを隠します。利用者が困るのはその2日です。

lags = [40] * 28 + [180, 200]
print("平均:", sum(lags) / len(lags), "分")
print("95パーセンタイル(上から2番目付近):", sorted(lags)[int(0.95 * len(lags))], "分")

95パーセンタイル(小さい順に並べて95%の位置の値)は180分で、遅い日の存在がはっきり出ます。直し方:「期限内の日の割合が95%以上」または「95パーセンタイルの遅れが60分以内」のように、遅い側を測る指標で書く。

失敗3:完全性の分母を自分の取込件数にする

source_sent = 1000      # 送信側が通知した件数(制御合計)
ingested = 982          # 取り込めた件数(18件は通信断で届いていない)
served = 982
print("自分の取込件数を分母にすると:", f"{served / ingested:.1%}")
print("送信側の件数を分母にすると:", f"{served / source_sent:.1%}")

自分が受け取った件数を分母にすると、届かなかった行は分母からも消えるので、完全性はいつも100%になります。直し方:分母は基盤の外から取る。業務システムの確定記録、または送信側がファイルやメッセージと一緒に送る件数・金額(制御合計)を契約に入れる(取込契約と粒度)。

失敗4:パーセントとパーセントポイントを混同して報告する

先月の達成率93.3%、今月96.7%。「達成率が3.4%改善」と報告すると、読み手は $93.3 \times 1.034 = 96.5\%$ になったと読むかもしれません。

表現 意味 この例
パーセントポイント(pt) 2つの%の差 $96.7 - 93.3 = 3.4$ pt
相対変化(%) 前の値に対する比 $(96.7 - 93.3) \div 93.3 = 3.6\%$

直し方:達成率・完全性・隔離率の変化は「3.4pt 改善」と書く。相対変化を使うときは「前月比」と明記する。未達の日数(2日→1日)を併記すると、利用者は実感をつかみやすくなります。

まとめ

用語

SLI(サービスレベル指標)(Service Level Indicator)

利用者が感じる品質(鮮度・完全性・正確さなど)を数値にしたもの。

SLO(サービスレベル目標)(Service Level Objective)

SLI の目標値と測る期間。例:30日間で期限内提供の日の割合95%以上。

SLA(サービスレベル合意)(Service Level Agreement)

利用者との品質の約束。SLO より緩い目標と、違反時の連絡・報告などの対応を含む。

エラー予算(error budget)

期間中に許される未達の量。(1−SLO)×期間で計算する。

提供判定(品質ゲート)(quality gate)

照合や契約検査の結果から、区画ごとに提供・注記つき提供・保留を決める仕組み。

制御合計(control total)

送信側がデータと一緒に通知する件数や金額の合計。受信側の完全性を確かめる分母に使う。

よくある質問

なぜ「処理の成功」だけを監視するのでは足りないのですか?

処理が成功しても、上流のデータが古い・欠けている・二重になっていることがあります。利用者が困るのは数字の鮮度・完全性・正確さなので、それを直接測る SLI が必要です。処理の成功・失敗は運用の監視(「監視と通知」(有料版))として別に見ます。

SLO と KPI(Key Performance Indicator:重要業績評価指標)はどう違いますか?

KPI は事業の成果(売上、解約率など)を測る指標で、SLO はサービスの品質(データが期限内に正しく届くか)の目標です。SLO を守ることは、KPI を正しく測るための前提条件です。

hold(保留)にすると鮮度の SLO を落とします。それでも保留すべきですか?

利用者がその差で判断を誤るなら保留すべきです。間違った数字で意思決定するほうが、1日遅れるより損失が大きいことが多いからです。ただし用途で変わります。販促の速報は鮮度優先で note として出し、経理の確定値は正確さ優先で hold にする、のように利用者ごとに決めて SLA に書きます。

閾値(1%、0.5%など)はどう決めればよいですか?

まず過去の照合結果の差の分布を見ます。普段の差が0.05%程度なら、0.1%を超えたら注記、という値に意味があります。次に、利用者に「何%ずれたら判断が変わるか」を聞きます。最後に、hold が月に何回起きるかを過去データで試算し、鮮度の SLO と両立するかを確かめます。

エラー予算を使い切ったら、何をするのですか?

多くの組織では、新しいデータ源の追加や大きな変更を一時的に止め、未達の原因対策(上流との遅延の取り決め、再処理の自動化など)を優先します。予算が余っているときは、変更を進めてよい根拠になります。事前に「予算を超えたらどうするか」を合意しておくのがポイントです。

正のデータが数日後にしか確定しない場合は、どうしますか?

当日は送信側の制御合計で「暫定の完全性」を測って note つきで提供し、正が確定した時点で照合して版を上げます(整合性と再処理)。SLA には「暫定値と確定値がある」「確定はいつか」を明記します。

確認問題

問1 SLI・SLO・SLA の関係として最も適切なものはどれか。

  1. ① SLI は利用者との約束、SLO は測った値、SLA は社内目標
  2. ② SLI は測る指標、SLO はその社内目標、SLA は違反時の対応を含む利用者との約束で、ふつう SLO より緩くする
  3. ③ 3つは同じ意味で、組織によって呼び方が違うだけ
  4. ④ SLA は SLO より厳しく置き、社内目標には余裕を持たせる
解答と解説

正解:②

SLI を測り、SLO で社内の目標を置き、SLA で利用者と約束します。SLO を厳しめにしておくと、SLA を破る前に気づけます。

問2 30日間の SLO が「期限内に提供した日の割合95%以上」のとき、エラー予算は何日か。

  1. ① 1.5日
  2. ② 0.95日
  3. ③ 5日
  4. ④ 28.5日
解答と解説

正解:①

(1 − 0.95) × 30 = 1.5日です。

問3 毎朝の処理はすべて 8:30 に成功している。しかし上流が止まり、提供している最新の区画は3日前のままだった。鮮度の SLI の判定として正しいものはどれか。

  1. ① 処理が成功しているので達成
  2. ② 提供しているデータの中身が前日分でないので未達
  3. ③ 上流の障害なので測定の対象外として達成
  4. ④ 処理時刻が 9:00 より前なので達成
解答と解説

正解:②

鮮度はデータの中身がいつの分かで測ります。処理の成功は利用者にとっての品質ではありません。

問4 照合で、正の件数1,000件に対して提供側が1,020件だった(金額も2%多い)。本文の閾値で判定するとどれか。

  1. ① publish(多い分には問題ない)
  2. ② note(注記つき提供)
  3. ③ hold(保留して前回版を表示)
  4. ④ 判定できない
解答と解説

正解:③

差は絶対値で測るので、2%の二重計上は件数の閾値1%を超え、hold です。

問5 先月の達成率が93.3%、今月が96.7%だった。最も正確な報告はどれか。

  1. ① 達成率が3.4%改善した
  2. ② 達成率が3.4pt改善した(未達の日は2日から1日へ)
  3. ③ 達成率が103.6%になった
  4. ④ 達成率の変化は報告しなくてよい
解答と解説

正解:②

2つのパーセントの差はパーセントポイントで表します。日数を併記すると実感がつかめます。

問6 完全性の SLI の分母として最も適切なものはどれか。

  1. ① 基盤が取り込めた件数
  2. ② 前日の提供件数
  3. ③ 過去30日の平均件数
  4. ④ 業務システムの確定記録や、送信側が通知する件数(制御合計)
解答と解説

正解:④

分母は基盤の外から取ります。自分の取込件数を分母にすると、届かなかった行が分母からも消えます。

次に学ぶこと

次の 基盤設計と障害演習 では、L01〜L05 の部品(契約・CDC・watermark・再処理と版・照合・提供判定・SLO)を1つの基盤設計にまとめ、遅延・重複・処理の中断を意図的に注入する障害演習で、件数と金額が守られることを確かめます。

戻って確認するなら、SLO の考え方は 「SLOとユーザー影響」(有料版)、監視と通知は 「監視と通知」(有料版)、監査レポートは 「監査レポート」(有料版) です。

キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。

アプリを無料で開く有料版と無料版の違い