2012年7月1日 08:59:59 秒(JST)の後に1秒が追加される、うるう秒が発生しま す。 うるう秒に関する基本的な情報は以下のNICTのページで説明されています。
このうるう秒発生時における、Linux上のNTPの動作について検証してみた所、 各種Linuxディストリビューションによって動作が異なる事が解ったのでまとめ てみました。
検証はNICTで公開されている 簡易NTPサーバー を利用して、LIフラグが01のパケットを受け取る方法で行いました。
うるう秒発生時の挙動として以下3種類のパターンが挙げられます。
kernelの機能を利用して時刻の補正を行う
LIパケット受信時、ntpdはシステムコールの adjtimex(2) を発行し、kernelの機能を利用して時刻の調整を行います。結果として、 うるう秒発生時に時間の逆行が発生します。
この動作は、IBMの 【Technical Notes】Linux システムクロックの『うるう秒』調整 で解説されている通りの動作となります。
該当ディストリビューション: CentOS 5(ntp-4.2.2p1-15), CentOS 6(ntp-4.2.4p8-2), Debian Lenny(ntp-4.2.4p4+dfsg-8lenny3)で確認
kernelの機能を利用せず時刻の補正を行う
うるう秒発生時、ntpdはclock_settime(2)を利用して時刻の調整を行いま す。結果として、時刻の進行が数ミリ秒遅れて逆行します。
ディストリビューション付属のntpdとしては未確認、KERNEL_PLL が無効で ビルドされたntpdでこの様な動作になりうる。古いkernelやntpdの環境は この動作になるかも
うるう秒発生時なにも行わない
うるう秒発生時以降、標準時との間に1秒の誤差が発生するが、その誤差 は徐々に補正されていきます。
該当ディストリビューション: Debian Squeeze(ntp-4.2.6.p2+dfsg-1+b1), Debian Wheezy(ntp-4.2.6.p5+dfsg-2)調べてないけど恐らくUbuntuも
各パターンにおける時刻の進行は以下の通りです。
以下の様なperlスクリプトで1ミリ秒毎にgettimeofday(2)を呼んで時刻の進行 を確認。gettimeofday.pl
逆行が発生するパターン(ntp-4.2.4 以前)
08:59:58.9 08:59:59.0 08:59:59.1 08:59:59.2 08:59:59.3 08:59:59.4 08:59:59.5 08:59:59.6 08:59:59.7 08:59:59.8 08:59:59.9 08:59:59.0 08:59:59.1 08:59:59.2 08:59:59.3 08:59:59.4 08:59:59.5 08:59:59.6 08:59:59.7 08:59:59.8 08:59:59.9 09:00:00.0
08:59:59.9の直後に08:59:59.0に戻っていることが解る
数ミリ秒遅れて逆行が発生するパターン(KERNEL_PLLを無効)
08:59:58.9 08:59:59.0 08:59:59.1 08:59:59.2 08:59:59.3 08:59:59.4 08:59:59.5 08:59:59.6 08:59:59.7 08:59:59.8 08:59:59.9 09:00:00.0 09:00:00.1 09:00:00.2 08:59:59.3 08:59:59.4 08:59:59.5 08:59:59.6 08:59:59.7 08:59:59.8 08:59:59.9 09:00:00.0
clock_settime(2)を利用して数ミリ秒遅れて逆行すると、こんな事になる。
なにもしないパターン(ntp 4.2.6 以降 Debian Squeeze, Wheezy など)
08:59:58.9 08:59:59.0 08:59:59.1 08:59:59.2 08:59:59.3 08:59:59.4 08:59:59.5 08:59:59.6 08:59:59.7 08:59:59.8 08:59:59.9 09:00:00.0
まとめ
ntp 4.2.4 と 4.2.6 で動作が異なる結果となりました。 恐らくは、ntp 4.2.4 の様にうるう秒の調整を行うのが正しい動作で、4.2.6 の様に何も行わないのはLIフラグ付きパケットのハンドリングに不具合がある のだろうと考えられます。
しかし、アプリケーションによっては時間の逆行が問題を引き起こす可能性が あるので、うるう秒の調整を行わず、時刻が単調に増加したほうが都合が良い 場合もあるでしょう。
気になる人は実際のうるう秒の挿入時に確認してみては如何でしょうか。上記 の結果と異なっていたら教えて下さい。
確認方法
確認方法のメモ
LIフラグ受信時に strace -e 'adjtimex' -p ntpdのPID を実行してadjtimex(2)がstatus=STA_PLL|STA_INS|0x2000を伴って呼ばれればパターン1。STA_INSを伴ないわないadjtimex(2)呼び出しは頻繁に行われているので注意。
adjtimex({...
status=STA_PLL|STA_INS|0x2000,
...}) = 1 (TIME_INS)
その後、うるう秒発生時にはkernelメッセージ
Clock: inserting leap second 23:59:60 UTC
を確認出来ます。
うるう秒発生時に strace -e 'clock_settime' -p ntpdのPID を実行してclock_settime(2)を確認できればパターン2
# ntpq -c "readvar 0 leap"
を確認し、01フラグを受け取っているのに何も行わなければパターン3
追記(2012年うるう秒を終えて)
Debian Wheezyなどでも期待通り、補正が行われたサーバーもあった。
adjtimex(8)というユーザーランドツールがあるそうなので、これで確認した方が良い。
Kernelがクラッシュする事案があった
MySQLなどのアプリケーションがCPU食いつぶす事案があった。