3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「1秒を笑う者は1秒に泣く」NTPと時刻同期、基本の"キ"

3
Posted at

たかが1秒、されど1秒

안녕하신게라!パナソニック コネクト株式会社クラウドソリューション部の加賀です。

インフラエンジニアでも初期設定以降はあまり意識しない「時刻同期」。
分散環境が当たり前になった今日、たった1秒の時刻ズレが悲劇を生みます。

ログを追っていて「リクエストとレスポンスのタイムスタンプが逆転している!?」と気付き、背筋が凍る経験をしたことはありませんか。え、私だけ?

本記事では、縁の下の力持ちNTPNTPクライアントに焦点を当て、その基礎知識と運用時のポイントをまとめました。

そもそも、時計ってズレるの?

ズレます。

OSは起動時にハードウェア時計(RTC)から時刻を読み取りますが、稼働中のシステム時計は主にCPUのタイマー(TSCやHPETなど)の割り込みを基準にソフトウェアで管理されています。当然これらもハードウェアの水晶発振器などに依存しているため、熱や個体差による誤差があります。
仮想環境ではvCPUの処理待ちによる僅かな差も加わり、乖離が加速します。

サーバ時計は「必ず自然に狂うもの」なのです。

時計を直すのは「障害の引き金」

じゃあ、ズレているのを発見したときに date コマンドや timedatectl コマンド等でサクッと直せば良いじゃん?と思うかもしれませんが、稼働中のサーバで時刻をイジるのはNGです。障害の引き金です。
OS上のアプリから見たら、時刻が急激にワープ・逆行した様に見えます。もしデータベースミドルウェアが動いている最中であれば、トランザクションが破綻したり、参照するアプリケーションが想定外の時間差のために異常終了する原因にもなり得ます。
ログのタイムスタンプも飛ぶため、追跡もかなり困難になります。百害あって一利なし。

では cron を使って定期的に ntpdate などのコマンドを叩いて自動補正すればいいのでは?というのも、絶対NGなアンチパターンです。
定期的に時刻がガクッとワープ(Step動作)する現象を自ら引き起こすことになります。( cron デーモンは時間が短時間巻き戻っても二重実行しないよう賢く保護していますが)アプリケーション内部の簡易的なポーリング処理や独自スケジューラなどは、時間が過去に戻ると「また0時0分がやってきたネ」と勘違いし、日次バッチ処理を二重実行してしまったり、逆に時間が未来へ進んだことで処理せずスキップしてしまうなど、予期せぬ惨事の引き金になり得ます。

時計はズレるから直さなきゃいけない、でも手動やcronで一気に直すと障害になる。じゃあ、システムを止めずにどうやって時刻同期したら良いの?

答えはNTP(Network Time Protocol)の「ネットワーク経由で正確な時刻を取得する手段」と、NTPクライアントが持つ「時計の進みを微調整する機能」を活用し、システムに影響を与えずに安全に時刻を合わせるアプローチです。詳細は後述します。

NTPの基本的な仕組み

NTPって「いま何時?」「そうね大体ねー」って聞くだけのプロトコルでしょ?という理解でおよそ合っていますが、ネットワークの通信遅延時間(レイテンシ)も計算して現在時刻を推測する割と精巧なプロトコルです。大体じゃないです。

近年では、通信経路を保護してパケット改ざんや中間者攻撃(NTP Spoofing)を防ぐ「NTS(Network Time Security)」が chrony 等で実装されるなど、プロトコル自身も進化を続けています。

Stratum(ストラタム)が作る階層構造と分散同期

時刻の世界には、原子時計などの基準(Stratum 0)を頂点にした階層構造「Stratum」があります。GPSや原子時計などの絶対的な時刻源(Stratum 0)に直接繋がっているサーバがStratum 1、そこからネットワーク越しにもらうのがStratum 2、3…です。

この数字は「大元の時刻源からの階層数」です。サーバ同士が参照し合って無限ループに陥るのを防ぐための「絶対的な距離の基準」として働きますが、ネットワークを経由するごとにレイテンシの非対称性やジッタによる微小な誤差が蓄積されやすくなるため、上位層のほうが正確な時刻を持っています。

このおかげで、Stratum 1へのNTPクライアント集中を避けつつも時刻同期できる分散システムとして成立しています。

