2015年うるう秒の検証方法と検証結果 (Amazon Linux, CentOS)
日本時間 2015/07/01 08:59:59 から 09:00:00 の間にうるう秒が挿入されます。
検証手順と、どのように対応すれば良さそうか検証した結果をまとめます。
情報は、すべて執筆時(2015/06/18)のものです。
検証環境は Amazon Linux 2015.03、Timezone は Asia/Tokyo です。
- うるう秒を挿入させない
- 時間遡行を起こさせない
- 08:59:60 を刻ませない
の 3 点に対応するための方法を記します。
結論
追記(2015/06/25):
ntpd を事前に止める手順で、すでに Leap Indicator(LI) がセットされている場合は、
ntptime -s 0 を実行する必要があります。
実行する必要があるケースは、ntptime で確認できます。
$ ntptime ntp_gettime() returns code 1 (INS) time d93d0376.885cfeac Tue, Jun 30 2015 21:00:54.532, (.532669028), maximum error 145742 us, estimated error 97 us, TAI offset 0 ntp_adjtime() returns code 1 (INS) modes 0x0 (), offset -44.746 us, frequency -26.426 ppm, interval 1 s, maximum error 145742 us, estimated error 97 us, status 0x6011 (PLL,INS,NANO,MODE), time constant 10, precision 0.001 us, tolerance 500 ppm,
ntp_adjtime() returns code 1 (INS) や status に INS が入っていることから、
うるう秒が挿入されることがわかると思います。
この場合は、ntptime -s 0 を実行すると status をクリアすることができます。
$ ntptime -s 0 ntp_gettime() returns code 1 (INS) time d93d03fa.58b9882c Tue, Jun 30 2015 21:03:06.346, (.346581769), maximum error 211742 us, estimated error 97 us, TAI offset 0 ntp_adjtime() returns code 0 (OK) modes 0x10 (STATUS), offset -43.000 us, frequency -26.426 ppm, interval 1 s, maximum error 211742 us, estimated error 97 us, status 0x0 (), time constant 10, precision 1.000 us, tolerance 500 ppm,
ntp_adjtime() returns code 0 (OK) と status から INS が消えているので OK です。
詳しくは Leap Second Insertion フラグを受信後にそのフラグを削除する - Red Hat Customer Portal の回避策 1をご確認ください。
ntpd をアップデートして SLEW モードで実行する手順では、
ntptime -s 0 -f 0 を実行したほうが良いそうですが、
SLEW モードで動かしていれば LI がセットされていてもうるう秒が挿入されないので問題ない認識です(あまり自信ないです...)。
-f 0 は周波数オフセットをリセットするそうですが、リセット前後で何がどう変わるかはソースコードを読んでもよくわかりませんでした...(少なくとも、時間遡行が起こることはなさそうです)
-s と -f は、timex 構造体の status と freq に 0 を代入しているようです。
- s と -f の処理は、以下をご確認ください。
- -f : https://github.com/ntp-project/ntp/blob/stable/util/ntptime.c#L138-L141
- -s : https://github.com/ntp-project/ntp/blob/stable/util/ntptime.c#L157-L162
timex 構造体については Man page of ADJTIMEX をご確認ください。
長いので結論から書きます。
ntpd には SLEW モードで動作させていても、うるう秒が挿入されてしまうバグのあるバージョンがあります(Bug 1190619 – ntpd -x steps clock on leap second)。
- うるう秒挿入時刻より前に、バグ修正済みの ntpd を SLEW モードで動作させておく
- うるう秒挿入時刻には ntpd を止めておき、うるう秒挿入時刻が過ぎたあとに ntpd を SLEW モードで動作させる
- Timezone を right/Japan にしていた場合は、Asia/Tokyo にする
- うるう秒を挿入するという情報(LI)をリセットする
のどちらかの方法で前述した 3 点に対応することができます。
環境ごとの対応方法は以下のとおりです。
Amazon Linux 2013.09 以前(と CentOS 5, 7)
- Timezone を right/Japan にしている場合は Asia/Tokyo に変更
- 08:59:60 を刻んでも問題なければ、right/Japan で問題ない(はず)
- tzdata を更新せず、2015年のうるう秒のデータが入っていない場合も right/Japan で問題なし(08:59:60 を刻まない)
- うるう秒挿入時刻の前に ntpd を止めておく
- うるう秒を挿入するという情報(LI)をリセットする(ntptime -s 0)
- うるう秒挿入時刻の後に ntpd を SLEW モードで起動
Amazon Linux が 2014.03 以降と 2013.09 以前で対応方法が違うのは、
ntpd のアップデートは出来ますが、glibc のバージョンも依存関係で上がってしまうためです。
CentOS 5 と 7 はバグ修正済みの RPM が配布されていませんでした(RPM の Changelog しかみていないので間違っている可能性があります)。
また、CentOS 5 は tzdata を更新しても 2015年のうるう秒のデータは更新されないようでした。
tzdata の中身は、以下のコマンドで確認することができます。
/usr/sbin/zdump -v /usr/share/zoneinfo/right/Japan
追記(2015/06/23):
古い Kernel を考慮していない対応方法になっていました。
2012年のうるう秒挿入時に高負荷になる問題が修正されていない Kernel を使っている場合は、
Kernel をアップデートする必要があります。
修正済みの場合、CentOS 6 の Kernel の Changelog に、以下があると思います。
$ rpm -qa --changelog kernel ... [kernel] timekeeping: Fix leapsecond triggered load spike issue (Prarit Bhargava) [836803]
2012年の Linux Kernel の不具合については、2012 年 7 月 1 日のうるう秒挿入時に発生した Linux カーネルの不具合に関する情報 が参考になりました。
ありがとうございます。
ntpd のアップデート方法
以下のとおりです。
SLEW モードで起動する方法
- /etc/sysconfig/ntpd の OPTIONS に "-x" を追加
- ntp.conf に "tinker step 0" を設定
のいずれかの対応を行い、ntpd を再起動すれば SLEW モードで起動できます。
ここまでが、結論と対応方法についてです。
以降では、SLEW モードやtzdata、検証方法について説明していきます。
SLEW モード
すでに何度も登場していますが、結論を最初に書いた関係で説明がなかったので書いておきます。
通常、ntpd は STEP モードという時間を一気に調整するモードで動作しています。
SLEW モードは、時間を一気に調整せず 1 秒あたり最大 0.5ms ずつ時間を調整します。
これにより、うるう秒を挿入された場合でも、時間遡行を起こさずに時間を調整することができます。
詳細については Stray Penguin - Linux Memo (ntpd) が大変参考になりました。
ありがとうございます。
tzdata
こちらもすでに何度も登場していますが、タイムゾーンデータです。
サマータイムやうるう秒の情報などが記載されています。
ntpd を動かしていない場合は、tzdata を参照してうるう秒を刻むことになります。
right/Japan のデータを見ると、
/usr/sbin/zdump -v /usr/share/zoneinfo/right/Japan ... /usr/share/zoneinfo/right/Japan Sat Jun 30 23:59:60 2012 UTC = Sun Jul 1 08:59:60 2012 JST isdst=0 gmtoff=32400 /usr/share/zoneinfo/right/Japan Sun Jul 1 00:00:00 2012 UTC = Sun Jul 1 09:00:00 2012 JST isdst=0 gmtoff=32400 /usr/share/zoneinfo/right/Japan Tue Jun 30 23:59:60 2015 UTC = Wed Jul 1 08:59:60 2015 JST isdst=0 gmtoff=32400 /usr/share/zoneinfo/right/Japan Wed Jul 1 00:00:00 2015 UTC = Wed Jul 1 09:00:00 2015 JST isdst=0 gmtoff=32400 /usr/share/zoneinfo/right/Japan 9223372036854689407 = NULL /usr/share/zoneinfo/right/Japan 9223372036854775807 = NULL
2015年のうるう秒の情報があります。
この状態で Timezone を right/Japan にして、
ntpd を動かさずにうるう秒の時刻を迎えると 08:59:60 を刻みます。
Asia/Tokyo を見ると、
/usr/sbin/zdump -v /usr/share/zoneinfo/Asia/Tokyo ... /usr/share/zoneinfo/Asia/Tokyo Sat May 5 16:59:59 1951 UTC = Sun May 6 01:59:59 1951 JST isdst=0 gmtoff=32400 /usr/share/zoneinfo/Asia/Tokyo Sat May 5 17:00:00 1951 UTC = Sun May 6 03:00:00 1951 JDT isdst=1 gmtoff=36000 /usr/share/zoneinfo/Asia/Tokyo Fri Sep 7 15:59:59 1951 UTC = Sat Sep 8 01:59:59 1951 JDT isdst=1 gmtoff=36000 /usr/share/zoneinfo/Asia/Tokyo Fri Sep 7 16:00:00 1951 UTC = Sat Sep 8 01:00:00 1951 JST isdst=0 gmtoff=32400 /usr/share/zoneinfo/Asia/Tokyo 9223372036854689407 = NULL /usr/share/zoneinfo/Asia/Tokyo 9223372036854775807 = NULL
2015年のうるう秒の情報がありません。
08:59:60 を刻ませないためには、
ntpd を動かしていない場合 tzdata を参照するので、
うるう秒の情報が含まれていない Timezone である Asia/Tokyo にする必要があることがわかると思います。
検証方法
検証方法は 【RHEL】這いよる閏秒 7月1日9:00(JST)の挙動(3年ぶりだな) | Pocketstudio.jp log3 を参考に致しました。
ありがとうございます。
以降、日本標準時プロジェクト 関連資料 のプログラム(以下、sntp.pl) を動かすサーバを NTP Server、
NTP Server と同期するサーバを NTP Client とします。
NTP Server
sntp.pl をそのまま使うと timegm の引数が多くて検証する度に変更するのが大変だったのと、
うるう秒を発生させる時間をJSTで指定したかったので patch を書きました。
以下のモジュールをインストールします。
$ yum install -y perl-DateTime perl-DateTime-Format-Strptime perl-Time-HiRes
perl-Time-HiRes は patch を当てない場合も必要です。
以下の patch を sntp.pl.patch などと保存し、
patch sntp.pl < sntp.pl.patch
で patch を当てます。
patch を当てたら、以下のように実行します。
NTP は well known port を使いますので、root 権限で実行してください。
./sntp.pl 2015-06-18T20:15:00
これで NTP Server 側の準備は完了です。
この場合、NTP Client 側では 2015/06/18 20:15:00(JST) にうるう秒が挿入されます。
十数分後くらいにうるう秒を挿入するようにすると良いです。
NTP Client
NTP Server と同期する側の設定です。
NTP Server の IP を 192.168.12.34 とします。
Timezone は Asia/Tokyo にします。
ntp.conf を変更して同期するサーバを NTP Server にします。
# ntp.conf server 192.168.12.34
以下を実行して NTP Server と同期し、ntpd を起動します。
こちらも root 権限が必要です。
$ service ntpd stop && /usr/sbin/ntpdate 192.168.12.34 && service ntpd start Shutting down ntpd: [ OK ] 1 Jul 08:48:35 ntpdate[21386]: step time server 192.168.12.34 offset 60.000945 sec Starting ntpd: [ OK ]
NTP Client の時間が 2015/07/01 09:00:00 のおよそ10分前になっていると思います。
時刻の推移を確認するのに以下を実行します。
while :; do date +'%Y-%m-%d %H:%M:%S.%3N'; usleep 100000; done
これで NTP Client 側の準備は完了です。
あとは、うるう秒挿入時刻を待つだけです。
検証時の注意点
以下が、検証時にはまったことです。
- ntp.conf をデフォルトの状態で使用する場合、うるう秒挿入までの時間が早過ぎると Leap Indicator(LI, leap=01) がセットされない
- だいたい3 分半 〜 5 分の間くらいで LI がセットされるようでした
- うるう秒挿入を10分後くらいに設定しないと、うるう秒が挿入されない
- tzdata を更新した状態で、Timezone を right/Japan などのうるう秒が含まれているものにした場合、2016/07/01 08:59:35 あたりでうるう秒が挿入された
LI がセットされているかどうかは、以下のコマンドで確認することができます。
ntpq -p -c rv
検証結果
ntpd のバージョンを上げて、SLEW モードで起動した場合
/var/log/messages に何も出力されず、うるう秒も挿入されていないと思います。
- うるう秒を挿入させない
- 時間遡行を起こさせない
- 08:59:60 を刻ませない
がすべて達成されている状態です。
ntpd のバージョンを上げず、STEP モードで起動した場合
/var/log/messages に
Jun 30 23:59:59 ntp-client kernel: [2009692.154198] Clock: inserting leap second 23:59:60 UTC
というログが出力されています。
時間の推移を確認すると、
08:59:59.043200 08:59:59.143489 08:59:59.243810 08:59:59.344059 08:59:59.444374 08:59:59.544695 08:59:59.644945 08:59:59.745170 08:59:59.845425 --------------------- 08:59:59.945695 08:59:59.045997 --------------------- 08:59:59.146308 08:59:59.246599 08:59:59.346916 08:59:59.447196 08:59:59.547398 08:59:59.647677 08:59:59.747925 08:59:59.848165 08:59:59.948395 09:00:00.048650 09:00:00.148907 09:00:00.249210 09:00:00.349473 09:00:00.449769 09:00:00.550032 09:00:00.650247 09:00:00.750502 09:00:00.850745 09:00:00.951033
うるう秒が挿入され、08:59:59 が2回刻まれていることがわかります。
ntpd のバージョンを上げずに、SLEW モードで実行した場合
08:59:59.029329 08:59:59.129500 08:59:59.229704 08:59:59.329902 08:59:59.430197 08:59:59.530375 08:59:59.630553 08:59:59.730777 08:59:59.830986 08:59:59.931246 09:00:00.031513 09:00:00.131779 09:00:00.231966 09:00:00.332222 09:00:00.432509 --------------------- 09:00:00.532794 08:59:59.633065 --------------------- 08:59:59.733321 08:59:59.833618 08:59:59.933873 09:00:00.034119 09:00:00.134407 09:00:00.234694 09:00:00.334972 09:00:00.435262 09:00:00.535558
09:00:00.532794 を過ぎたあとにうるう秒が挿入され、08:59:59.633065 になっています。
本来 SLEW モードで起動していれば巻き戻らないはずなのに、
時間が巻き戻ってしまいました。
このとき、/var/log/messages にログは出力されませんでした。
まとめ
2015年うるう秒の対応方法と検証結果を示しました。
2012年のうるう秒挿入時は、高負荷になる問題があったようですが、
同年に問題が対応されたようでしたので、
実環境で稼働しているミドルウェアやアプリケーションを動作させながらの検証は行いませんでした。
万全を期すのであれば、実環境と同じものを用意して検証を行うことをおすすめ致します。
08:59:60 を刻んでも良い場合は、うるう秒を含む tzdata を参照することで SLEW モードでの調整はほとんど不要となると思いますが、
ミドルウェアやアプリケーションが 08:59:60 を刻んだ場合にエラーが発生しないか十分に確認する必要がありそうです。
内容に誤りがある場合は、ご指摘いただければと思います。