インターネットでの時刻合わせという難題に挑む(345号)
コンピュータシステムにとって、時刻というのはとても大切な情報です。
サーバと呼ばれるコンピュータでは日常的には人を張り付けたりしていません。
いざ問題が起きてから「なんだなんだ。何が起きたんだ」と担当者が調査を始めます。
こういった調査では「いつ」「何が」起きたかを正確に把握することが肝心です。
ですが、この「いつ」を複数のサーバ間で時刻を共有することが意外に難しいということはあまり知られていません。
今回は、インターネット上での時刻合わせについてお話をします。
なぜ時刻合わせが必要なのか?
日常では、1分や2分のズレを気にするシーンはあまりありません。
ですが、推理小説や刑事ドラマでは時刻が重要なポイントとなることがありますよね。
サーバでのトラブル発生時の調査もこれに似たところがあります。
各サーバではいつ何をしたのか?という記録をログという形で残しています。
サーバトラブル時にはこのログを頼りに何が起きたかを紐解いていくわけです。
ログには年月日時分秒が記録(ミリ秒まで記録するログもある)されています。
複数のサーバ間でのトラブルが起きると、両サーバのログを突き合わせて問題が生じた箇所を調べるわけです。
この調査には、2つのサーバ間で時刻が合っていることが条件になります。
もちろん、国が違えば時差はありますので人手の補正は必要ですが、同じ時刻を共有できる環境は必要です。
コンピュータは高速ですから1秒間でもたくさんの仕事をこなせます。
特にたくさんの依頼を受け付けるサーバは1秒に何百何千のリクエストをこなします。
そんなサーバでの調査を行う場合にはミリ秒まで伝えた方が調査をスムーズに進めることができます。
ですから、時刻ズレなんてない方が良いのは明らかです。
少なくとも1秒未満、できれば数ミリ秒程度のズレであって欲しいわけです。
ですが、これは意外なほど難しいことなのです。
なぜ時刻合わせが難しいのか?
コンピュータはほぼ必ず内部時計(水晶発振器を使った部品)を持っています。
ログを記録したりする時には、この内部時計を参照して時刻を得ています。
水晶発振器は精度の高い時計なのですが、それでも誤差は生じます。(1ヶ月で数秒程度)
だから、何らかの形でサーバ間の時刻を共有すること、つまり時刻合わせが必要になります。
ここで問題となるのは、求められる精度です。
これが数秒程度の誤差が許されるのであれば、人手で月に一度の補正をかけてやればOKです。
上述の通り、コンピュータ間のズレはできるだけ減らしたい事情があります。
となると、人手による補正は現実的ではありません。
「なら、コンピュータ間で通信して決めさせよう」となるのは当然で、実際ネットワーク上で事刻合わせを行うプロトコル(通信手順)が存在しています。
これをNTP(Network Time Protocol)と言います。
たかが時刻合わせのためにプロトコルまで決める必要あるの?となりそうですが、これには理由があります。
というのは、時刻を厳密に合わせようとすればするほど、劇的に難易度が上がっていくのです。
特に問題となるのは、問い合わせに要する時間です。
通信を行うわけですから、リクエスト(正しい時刻を教えてよという依頼)からレスポンス(「オレが知ってる正しい時刻はコレだよ」)が帰ってくるまでにも時間を要します。
さらに細かいことを言うと、相手サーバに教えてもらった時刻を内部時計にセットするにも(わずかですが)時間が必要です。
時刻を求めている間にも時は進んでいきますし、コンピュータで何をするにも時間をゼロにはできませんから「正しい時刻」を求めることは不可能です。
「ある程度は正しいと思われる時刻」を設定するのが限度だということです。
NTP
というわけでNTPです。
NTPはかなり古いプロトコルで、1992年に制定されました。
HTTP(Hyper Text Transfer Protocol:Webサイトの閲覧用プロトコル)が1996年です。それよりも4年も前に時刻同期の重要性を見抜いていたのですから驚きます。
さて、時刻同期をするには、通信処理や登録処理を考慮する必要があります。
でないと、実際の時刻と設定される時刻にズレが生ずるためです。
NTPはネットワークの影響を小さくするために、かなり巧妙な方法を用います。
以降では、時刻を知りたいサーバのことを「クライアント」、時刻を教えてくれるサーバのことを「NTPサーバ」と書きます。
なお、下記のt1~t4はそれぞれの時刻を示します。
つまり、t1はクライアントの内部時計での送信時刻、t2はNTPサーバの内部時計の受信時刻です。
1. クライアントから依頼を送信(t1)
↓
↓(通信処理)
↓
2. NTPサーバは依頼を受信(t2)
↓
↓(内部処理)
↓
3. NTPサーバから回答を送信(t3)
↓
↓(通信処理)
↓
4. クライアントは回答を受信(t4)
↓
↓(時刻の計算処理。後述※1)
↓
5. クライアントは求めた時刻を設定
さて、クライアントで行う時刻計算(上図の※1)は以下の通りです。
a. 送信時間(t2-t1)と受信時間(t4-t3)を求めます。
※両者の絶対値(マイナス記号を除いた値)が大きくズレている場合はやりなおし。
b. 次の計算をします。
正しい時刻=クライアントの現在時刻+(送信時間-受信時間)÷2
c. 上で計算した正しい時刻を設定します。
さらっと書きましたが、これで上述の「巧妙な方法」に気付く方は少数でしょう。
(筆者も最初は何がスゴいんだろう?と思いました)
以下で、それを解説します。
NTPの計算のトリック
トリックというほどではないのですが、上述の「送信時間(t2-t1)」というのは厳密には「送信時間」ではありません。
t1はクライアント視点の時刻情報、t2はNTPサーバ視点の時刻情報です。
つまり、そもそもベースとなる時刻情報が違うのです。
例えば、クライアントの現在時刻が 12:00:00、NTPサーバの現在時刻が12:01:00だったとしましょう。(12:01:00が正しい時刻という想定)
で、実際の送信処理に1秒かかったとすると、t2は 12:01:01 になります。
さて、これで t2-t1 を計算するとこうなります。
12:01:01-12:00:00= 00:01:01
もちろん実際に通信に要した時間は1秒ですが、見た目の送信時間は01分1秒となります。
同じように、受信時間も計算してみます。
今度はNTPサーバの内部処理に2秒、実際の受信通信に1秒かかったとしましょう。
すると、t3は12:01:03、t4は 12:00:04 となります。
結果、t4-r3 はこうなります。
12:00:04-12:01:03=(-00:00:59)
ここでは見た目の受信時間がマイナス値というわけのわからないことになっています。
こんなので本当に正しい値になるのでしょうか?
不思議に感じますが気にせず先に進みましょう。
さて、上述の手順(b)に従って次の計算をします。
クライアントの現在時刻+(送信時間-受信時間)÷2
これを計算するとこうなります。
12:00:04+(00:01:01-(-00:00:59) )÷2
=12:00:04+(00:02:00)÷2
=12:00:04+00:01:00
=12:01:04
いかがでしょうか。
実にシンプルな計算なのですが、01分の誤差が補正され正しい時刻が設定されました。
ただし、これは送信時間と受信時間の絶対値(マイナス記号を取った値)に大きな差がないことが条件です。
計算を見ればわかりますが(送信時間-受信時間)を2で割っていますので、両者が大きく違っていると、計算で得られる時刻が実際と違ってしまいます。
上のパターンで、送信時間が1秒、受信時間が10秒だとすると次の計算となります。
受信時間
=12:00:13-12:01:03=(-00:00:50)
正しい時刻
=12:00:13+(00:01:01-(-00:00:50) )÷2
=12:00:13+(00:01:51)÷2
=12:00:13+00:00:55
=12:01:08
時刻がズレてしまっていますよね。
これは、送信時間と受信時間が大きく違っていると、得られる時刻にズレが生ずるためです。
これでは正しい時刻が得られません。だからNTPではズレが激しい場合には、最初からやり直しをすることになっているのです。
まとめ
サーバでトラブルが起きると、担当者はそのサーバ上のログ情報を確認します。
他のサーバとの接続でのトラブルの場合は、相手サーバの担当者も同じ様にログを確認します。
この時に重要なのは事象が起きた時刻です。
コンピュータ内部の時計もそれなりの性能ですが永遠に誤差が出ないわけではありません。
かといって、各サーバの時刻が合致していない状態では互いに調査が大変です。
こういったサーバ間の時刻を同期するためにNTPというプロトコル(通信手順)が使われます。
NTPでは複数のコンピュータ間の時刻を同期させることができます。
現在のインターネットでは、NTPによってサーバ間に時刻同期が行われています。
なお、今回は説明しませんでしたが、NTPでは全世界のサーバ時刻を合わせる際に一部サーバに負荷がかからない仕組みなども決められています。
このNTPが発表されたのは1990年初頭で、国内ではインターネットというコトバすら一般的ではありませんでした。
こんな時期にサーバ間の時刻同期にまで考慮していた先見の明には驚くばかりです。
今回はNTPという時刻同期プロトコルについてお話をしました。
次回もお楽しみに。
(本稿は 2024年2月に作成しました)