NTPは「絶対時間」しか持たない

厳密に言えば、NTPプロトコルがやり取りするのは「1900年1月1日 00:00:00 を起点とした64ビット1の経過秒数」という単なるカウンタ値です。UTCと同等ですが、タイムゾーン概念を持っておらず、人間向けの時刻形式への変換処理はすべてOS側の機能(tzdata等)です。

設定ミスで「9時間ズレる」などの事象はよく起こりますが、NTPは正しい絶対時間を刻んでいるのに、OSのタイムゾーン設定のミスでズレて見えているだけのことが大半です。

タイムゾーンとサマータイム(DST)の罠

特に海外リージョンでシステムを組む場合や、グローバルなシステム・SaaSと連携する際は「サマータイム(DST:Daylight Saving Time)」に最大の注意が必要です。
ある日突然システムやログのタイムスタンプが「1時間」ズレているように見えたら、サマータイムの切り替わりタイミングを疑いましょう。NTPは正しい時間をキープしているのに、OSが自動的に表示時刻を正しく1時間ズラしてしまうためです。
混乱を防ぐため、サーバOSのタイムゾーン設定は原則として「UTC」で統一するのが世界共通のベストプラクティスです。(日本はサマータイムが無くJSTが主流なので、海外製SaaSとの連携時に要注意です)

各クラウド環境の時刻提供

オンプレミス環境や自宅サーバでは現在もNICT(ntp.nict.jp)やインターネットマルチフィード(ntp.jst.mfeed.ad.jp)、NTP Pool Project等の公開NTPサーバの恩恵にあずかることが多いですが、今のクラウド基盤は独自に高精度な仕組みを備えています。

さらに最近のトレンドとして、仮想マシンとクラウド基盤の時計合わせに、ネットワーク経由のUDP 123番通信(NTP)ではなく、ハイパーバイザー側の高精度なハードウェアクロック(PTP Hardware Clock)を仮想マシンにマウントして同期する(/dev/ptp0 などを参照する)方式へとベストプラクティスが移行しつつあります。

【コラム】 NTPの限界と「PTP」
NTPの数ミリ秒のズレも許されない「マイクロ秒・ナノ秒単位の精度」が求められる金融システムや携帯の5G、放送業界では「PTP (Precision Time Protocol)」という技術が使われています。最近のクラウドはこのPTP基盤をベースに高精度な時刻を提供しています。

AWS(Amazon Time Sync Service)

EC2でおなじみ、リンクローカル(169.254.169.123)へのアクセスです。Amazon Linux 2023等ではデフォルトで chronyrefclock PHC /dev/ptp0 を参照するように構成され、数十マイクロ秒単位の精度を出します。面倒な「うるう秒」処理も内部でよしなにやってくれます。

GCP(Google Cloud Time Service)

GCPのCompute Engineはメタデータサーバ(metadata.google.internal)経由でGoogle独自基盤と同期します。「うるう秒」処理もAWS同様です。

Azure(Azure Time Sync)

AzureでもHyper-Vホストから時刻を注入する「VMICTimeSync」統合サービスがあります。以前は稼働中の高精度な時間維持としてはchrony等のネットワークNTPが推奨されていました。現在では「うるう秒」の吸収(スミアリング)も含め、Azureの基盤側がよしなに処理してくれる標準的な構成に進化しています。

時刻をうまく「吸収」するNTPクライアント側の工夫

さて、環境側から正確な時刻を教えてもらっても、OS(NTPクライアント)側でそれをうまく合わせられなきゃ意味がありません。前述したように、手動で急激に時間を直そうとすることは障害につながります。
では、様々な機器で動作するNTPクライアント達は、どうやって「安全に」時刻を修正しているのでしょうか。

時計の合わせ方

NTPクライアントが「自分の時計、ズレてるから直さなきゃ」と判断し、修正するアプローチには、大きく2種類あります。

1つが「Step(ステップ)」。今が2時なのに手元の時計が1時だったら、一気に2時に「ワープ」させる動きです。手っ取り早いですが、システム的には時間が飛ぶのでログの順序が破綻したり、アプリケーション側がパニックを起こすリスクがあります(通常はOS起動時など限定的に使われます)。

