基盤設計と障害演習|データエンジニアリング実践
このページはプロモーション(広告)を含みます。
データエンジニアリング実践(上級・読む40分+演習60分)
この授業のゴール
- 利用者の要件から、時点の定義・取込契約・配送保証・watermark・再処理と版・提供判定とSLO・運用費を1つの基盤設計書にまとめられる
- 再送・遅延・契約違反・処理の中断を注入する障害演習を設計し、件数と金額の不変条件で結果を自動判定できる
- 運用費を、計算・保存・再処理・人の対応に分けて架空単価で見積もり、方式の選択を説明できる
- 小さな模擬で検証できたことと、実基盤で別に確かめるべきこと(模擬範囲)を区別して書ける
仕事でどう使うか
この授業は、モジュールの仕上げです。L01〜L05 で作った部品を1つの基盤設計にまとめ、障害演習(わざと障害を起こして、数字が守られるかを確かめる訓練)で検証します。
| 路線 | この授業が使われる成果物・意思決定 |
|---|---|
| DS(データサイエンティスト) | 分析に使うデータ基盤の設計書を読み、時点の定義・遅延・訂正の扱いが分析の前提と合うかを確認する |
| ML(機械学習エンジニア) | 特徴量の取込に障害演習を組み込み、再送や遅延で学習データ・推論の入力が二重・欠落しないことを確かめる |
| DX(DX推進・AI企画) | 業務部門向けデータ提供の設計書と運用費の見積もりを作り、方式(バッチかストリームか)の投資判断を説明する |
| RS(研究者) | 計測データの収集基盤について、欠落・重複・遅延が結果に与える影響と、検証した範囲を論文の方法に書く |
L04の例は、この授業でも中心です。e1=100円、e2=200円、e1 の再送、さらに処理の途中で止まって再開しても、合計は300円。後から e3=50円が届いたら350円の版2。これを、障害を注入した模擬で確かめます。
注意:この授業の模擬は、ブラウザの中で動く数十行の Python です。大規模な分散基盤を動かしたわけではありません。模擬で確かめられるのは論理(規則の正しさ)で、性能や実製品の設定は別に確かめます。
前提
この授業は L01〜L05 のまとめです。次の部品を使います。
| 部品 | 授業 |
|---|---|
| 取込契約・粒度・隔離・配送保証 | 取込契約と粒度 |
| CDC・イベント時刻と確定時刻 | CDCとイベント時刻 |
| 枠・watermark・遅延イベント・読み取り位置 | バッチとストリーム |
| 原本・再処理・版・照合 | 整合性と再処理 |
| 提供判定・SLI/SLO/SLA・エラー予算 | 品質と提供SLA |
運用の手順書と担当表は 「運用手順と担当」(有料版)、障害分析は 「障害分析と改善」(有料版)、費用の内訳は 「転送・計算・保存費用」(有料版) と 「性能・遅延・費用」(有料版) で扱っています。
身近な状況:「アプリの売上を、速報と確定値で出してほしい」
架空の小売会社から、次の依頼が来ました。
| 利用者 | 要件 |
|---|---|
| 販促部 | アプリの購入を10分ごとに集計し、枠が終わってから数分で見たい(速報) |
| 経理 | 前日の売上を毎朝 9:00 までに確定値で受け取り、決済システムと一致していてほしい |
| 情報システム部 | 決済の通知は「少なくとも1回」送る。通信が切れると再送する。端末の事情で数時間遅れることもある |
| 経営企画 | 運用費を月いくらと見込めばよいか知りたい |
この依頼に「ストリームで作ります」とだけ答えると、遅延をどこまで待つか、再送をどう扱うか、訂正をどう伝えるか、障害時に何が起きるかが決まっていません。要件の1行ずつに、L01〜L05 の部品が対応します。
| 要件 | 決めること | 部品 |
|---|---|---|
| 10分ごと・枠の終了から数分 | イベント時刻の枠、watermark の待ち時間 | L03 |
| 確定値・決済と一致 | 原本からの再処理、版、照合 | L04 |
| 少なくとも1回・再送 | event_id での重複除去、書き込み→位置の記録 | L01、L03 |
| 数時間の遅れ | 遅延イベントの訂正(版2)、遅延の上限 | L03、L04 |
| 9:00 まで | 提供判定と鮮度の SLO | L05 |
| 月の運用費 | 計算・保存・再処理・人の対応の見積もり | この授業 |
これを1枚の基盤設計書にまとめ、設計どおりに数字が守られるかを障害演習で確かめます。
直感的な説明:設計図と避難訓練
建物にたとえます。
- 基盤設計書は設計図です。どの部屋(工程)が何をし、どの扉(契約)を通って何が入ってくるかを書きます。
- 障害演習は避難訓練です。火事は起きないのがいちばんですが、起きたときに全員が出口にたどり着けるかは、実際にやってみないとわかりません。データ基盤でも、再送・遅延・処理の中断は「起きないのがよい」ものではなく、必ず起きるものとして扱います。
- 不変条件は、避難訓練の合格基準です。「全員が5分以内に外に出た」のように、何が起きても守られるべきことを、確認できる形で書きます。データ基盤では「受信=合格+隔離+重複」「最新版の件数と金額が正と一致」などです。
避難訓練で「階段が1つ使えない」状況を作るように、障害演習ではわざと再送を混ぜ、遅れたイベントを後から入れ、処理を途中で止めます。それでも不変条件が守られれば合格です。
たとえ話の限界:避難訓練は本物の建物で行いますが、この授業の障害演習は小さな模擬で行います。模擬で合格しても、本物の基盤(数百台の計算機、実際のネットワーク)で同じ結果になる保証はありません。何を模擬で確かめ、何を実基盤で確かめるかを分けて書くことが、設計書の大事な一部です。
正確な定義:基盤設計書の項目と、障害演習の不変条件
基盤設計書:利用者へ継続してデータを提供する仕組みについて、次の項目を具体的な値で決めた文書です。
| 項目 | 決めること | この授業の例 |
|---|---|---|
| 時点の定義 | 何の時刻で区切るか、タイムゾーン | 購入のイベント時刻、10分枠、日次は日本時間の日付 |
| 取込契約 | 列・型・粒度・キー・制御合計・違反時の処理 | 1行=1購入、キー event_id、違反は隔離 |
| 配送保証 | 上流の保証と、基盤として実現する保証 | 上流は少なくとも1回 → 重複除去で実質的なちょうど1回 |
| watermark | 待ち時間と、その根拠 | 遅れの99.5%点から5分 |
| 遅延と訂正 | 確定後に届いた分の扱い、遅延の上限 | 版を上げて訂正、72時間まで自動、それ以降は調整表 |
| 再処理と照合 | 原本、版、正、照合の頻度 | 原本は追記のみ、毎朝 決済システムと照合 |
| 提供判定と SLO/SLA | 閾値、鮮度・完全性の目標 | hold・note・publish、9:00 提供を月95% |
| 運用費 | 計算・保存・再処理・人の対応 | 架空単価で月の見積もり |
| 障害演習と模擬範囲 | 注入する障害、不変条件、模擬で確認しないこと | 下の表 |
障害演習(fault injection):起こり得る障害を意図的に起こし、システムが決められた振る舞いをするかを確かめること。注入する障害と、期待する振る舞いを先に表にします。
| 注入する障害 | 期待する振る舞い |
|---|---|
| 再送(同じ event_id がもう一度届く) | 重複として数え、合計は変えない |
| 遅延(確定済みの枠のイベントが届く) | 版を上げて訂正し、理由を残す |
| 契約違反の行 | 隔離して数え、捨てない |
| 処理の中断(書き込み後、位置の記録前に停止) | 再開後に同じ行が再配送されるが、重複除去で吸収する |
| 上流の欠落(ある枠が届かない) | 照合で missing を検出し、提供判定で hold |
不変条件(invariant):どんな障害を注入しても成り立つべき条件。この授業では次の3つを使います。
- balance:$\text{受信} = \text{合格} + \text{隔離} + \text{重複}$(1行も消えていない)
- versions:枠ごとの版番号が 1, 2, 3, … と抜けも重なりもなく並ぶ(古い版を書き換えていない)
- reconcile:正(決済システム)にある枠すべてについて、最新版の件数と金額が正と一致する
模擬範囲:模擬で確かめた範囲と、確かめていない範囲を明記したもの。模擬で確かめるのは規則の正しさで、処理能力・分散した計算機の故障・実製品の設定は対象外です。
段階付き例題:処理の途中で止めても300円、遅延で350円
入力:取込ログ7行(到着順)。e1=100円、e2=200円、e1 の再送、x1=80円(13分)、契約違反の行(event_id なし)、y1=120円(18分)、遅れて届いた e3=50円(5分)。枠は10分、待ち時間は5分。
ステップ1:障害なしで流す。y1(18分)が届くと watermark は $18 - 5 = 13$ 分になり、枠0(0〜9分)の終わり10分を越えるので確定します。版1は e1・e2 の2件300円(再送の e1 は重複)。その後 e3(5分)が届くと、枠0は確定済みなので版2として3件350円に訂正します。
ステップ2:処理の中断を注入。offset 1(e2)を書き込んだ直後、読み取り位置を記録する前に止めます。再開すると、記録済みの位置(offset 1)から読み直すので、e2 がもう一度届きます。
ステップ3:結果を比べる。中断ありでも、版1=300円、版2=350円で同じです。違うのは重複の件数(1→2)だけで、受信8行=合格5+隔離1+重複2 と収支が合います。
ステップ4:意味。「書き込み→位置の記録」の順序と、event_id での重複除去の組み合わせで、少なくとも1回の配送・処理の中断があっても、合計は二重になりません(バッチとストリーム の実質的なちょうど1回)。
class Crash(Exception):
"""処理の途中で止まったことを表す(模擬)"""
def new_state():
return {"received": 0, "accepted": 0, "quarantined": 0, "duplicates": 0,
"seen": set(), "raw": {}, "final": set(), "versions": [], "wm": None}
def publish(st, w, reason):
rows = st["raw"][w]
k = sum(1 for v in st["versions"] if v["window"] == w) + 1
st["versions"].append({"window": w, "version": k, "n": len(rows),
"total": sum(rows.values()), "reason": reason})
st["final"].add(w)
def step(st, e, wait, window):
st["received"] += 1
if not e.get("event_id") or not isinstance(e.get("amount"), int) or e["amount"] < 0:
st["quarantined"] += 1 # 契約違反 → 隔離(捨てない)
return
if e["event_id"] in st["seen"]:
st["duplicates"] += 1 # 再送・再配送 → 重複
return
st["seen"].add(e["event_id"]); st["accepted"] += 1
w = e["event_min"] // window * window
st["raw"].setdefault(w, {})[e["event_id"]] = e["amount"]
if w in st["final"]:
publish(st, w, "late:" + e["event_id"]) # 確定済みの枠 → 版を上げて訂正
cand = e["event_min"] - wait
st["wm"] = cand if st["wm"] is None else max(st["wm"], cand)
for s in sorted(st["raw"]):
if s not in st["final"] and s + window <= st["wm"]:
publish(st, s, "watermark")
def run(log, wait=5, window=10, crash_at=None):
"""書き込み→位置の記録 の順で処理する。crash_at の処理の直後(記録の前)に1回だけ止める"""
st, committed, crashed = new_state(), 0, False
while committed < len(log):
try:
for i in range(committed, len(log)):
step(st, log[i], wait, window) # 1. 書き込み
if i == crash_at and not crashed:
crashed = True
raise Crash() # 位置を記録する前に停止
committed = i + 1 # 2. 読み取り位置の記録
except Crash:
print(f" [障害注入] offset {crash_at} の処理後に停止 → offset {committed} から再開")
return st
log = [ # 取込ログ(到着順)。event_min は 10:00 からの経過分(イベント時刻)
{"event_id": "e1", "event_min": 2, "amount": 100},
{"event_id": "e2", "event_min": 7, "amount": 200},
{"event_id": "e1", "event_min": 2, "amount": 100}, # 再送
{"event_id": "x1", "event_min": 13, "amount": 80},
{"event_id": "", "event_min": 14, "amount": 30}, # 契約違反(event_id がない)
{"event_id": "y1", "event_min": 18, "amount": 120},
{"event_id": "e3", "event_min": 5, "amount": 50}, # 遅れて到着
]
for crash in (None, 1):
print("crash_at =", crash)
st = run(log, wait=5, crash_at=crash)
for v in st["versions"]:
print(" ", v)
print(" 受信", st["received"], "= 合格", st["accepted"], "+ 隔離", st["quarantined"], "+ 重複", st["duplicates"])
print(" 未確定の枠:", {w: sum(r.values()) for w, r in st["raw"].items() if w not in st["final"]})
関数の説明:step(st, e, wait, window) は1行を処理して状態の辞書 st を更新します(戻り値なし)。run(log, wait, window, crash_at) は取込ログ(辞書のリスト)を先頭から処理し、crash_at の番号の行を処理した直後に1回だけ止めて再開し、最終の状態の辞書を返します。st["versions"] は版の辞書(window、version、n、total、reason)のリストです。
模擬の前提:この模擬では、重複除去に使う
seenと原本rawが停止しても消えない(書き込み先に保存されている)と仮定しています。実基盤では、重複除去の状態を書き込み先と同じトランザクションで保存するか、書き込み先の一意キー(event_id)で重複を拒否します(失敗2)。
操作して理解する:待ち時間と中断の位置を変え、運用費を見積もる
例題のコードで、次を試してみましょう(run(log, wait=..., crash_at=...) の値を変えます)。
crash_atを 0〜6 のどれに変えても、版1=300円・版2=350円は変わりません。変わるのは受信の件数(+1)と、再配送された行の数え先です。多くは重複が1増えますが、crash_at=4(event_id のない契約違反の行)では重複として判定できないので、隔離が2件になります。実基盤では、隔離の記録にも取込ログの位置(offset)を残し、同じ位置の行を二重に隔離しないようにします。wait=15にすると、y1(18分)が届いても watermark は3分で、枠0は確定しません。e3 は遅延にならず、枠0は最後まで未確定です。待ち時間を延ばすと訂正は減りますが、速報が遅れます(バッチとストリーム)。
次に、運用費を架空単価で見積もります。計算機だけでなく、保存・再処理・人の対応も入れます。
PRICE_HOUR = 40 # 計算機1台1時間あたり(架空、円)
PRICE_GB = 3 # 保存1GB 1か月あたり(架空、円)
PRICE_PERSON = 4000 # 担当者の対応1時間あたり(架空、円)
DAYS = 30
options = {
"ストリーム(常時1台)": 24 * DAYS,
"マイクロバッチ(15分ごと3分)": 96 * 3 / 60 * DAYS,
"日次バッチ(1日20分)": 20 / 60 * DAYS,
}
storage = 1.0 * 90 * PRICE_GB # 原本 1GB/日 を90日保持
reprocess = 3 * (20 / 60) * PRICE_HOUR # 月3回、1回20分の再処理
person = 2 * 2 * PRICE_PERSON # 月2回の障害対応、1回2時間
for name, hours in options.items():
compute = hours * PRICE_HOUR
total = compute + storage + reprocess + person
print(f"{name}: 計算 {compute:,.0f} + 保存 {storage:,.0f} + 再処理 {reprocess:,.0f} + 人 {person:,.0f} = {total:,.0f} 円/月")
ストリームの計算費は28,800円、日次バッチは400円です。ただし、どの方式でも人の対応(16,000円)と保存(270円)はかかります。「ストリームは高い」と言うだけでなく、販促部の速報の要件が15分遅れでも許されるなら、マイクロバッチで計算費を5,760円に下げられる、という形で利用者に選択肢を示します。
最後に、模擬で検証した結果と、実基盤へ移すための設定を別々に出力します。後者は「未検証」と明記した、移行作業の入力です。
import json
verified = {"範囲": "ブラウザ内の模擬(数十行の Python、7行の取込ログ)",
"確認した不変条件": ["balance", "versions", "reconcile"],
"注入した障害": ["再送", "遅延", "契約違反", "書き込み後・記録前の中断"],
"結果": "全て合格(中断の位置 0〜6 で同じ版)"}
to_real = {"状態": "未検証。実基盤の検証環境で確かめる",
"取込ログの保持期間": "再処理したい期間以上(例:7日)",
"読み取り位置の記録": "書き込み完了の後に記録する(自動記録を使わない)",
"書き込み先": "event_id を一意キーにした上書き、または区画の置換",
"watermark の待ち時間": "本番の遅れの分布の99.5%点から決め直す",
"照合": "毎朝 決済システムと枠・日ごとに件数と金額",
"監視": ["鮮度", "完全性", "隔離率", "遅延件数", "消費の遅れ"],
"障害演習": "検証環境で四半期ごとに実施し、結果を記録"}
print("[模擬で検証した結果]"); print(json.dumps(verified, ensure_ascii=False, indent=1))
print("[実基盤へ移す設定(未検証)]"); print(json.dumps(to_real, ensure_ascii=False, indent=1))
実製品の設定名(読み取り位置の自動記録を切る設定など)は製品と版で異なります。執筆時点(2026年)の一般的な説明として読み、最新は各製品の公式情報で確認してください。
発展:実基盤での障害演習と、模擬では見えない故障
実基盤での障害演習:検証環境(本番と同じ構成で、利用者に見えない環境)で、計算機を1台止める、ネットワークを数分切る、取込ログの一部を遅らせる、といった障害を注入します。本番で行う場合は、影響範囲・中止の条件・責任者・利用者への事前通知を決めてから行います(「運用手順と担当」(有料版))。
模擬では見えない故障の例
| 故障 | なぜ模擬で見えないか |
|---|---|
| 処理能力の不足(入力が処理より速い) | 7行では負荷がかからない |
| 計算機どうしの通信断(分断)と、二重の書き込み | 模擬は1つのプロセスで動いている |
| 計算機ごとの時計のずれ | 模擬はイベント時刻を与えているだけ |
| 区画の再割り当て中の重複処理 | 区画が1つしかない |
| 実製品の設定の誤り | 実製品を使っていない |
障害演習の結果の書き方:「何を注入し、何を期待し、何が起きたか、どの不変条件で判定したか」を表にし、合格・不合格と、不合格なら対策と再演習の日を書きます。合格でも「この範囲では合格」と範囲を書きます。
設計書の見直し:本番で遅れの分布や重複率が変わったら、watermark の待ち時間や閾値を見直します。設計書は一度書いて終わりではなく、SLO の達成状況(品質と提供SLA)と障害の記録(「障害分析と改善」(有料版))を見て更新する文書です。
限界:不変条件を満たしても、「正」とした決済システム自体の誤りや、契約で決めた意味の誤り(税込と税抜の取り違え)は見つかりません。意味の確認は、利用者とのレビューと、独立した経路での照合で補います。
よくある失敗
失敗1:位置を先に記録してから書き込み、中断で行を失う
def run_commit_first(log, crash_at):
total, committed, seen = 0, 0, set()
i = 0
while i < len(log):
e = log[i]
committed = i + 1 # 誤り:先に位置を記録
if i == crash_at:
crash_at = None
i = committed # 停止 → 記録済みの位置(次の行)から再開
continue # この行は書き込まれないまま
if e["event_id"] not in seen:
seen.add(e["event_id"]); total += e["amount"]
i += 1
return total
log = [{"event_id": "e1", "amount": 100}, {"event_id": "e2", "amount": 200}, {"event_id": "e1", "amount": 100}]
print("中断なし:", run_commit_first(log, None), "円")
print("e2 で中断:", run_commit_first(log, 1), "円(e2 が消えた)")
位置を先に記録すると、書き込む前に止まった行は二度と読まれません(高々1回)。障害なしの演習では正しく見えるので、中断を注入しない限り気づけません。直し方:書き込みの後に位置を記録し、再配送される重複は event_id で吸収する。障害演習に「書き込み前の中断」「書き込み後・記録前の中断」の両方を入れる。
失敗2:重複除去の状態をメモリにだけ置き、再起動で二重に数える
log = [{"event_id": "e1", "amount": 100}, {"event_id": "e2", "amount": 200}]
sink_total = 0 # 書き込み先(再起動しても残る)
seen = set() # 誤り:メモリだけ(再起動で消える)
for e in log[:2]:
if e["event_id"] not in seen:
seen.add(e["event_id"]); sink_total += e["amount"]
# e2 の書き込み後、位置の記録前に停止 → 再起動で seen が空になり、e2 が再配送される
seen = set()
for e in log[1:]:
if e["event_id"] not in seen:
seen.add(e["event_id"]); sink_total += e["amount"]
print("書き込み先の合計:", sink_total, "円(正しくは300円)")
例題の模擬は「seen が消えない」前提でした。前提を外すと、再配送された e2 を新しい行として足してしまいます。直し方:重複の判定を書き込み先で行う(event_id を一意キーにして、同じキーは上書きまたは拒否)か、重複除去の状態と書き込みを同じトランザクションで保存する。模擬の前提は設計書の模擬範囲に書く。
失敗3:模擬の合格を「本番でも大丈夫」と書く
誤った設計書の記述:
障害演習の結果、本基盤は1日1億件の処理でも重複・欠落なく動作することを確認した。
模擬で流したのは7行です。確認したのは規則の正しさで、1億件の処理能力や、計算機どうしの通信断での振る舞いは確認していません。
直した記述:
ブラウザ内の模擬(7行の取込ログ)で、再送・遅延・契約違反・書き込み後の中断を注入し、不変条件 balance・versions・reconcile がすべて成り立つことを確認した。処理能力、分断、区画の再割り当て、実製品の設定は未確認であり、検証環境で別途確認する(担当:基盤チーム、期限:移行前)。
直し方:確認した範囲・注入した障害・判定に使った不変条件を書き、確認していないことを「未確認」として、誰がいつ確かめるかまで書く。
失敗4:運用費を計算機の料金だけで比べる
compute = {"ストリーム": 28800, "日次バッチ": 400}
other = 270 + 40 + 16000 # 保存+再処理+人の対応(架空)
for k, v in compute.items():
print(f"{k}: 計算だけ {v:,} 円 → 全体 {v + other:,} 円(比 {v / compute['日次バッチ']:.0f}倍 → {(v + other) / (400 + other):.1f}倍)")
計算だけで比べると72倍ですが、全体では約2.7倍です。逆に、障害対応の時間がストリームのほうが多くかかるなら、差はさらに開きます。直し方:計算・保存・再処理・人の対応を分けて見積もり、前提(台数・時間・回数・架空単価)を表に残す。料金は提供者・地域・契約で変わるので、実際の金額は執筆時点の情報ではなく、最新の公式料金と自社の契約で確認する。
まとめ
- 基盤設計書は、時点・契約・配送保証・watermark・遅延と訂正・再処理と照合・提供判定とSLO・運用費・障害演習と模擬範囲を具体的な値で書く。
- 障害演習では再送・遅延・契約違反・中断・欠落を注入し、期待する振る舞いを先に表にする。
- 不変条件は balance(収支)・versions(版の履歴)・reconcile(照合)を組み合わせる。1つだけでは見逃す誤りがある。
- 書き込み→位置の記録の順序と、書き込み先での event_id の重複除去で、中断があっても300円は300円のまま。
- 運用費は計算・保存・再処理・人の対応に分ける。模擬で確かめた範囲と、実基盤で確かめることを分けて書く。
用語
- 基盤設計書(data platform design document)
利用者へ継続してデータを提供する仕組みについて、時点・契約・方式・品質目標・費用・検証の範囲を具体的な値で決めた文書。
- 障害演習(fault injection / game day)
起こり得る障害を意図的に起こし、決められた振る舞いをするかを不変条件で確かめる訓練。
- 不変条件(invariant)
どんな障害を注入しても成り立つべき条件。例:受信=合格+隔離+重複。
- 模擬範囲(simulation scope)
模擬で確かめた範囲と、確かめていない範囲(処理能力・分散の故障・実製品の設定など)を明記したもの。
よくある質問
なぜわざわざ障害を起こすのですか? 本番で起きたときに直せばよいのでは?
本番で初めて起きた障害は、数字が二重・欠落したまま利用者に届いてから気づくことが多く、原因の調査にも時間がかかります。障害演習なら、利用者に影響しない場所で、決まった障害を何度でも再現できます。失敗1の「位置を先に記録する」誤りは、障害なしの試験では絶対に見つかりません。
基盤設計書と運用手順書はどう違いますか?
基盤設計書は「何をどう作るか、なぜそう決めたか」(時点・契約・方式・SLO・費用)を書きます。運用手順書は「障害が起きたら誰が何をするか」(「運用手順と担当」(有料版))を書きます。設計書の SLO や障害演習の結果が、手順書の判断の根拠になります。
不変条件はいくつ用意すればよいですか?
少なくとも「行が消えていない(収支)」「正と一致する(照合)」「履歴が壊れていない(版)」の3種類を用意します。ガイド付き演習のように、二重計上は収支では見逃し照合で捕まるなど、1つでは見逃す誤りがあるからです。題材によって「金額が負にならない」「同じキーが2行ない」なども加えます。
模擬で確かめたことは、実基盤では意味がないのですか?
意味があります。規則の誤り(位置の記録の順序、重複の判定、版の付け方)は規模に関係なく起きるので、小さな模擬で安く見つけられます。ただし処理能力や分散の故障は模擬では見えないので、実基盤の検証環境で別に確かめます。両方の結果を、範囲を明記して設計書に残します。
運用費の見積もりは、料金表の金額を使うべきですか?
料金は提供者・地域・契約・時期で変わります。授業では架空単価で計算の形を学びました。実際の見積もりでは、最新の公式料金と自社の契約で単価を置き換え、前提(台数・時間・保持期間・回数)を表で残します。前提が変わったときに再計算できることが大切です。
設計の判断(バッチかストリームか)で迷ったら、何で決めますか?
利用者の鮮度の要件、遅れの分布、運用費の3つを並べ、利用者に選択肢として示します。例えば「速報が15分遅れでよければ月の計算費は5,760円、数分以内なら28,800円」のように示すと、利用者が価値と費用を比べて決められます(バッチとストリーム)。
確認問題
問1 少なくとも1回の配送で、処理の途中で止まっても合計を二重にも欠落にもしないための組み合わせとして正しいものはどれか。
- ① 読み取り位置を先に記録し、その後で書き込む
- ② 書き込みの後で読み取り位置を記録し、event_id で重複を吸収する
- ③ 書き込み先の合計に足し込み、止まったら手で直す
- ④ 再送を防ぐため、上流に再送をやめてもらう
解答と解説
正解:②
書き込み→記録の順で欠落を防ぎ、再配送された重複を event_id で吸収します。
問2 障害演習の結果、受信8行・合格6・隔離1・重複1で、最新版の金額が正より100円多かった。どの不変条件で検出されるか。
- ① balance だけ
- ② reconcile だけ
- ③ balance と versions
- ④ どれでも検出されない
解答と解説
正解:②
6+1+1=8 なので収支は合っていますが、最新版が正と違うので reconcile で検出されます。
問3 ブラウザ内の模擬(7行)で障害演習に合格した。設計書の書き方として最も適切なものはどれか。
- ① 注入した障害と不変条件の範囲で規則が正しいことを確認し、処理能力・分断・実製品の設定は未確認として担当と期限を書いた
- ② 本基盤は大規模でも重複・欠落なく動作することを確認した
- ③ 模擬は意味がないので書かない
- ④ 合格したので実基盤での確認は不要と書いた
解答と解説
正解:①
模擬で確かめたのは論理の正しさです。確かめていないことを未確認として書くのが模擬範囲です。
問4 運用費の見積もりで、ストリームの計算費28,800円、日次バッチ400円、両方に共通の保存・再処理・人の対応が16,310円だった。全体の費用の比(ストリーム÷日次バッチ)に最も近いものはどれか。
- ① 72倍
- ② 約1.0倍
- ③ 約0.5倍
- ④ 約2.7倍
解答と解説
正解:④
(28,800+16,310)÷(400+16,310)=45,110÷16,710≒2.7倍です。計算費だけの72倍とは大きく違います。
問5 設計書で、遅れの分布が「95%は2分以内、99.5%は8分以内、最大48時間」のときの watermark の待ち時間として最も筋の通った選び方はどれか。
- ① 最大の48時間待つ
- ② 0分にして、遅れたものはすべて捨てる
- ③ 鮮度の要件と両立する範囲で99.5%点の8分とし、それより遅いものは版の訂正で扱う
- ④ 平均の遅れを使う
解答と解説
正解:③
待ち時間は遅れの分布と鮮度の要件から決め、まれな大きな遅れは待たずに訂正で扱います。
問6 例題の模擬で、crash_at=1(e2 を書き込んだ直後、位置の記録前)で中断した。障害なしの場合と比べて、変わった値として正しいものはどれか。
- ① 重複の件数(再配送の分だけ増える)
- ② 合格の件数
- ③ 隔離の件数
- ④ 版の数
解答と解説
正解:①
中断で再配送された e2 が重複として数えられるので、受信と重複が1つ増えます(7=5+1+1 → 8=5+1+2)。合格・隔離・版は変わりません。
次に学ぶこと
これで データエンジニアリング実践 の6授業は終わりです。モジュールの総合テストと、自力課題(遅延と重複を持つイベントを取込み、提供する)に進んでください。
戻って確認するなら、配送保証と watermark は バッチとストリーム、版と照合は 整合性と再処理、提供判定と SLO は 品質と提供SLA です。運用の手順と担当は 「運用手順と担当」(有料版)、障害の分析と改善は 「障害分析と改善」(有料版) で扱っています。
キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。
アプリを無料で開く有料版と無料版の違い