午前2時の呼び出し:大規模環境でNTPが通用しない理由
午前2時14分、私のダッシュボードは真っ赤に染まりました。毎秒5万件のトランザクションを処理する分散データベースクラスターが、一貫性エラーを吐き出し始めたのです。
ログを調査すると、異なるラックにある2つのノード間で、15ミリ秒というわずかながら致命的なクロックドリフトが発生していることが判明しました。10Gbpsの環境において、15ミリ秒は永遠とも言える時間です。これは数百万ものオペレーションが時系列順序を失うのに十分な長さでした。NTP(Network Time Protocol)はオフィスのワークステーションには最適ですが、現代の金融や通信インフラが要求する解像度には不足しています。
私は本番環境でこの光景を何度も目にしてきました。標準的なNTPは、OSカーネルがすべてのネットワークパケットを処理する必要があるため、ジッターの影響を受けやすくなります。マイクロ秒の壁を突破するには、タイムスタンプの付与をソフトウェアスタックからネットワークハードウェアへと直接移行する必要があります。これが、IEEE 1588によって規定され、Linuxではlinuxptpプロジェクトを通じて実装されているPTP(Precision Time Protocol)の領域です。
クイックスタート(5分で完了するセットアップ)
PTPをサポートするハードウェアを使用しており、すぐに同期が必要な場合は、以下のガイドに従ってください。これらの手順は、Ubuntu、Debian、およびRHELベースのシステムに適用されます。
ステップ1:ハードウェアサポートの確認
すべてのネットワークインターフェースカード(NIC)が同じように作られているわけではありません。ethtoolを使用して、お使いのインターフェース(Intel i210やMellanox ConnectXなど)がハードウェアタイムスタンプをサポートしているか確認します。
sudo ethtool -T eth0
「Capabilities」セクションを確認してください。hardware-transmit、hardware-receive、およびhardware-raw-clockが表示されている必要があります。ソフトウェアのみのサポートも可能ですが、その場合の精度は約50〜100マイクロ秒に制限されます。
ステップ2:linuxptpのインストール
linuxptpパッケージは、2つの重要なデーモンを提供します。プロトコルロジックを担当するptp4lと、NICとOSクロックの間のギャップを埋めるphc2sysです。
# Debian/Ubuntuの場合
sudo apt update && sudo apt install linuxptp
# RHEL/Rocky/Fedoraの場合
sudo dnf install linuxptp
ステップ3:ptp4lの起動
ハードウェアタイムスタンプを使用してクライアント(スレーブ)として実行するには、次のように実行します。
sudo ptp4l -i eth0 -m
出力のmaster offsetに注目してください。この値が1,000 ns(1マイクロ秒)未満で安定すれば、NICのハードウェアクロックは正式にマスターと同期されたことになります。
ディープダイブ:精度の仕組み
NTPの主な弱点は、パケットが辿る経路にあります。パケットはNIC、ドライバ、カーネルネットワークスタックを経由してアプリケーションに到達します。各レイヤーで予測不可能なレイテンシが発生します。CPU使用率が90%に達すると、タイムスタンプが数ミリ秒遅れる可能性があります。
PHC vs システムクロック
PTP対応のNICは、オンボードのPHC(PTP Hardware Clock)を搭載しています。PTPパケットが物理回線に到達した瞬間, ハードウェアが即座に時刻を刻印します。これによりOSのジッターを完全に回避できます。しかし、これによって「スプリットブレイン」問題が発生します。NICは正確な時刻を知っていますが、Linuxのシステムクロックはまだズレているのです。これを解決するためにブリッジが必要になります。
linuxptpのエコシステム
- ptp4l: エンジン。NIC上のPHCをネットワーク上のグランドマスターと同期させます。
- phc2sys: ブリッジ。時刻をPHCからLinuxシステムクロックにコピーします。
- pmc: 管理ツール。同期を妨げることなくノードの状態を確認するために使用します。
アプリケーションがPTPの恩恵を受けるのは、両方のデーモンがアクティブな場合のみです。phc2sysがないと、NICだけが高精度な世界に留まり、アプリケーションは依然として古くて不正確なシステムクロックを読み取ることになります。
本番環境の設定
テストには手動コマンドで十分ですが、本番環境では永続的なサービスが必要です。
ptp4lをサービスとして設定する
/etc/linuxptp/ptp4l.confを編集します。標準的なクライアントノードでは、ノードが誤ってグランドマスターになろうとするのを防ぐため、priority1を255に設定してください。
[global]
slaveOnly 1
priority1 255
network_transport UDPv4
delay_mechanism E2E
特定のインターフェースに対してサービスを開始します。
sudo systemctl enable --now ptp4l@eth0
システムクロックの同期
phc2sysを使用してNICのハードウェアクロック(-s eth0)を追跡し、システムクロック(-w)を更新します。
# eth0からシステムクロックを同期
sudo phc2sys -s eth0 -w -m
NTPとPTPの両方のソースが混在する複雑な構成の場合は、timemasterデーモンを使用してください。これはchronydとlinuxptpを調整し、それらがシステムクロックを奪い合って激しく変動するのを防ぎます。
現場で培ったトラブルシューティング
午前2時の障害は、私にいくつかの厳しい教訓を与えてくれました。以下は、私が現在すべてのデプロイで使用しているチェックリストです。
- スイッチの監査: スイッチが「PTP対応」(Transparent ClockまたはBoundary Clockモードをサポート)でない場合、PTPパケットを一括トラフィックとして処理してしまいます。これによりジッターが発生し、精度がナノ秒から数十マイクロ秒にまで低下します。
- 競合するデーモンの停止:
timemasterで管理されていない限り、同じシステムクロックに対してphc2sysとntpd/chronydを同時に実行しないでください。周波数を調整しようとして競合し、クロックが跳ねる原因になります。 - 「rms」値の監視:
ptp4lの出力でrms(二乗平均平方根)の値を確認してください。ハードウェア支援が適切に機能しているネットワークでは、この値は100ns未満に保たれるはずです。急上昇した場合は、ネットワークの混雑やケーブルの不良を疑ってください。
PTPの設定とは、回線からCPUに至るまでのシングルビットの経路をマスターすることに他なりません。正しく構成されれば、分散システムは従来のネットワークが「大まかな推測」の連続に思えるほどの同期レベルに達します。それは、イベントを推定することと、ナノ秒単位でタイミングを知ることの差なのです。