もう1つが「Slew(スルー)」。一気に飛ばすのではなく、時計の進む1秒の速度を「少し早く(遅く)する」動きです。時間を逆行させずに少しずつ正しい時刻にすり合わせていくため、DBやアプリに優しく安全に補正できます。
ただし、Slewによる補正速度には限界があります。数分・数時間単位の激しいズレをSlewだけで吸収しようとすると、追いつくまでに数ヶ月〜年単位で時間がかかることもあります。いかにこのSlewを賢く使って安全に直すか、極端なズレの場合はあきらめて手動介入や再起動(Step)を許可するか、がNTPクライアントの腕の見せ所です。
(伝統的な ntpd では128ms以上オフセットがあるとStep動作をしてしまいますが、 chrony の場合は設定値 makestep 1 3 によって「起動後の最初の3回の更新で1秒以上ズレていればStep動作を許可し、それ以降はどんなにズレてもSlewで頑張る」という安全な構成が主流です)

さらにNTPクライアントが優れているのは「ドリフト(Drift)の学習機能」です。ローカルの安物時計が「1日に何ミリ秒ズレるのか(傾き)」を学習・記録(driftfile等)します。これにより、ネットワークが一時的に切れてNTPサーバと通信できなくなっても、自分の時計のズレ癖を自己補正しながら正確な時を刻み続けることができます。

Linuxの主流は「chrony」へ、そして「SNTP」との使い分け

最近のRHEL系ディストリビューションでは ntpd に代わり chrony が標準です。
chronyはこの「Slew」を非常に賢く行い、一時停止(サスペンド)やネットワーク瞬断後の復旧も早い設計になっています。
同期先が気になるなら chronyc sources を叩き、 ^* 付きの行を確認しましょう。さらに chronyc tracking コマンドを叩くことで、「Leap status が Normalか」「RMS offset (時刻のばらつき) がどれくらいか」といった稼働状況を詳細に確認できます。

一方で、近年のUbuntuなどSystemdを採用するディストリビューションのデフォルトは、フル機能ではなく簡易版である systemd-timesyncd(SNTPクライアント) になっています。
SNTP (Simple NTP) は、複数のNTPサーバと同時に通信し、遅延やジッタの統計アルゴリズムを用いて最も正確なサーバ群を選出する高度な「交差検証機能」を持たず、応答のあったサーバを単一で信じる軽量な仕組みです。精密な時刻同期や、自身がNTPサーバとして振る舞う必要がある場合は、明示的に chrony 等をインストールする必要があります。

Windows環境では「W32Time」とADの呪縛

Windows環境だと「Windows Time サービス(W32Time)」が頑張っています。

AD(Active Directory)環境でのKerberos認証は、DC(ドメインコントローラ)と「5分」以上時刻がズレるとリプレイ攻撃扱いでログイン不能になります。
AD環境では以下の「ツリー構造の時刻同期」を絶対のルールとして守らなければなりません。

  1. フォレストルートのPDCエミュレータ(最上位DC) だけが、外部の信頼できるNTP(クラウドの時刻基盤やNICTなど)と同期する
  2. 他のすべてのドメインコントローラ は、PDCエミュレータと同期する
  3. 一般のメンバサーバやクライアントPC は、近くのドメインコントローラと自動的に同期する

ここで運用担当者が良かれと思って、一般のメンバサーバのNTP参照先を手動で外部(NICTなど)に向けてしまうのはトポロジ違反の罠です。これをやってしまうと、DC側(クラウド基盤時刻)とメンバサーバ側の参照する時刻源が割れ、ドメインから弾かれる可能性が出てきます。
Azureでクラウド基盤上にADドメインを展開する場合、Azureから強制適用されるVMICTimeSyncをドメインコントローラとして稼働する仮想マシン上で明示的に無効化するのを忘れないでください。ドキュメントでもっと明示して欲しい。

サーバOS「以外」でのNTPの役割

ネットワーク機器やIoTデバイスにとってもNTPは命綱です。

ルータやVPN機器で時刻がズレていると、複数レイヤのログ突合が不可能になり、IPsec証明書の期限外エラーでVPNすら張れなくなります。

IoT・エッジデバイスも同様で、コスト重視でRTC(時計電池)を積んでいないと、再起動直後は「1970年1月1日」です。MQTTやAPIを叩いてもSSL/TLS証明書エラーで弾かれるため、起動時のNTP同期がすべての通信の必須条件となります。

