
2025/12/24 3:59
時計同期は悪夢です
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
正確なコンピュータクロックは多くの実世界システムに不可欠ですが、各ホストの内部クォーツオシレーター(約32 768 Hz)は通常温度変動で年間約110 秒ずれ、さらに老化とともに悪化します。クロックスキュー(瞬間的なずれ)とドリフトは実際の問題を引き起こします:クライアントがサーバーよりも遅れているため再コンパイルを逃す、またはデータベースがトランザクションの順序を誤って不整合な読み取りや金融エラーを生む可能性があります。
これらの問題を緩和するためにいくつかの同期スキームが存在します:
| プロトコル | 仕組み | 一般的な精度 | 主な制約 |
|---|---|---|---|
| Cristian’s | クライアントが正確な時刻サーバーに問い合わせ、往復遅延の半分だけ調整します。対称レイテンシを仮定。 | ネットワークが安定していれば数ミリ秒。 | 信頼できる低レイテンシ参照が必要。 |
| Berkeley’s | ノードがクロック値を共有し、外れ値を除外し平均化後相対調整を送信;常に逆方向にジャンプしないようにして単調性を保つ。 | Cristian’s と同程度だがスムーズ。 | 協調されたノードネットワークが必要。 |
| NTP (Network Time Protocol) | 階層的ストラタムシステム(0=GPS/原子時計、1–15 サーバー)。複数測定とフィルタリングを用いて時刻に収束。 | インターネット上で数十ミリ秒;LAN 上ではサブミリ秒。 | ネットワーク非対称性・ジッター・OS タイムスタンプオーバヘッドによって制限される。 |
| PTP (IEEE 1588) | ハードウェア NIC のタイムスタンプと境界クロックがサブマイクロ秒精度を提供;すべてのスイッチは PTP をサポートする必要。 | 完全なハードウェアスタックでサブマイクロ秒からナノ秒。 | 高価で完全に準拠したインフラストラクチャが必要。 |
絶対的な時間保証を必要とするシステム(例:Google Spanner のグローバルトランザクション)では、TrueTime API が不確実性 ε(約1–7 ms)を持つ時刻区間 ([earliest, latest]) を GPS 受信機と原子時計から取得し提供します。トランザクションは
TT.after(ts) が真になるまで待機してコミットすることで外部整合性を保証します。
物理的な時間が重要でなく 順序 が重要な場合、論理クロック が使用されます:
- Hybrid Logical Clock (HLC):壁時計時間と論理カウンタを組み合わせ、実際の時間に近いタイムスタンプを保ちつつスキューがあっても単調性を維持。CockroachDB と YugabyteDB で採用されています。
- Lamport timestamps:プロセスごとの簡易カウンタで因果順序は保証できるが同時実行性は検出できない。
- Vector clocks:各イベントに対して N 要素の配列を持ち、O(N) の空間コストで完全な因果関係を提供。
例外的に 2016‑12‑31 23:59:60 UTC のような閏秒は、固定された 60 秒/分 を前提としたシステムを壊します。主要クラウドプロバイダーは数日間にわたってクロック速度を徐々に調整して閏秒をスミアリングし、代替策としてステップ調整や UTC の放棄(TAI への移行)があります。
同期方法の選択は必要な精度、レイテンシ、および複雑さのトレードオフです:
- NTP はほとんどのビジネスアプリケーションに十分。
- PTP はサブマイクロ秒精度が必須な場合(電気通信 TDM、科学実験)に必要。
- 論理クロック は物理的時間が重要でなく一貫した順序が必要なときに適切。
堅牢なシステムはまた、VM マイグレーションや OS バグなどのクロック不連続を監視し、安全な抽象化 を使用してオフセットを追跡することで単調性を維持します。
これらのメカニズムは分散データベースの一貫性を向上させ、金融取引エラーを減少させ、リアルタイム通信を可能にし、高精度科学測定をサポートし、企業がグローバルな時間保証のために適切なタイミングインフラストラクチャへ投資する指針となります。
本文
時間は単純に思えるかもしれません。しかし、エンジニアとして「クロックを同期させる」という基本的な作業で睡眠不足になることもあります。理由は以下の通りです…
答えは一つの簡潔な真実にあります ― どこにも「グローバルクロック」は存在しません。データセンター、大陸、タイムゾーンを横断して数千台もの機器が独立して動作するとき、「今何時か?」という単純な質問さえも驚くほど複雑になります。
クロック同期は分散システムにおける最も難しい問題の核心であり、データベース整合性からデバッグ、金融取引まで幅広い領域に影響を与えます。
正確な時間の幻想
すべてのコンピュータには内部クロックが備わっており、通常はクォーツ結晶発振器で動作します。
このオシレーターは電圧を加えると特定の周波数で振動し、その周期をカウントして時間を測ります。
ほとんどのコンピュータクロックの標準周波数は 32768 Hz(2 のべき乗)で、1 秒まで簡単に数え下げられるよう設計されています。
しかしクォーツ結晶は完璧ではありません。
振動周波数は多くの要因によって変化します:
- 温度 – 標準結晶は温度変化で数十 ppm のドリフトを示し、10 °C の偏差で年間約 110 秒分に相当するドリフトが起こります。
- 製造ばらつき – 同一バッチでも微妙な差異が生じます。
- 老化 – 結晶は時間とともに特性を変え、ドリフトが累積します。
これらの要因により、同時に起動して通信しない2 台のコンピュータは必ずドリフトします。1 日後には数百ミリ秒、1 か月後には数秒の差が生じることもあります。
クロックスキュアが破壊する理由
- クロックスキュア – 任意時点で2 台のクロック間に存在する時間差。
- クロックドリフト – 時間とともにクロックが離れる速度。
どちらも分散システムで重大な問題を引き起こします。
例:分散 make
クライアント機械のクロック: 10:00:00(遅れている) サーバー機械のクロック: 10:00:05(先行している) 1. クライアント時刻 10:00:00 に util.c を編集 2. サーバー側 util.o のタイムスタンプは 10:00:03 3. make は util.o (10:00:03) と util.c (10:00:00) を比較 4. 結論: util.o が新しい → 再コンパイルをスキップ 5. 結果: あなたの変更は無視される
データベースシステムではさらに重要なタイムスタンプ問題があります。異なるノードでほぼ同時に発生した2 つのトランザクションがある場合、どちらが先かを決定しなければならず、クロックが同期していないと不正確な順序付けや整合性保証違反につながります。
ログ記録やデバッグもクロックが一致しないとほぼ不可能です。分散トレースはイベントの順序を再構築するためにタイムスタンプに依存しており、スキュアなクロックは「原因より前に効果」が起こるようなトレースを生成します。
物理クロック同期
Cristian アルゴリズム
クライアントが信頼できるサーバーから時刻を要求し、往復時間の半分を片方遅延と見積もり、自身のクロックを調整します:
def synchronize_clock(): t0 = local_time() # 要求前のローカル時刻 server_time = request_time_from_server() t1 = local_time() # 応答後のローカル時刻 round_trip = t1 - t0 one_way_delay = round_trip / 2 new_time = server_time + one_way_delay set_local_clock(new_time)
ネットワーク遅延が対称であれば機能しますが、実際のネットワークは非対称になることが多いです。
Berkeley アルゴリズム
単一の正確な時刻を持つマシンが存在しないと仮定し、指定されたデーモンがすべての機器をポーリングして平均(外れ値除外)を算出し、相対調整を送ります。クロックは逆戻りせず、徐々に速度を落として追いつくようにします。
Network Time Protocol (NTP)
階層構造の時刻サーバーで構成され、ストラタ(層)ごとに整理されています:
- ストラタ 0 – 原子時計や GPS 受信機などの高精度源。
- ストラタ 1 – ストラタ 0 に直接接続。
- 下位ストラタは上位から同期。
典型的な NTP の精度:
- 公衆インターネット: 10–100 ms
- 良好な LAN: 100–500 µs
ネットワーク非対称性、可変遅延、OS オーバヘッドが限界です。
ミリ秒では足りない
多くのアプリケーションにとって NTP のミリ秒精度は十分ですが、高頻度取引、電気通信(TDM)、科学実験などの分野ではマイクロ秒またはナノ秒レベルの正確さが必要です。
Precision Time Protocol (PTP) – IEEE 1588
NIC レベルでハードウェアタイムスタンプを使用し、ソフトウェア遅延を排除します。サブマイクロ秒精度を実現でき、ナノ秒の正確さが必要な用途では不可欠です。ただし、ネットワーク経路全体に対応(スイッチの境界クロック)を要求するため高価です。
論理クロックと因果関係
Lamport タイムスタンプ
各プロセスが持つ単純なカウンタ:
class LamportClock: def __init__(self): self.time = 0 def local_event(self): self.time += 1 return self.time def send_event(self): self.time += 1 return self.time def receive_event(self, received_time): self.time = max(self.time, received_time) + 1 return self.time
Lamport タイムスタンプは「A が B より先に起こったなら A のタイムスタンプが低い」という保証をしますが、同時発生するイベントを区別できません。
ベクトルクロック
Lamport を拡張し完全な因果関係を捕捉:
class VectorClock: def __init__(self, process_id, num_processes): self.id = process_id self.clock = [0] * num_processes def local_event(self): self.clock[self.id] += 1 return self.clock.copy() def send_event(self): self.clock[self.id] += 1 return self.clock.copy() def receive_event(self, received_clock): for i in range(len(self.clock)): self.clock[i] = max(self.clock[i], received_clock[i]) self.clock[self.id] += 1 return self.clock.copy() @staticmethod def compare(vc1, vc2): less = any(vc1[i] < vc2[i] for i in range(len(vc1))) greater = any(vc1[i] > vc2[i] for i in range(len(vc1))) if less and not greater: return "vc1 happened before vc2" elif greater and not less: return "vc2 happened before vc1" elif not less and not greater: return "equal" else: return "concurrent"
ベクトルクロックは因果関係を正確に判断できますが、O(N) の空間オーバーヘッドが大規模システムでは負担になります。
Google Spanner と TrueTime
Spanner は大陸横断で強い一貫性を必要としていました。その解決策は TrueTime というグローバル分散クロックインフラです。TrueTime は「真の時刻を含む必ずしも確実な時間区間」を返します:
→TT.now()
(不確かさ ε)[earliest, latest]- 通常の不確かさ: 1–7 ms
Spanner のトランザクションがコミットするとき、
TT.after(commit_timestamp) が真になるまで待機し、その後に成功を報告します。これにより外部一貫性が保証されます。
ハイブリッド論理クロック (HLC)
CockroachDB などのシステムは HLC を使用して物理時刻と論理カウンタを組み合わせます:
class HybridLogicalClock: def __init__(self): self.physical = 0 # 壁時計時間 self.logical = 0 # 論理カウンタ def now(self, wall_time): if wall_time > self.physical: self.physical = wall_time self.logical = 0 else: self.logical += 1 return (self.physical, self.logical) def receive(self, wall_time, received_physical, received_logical): # ...(タイムスタンプ統合ロジック)
HLC は実際の時間に近いタイムスタンプを保ちつつ、クロックスキュアがあっても因果順序を維持します。
同期戦略の選択
-
必要精度を決定
- ミリ秒精度で十分なビジネスアプリは多い。
- サブミリ秒が必要な取引、通信、科学実験もある。
-
インフラコストを評価
- NTP: 安価で広く利用可能。
- PTP: ハードウェアサポートとネットワークアップグレードが必要。
- TrueTime/原子時計: 高額だが世界規模でサブミリ秒精度を提供。
-
論理時刻 vs 物理時刻
- 論理クロックは物理時間の問題を回避できるが、実際のタイムスタンプは得られない。
- 物理またはハイブリッドクロックはログや監査に意味ある壁時計時間を提供。
-
異常処理
- クロックジャンプを監視し、単調増加保証(
等)を使用。SafeClock - 闇秒の扱い(闇秒スミアリング vs ステップ調整)を計画。
- クロックジャンプを監視し、単調増加保証(
-
トレードオフをバランス
- 緊密な同期 → コストと潜在的遅延が増大。
- ルーズな同期 → コストは低いが安全マージンや順序保証を強化する必要あり。
結論
分散システムにおけるクロック同期は、精度・レイテンシ・複雑さの間で折り合いをつける難しいトレードオフです。単純な NTP から Google の TrueTime インフラまで、それぞれが異なる強みとコスト構造を持ちます。自分たちのシステム要件と「完全同期」という理想に対する現実的限界を理解し、最適な戦略を選択することが鍵となります。