【昔話コラム】 ハードコードが生んだ悲劇「福岡大学NTP問題」
IoTやルータなどの組み込み機器で「NTPサーバの指定をどうするか」は非常に重要です。
過去、あるルータ製品のファームウェアに、当時の公開NTPサーバであった福岡大学のIPアドレスが「ハードコード(固定書き込み)」されて出荷されてしまう事件がありました。結果として、日本全国に普及したルータから一斉にNTPリクエストが送られ続け、大学のネットワークがDDoS攻撃さながらのトラフィックに数年間にわたり悩まされるという事態に発展しました。(ウィスコンシン大学のNTPサーバでも発生しています。)

機器にNTPサーバを固定で組み込む際は、自社でインフラを用意するか、pool.ntp.org 等の負荷分散されたプールを利用しましょう。ベストプラクティスは先人たちの失敗の上に成り立っています。

運用でハマる罠

実運用でありがちな落とし穴をいくつか紹介します。

実は一番多い?UDP123番の通信許可忘れ

「なぜか少しずつ時計がズレる」場合、まずはこれを疑います。NTPは「UDP 123番」を使いますが、ファイアウォール(SG等)のアウトバウンド許可漏れはよくあるミスです。

逆に、古いNTPデーモンや不適切な設定のままインターネットに公開してしまうと、monlist コマンドなどを悪用したNTPアンプリフィケーション攻撃(NTP増幅攻撃・リフレクション攻撃)の踏み台にされるので注意が必要です。

時刻のズレと「通信可否」を監視する

プロセス死活だけでなく、DatadogやZabbixで「タイムサーバとのOffset(ズレ)」を監視し、閾値でアラートを上げるのが実運用で有効です。
また、NTPはUDP通信なので、いつの間にか通信がドロップされていることが稀にあります。少しずつ時計がズレて閾値を超える前に、NTPサーバへ到達できなくなった(Reachが下落した)時点でアラートを上げる監視もベストプラクティスです。

うるう秒とLeap Smearing(混ぜるな危険)

「うるう秒(1秒の追加/削除)」とは、地球の自転のズレと原子時計の差を反映する調整秒のことです。1972年より始まり計27回追加されました。
現在はAWS、Google Cloud、Azureなどのクラウド各社が、数ミリ秒ずつ時計を微調整して1秒を24時間かけてゆっくり吸収する「Leap Smearing(スミアリング)」により、安全を担保する手法が主流となっています。

ここで運用上の最大のトラブル要因があります。それは「Smearingを実施しているNTPサーバと、本来のうるう秒を正しく配信するNTPサーバ(NICTの公開NTPなど)を、同じchronyの設定内で絶対に混ぜてはいけない」ということです。
混ぜてしまうと、うるう秒発生時に参照しているサーバ間で時刻が最大1秒乖離し、NTPクライアントがどちらを信じるべきか迷ってチャタリングを起こし、障害の引き金になります(ハイブリッドクラウドやマルチクラウドではどちらかに揃える意識が重要です)。

なお、うるう秒制度自体は2035年に廃止予定です。
かつて、うるう秒挿入の瞬間に立ち会うためNICT(情報通信研究機構)へ足を運ぶ程度には好きなイベントでしたが残念です。(毎回想像以上の人数の同志が集まっていました、好事家どもめ)
NICT.jpg
※うるう秒挿入の瞬間、ガラケー写真で画質が粗い(好事家な筆者撮影)

おわりに

地味で誰も気に留めない「NTPクライアント」ですが、彼らが微小なズレを常時補正してくれるため、今の分散システムは時刻同期を意識すること無く利用できます。

いざ障害が発生してログを突き合わせた時に「あれ、タイムスタンプが逆転している…?」と手遅れな状態で青ざめるのを防ぐためにも、縁の下の力持ちである彼らの仕組みを理解し、「基本の”キ”」を押さえておくのが大切です。


お断り
記事内容は個人の見解であり、所属組織の立場や戦略・意見を代表するものではありません。
あくまでエンジニアとしての経験や考えを発信していますので、ご了承ください。

  1. 整数部32ビット・小数部32ビットで表します。将来の桁あふれによる2036年問題を見据え、NTPv4仕様で128ビットデータフォーマットも定義されています。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?