概要
2017/01/01 09:00:00(JST)にうるう秒が挿入されますが、ちゃんと問題点や対応方法を理解してなかったのでまとめ。
前提知識
うるう秒発生でどうなるか
ntpを入れているか、tzdataが更新されているかによって動作が異なります。
JST | ntp (stepモード) |
tzdata | 未対応 |
---|---|---|---|
08:59:59 | 08:59:59 | 08:59:59 | 08:59:59 |
08:59:60 うるう秒発生 |
08:59:59 | 08:59:60 | 09:00:00 |
09:00:00 | 09:00:00 | 09:00:00 | 09:00:01 |
09:00:01 | 09:00:01 | 09:00:01 | 09:00:02 |
このようにntpであれば08:59:59が2回、tzdataであれば08:59:60が挿入されます。
うるう秒による問題
aは正直その時にならないと分からないので「うるう秒を挿入しないこと」が一番の対応になります。
bは言語系やDBが正しく処理できれば大丈夫ですが、これも検証が大変なので保証がない限り避けた方が良さそうです。
cは金融系など、かっちりしたシステムでなければ許容できるかと思います。
ntpでうるう秒時刻が修正されるタイミング
上位NTPサーバからうるう秒発生の24時間前にLeap Indicator(LI)フラグが渡されます。
これがあると08:59:59を2回繰り返します。同期タイミングに実行されるわけではありません。
うるう秒対応の方法によってはLIフラグを消してゴニョゴニョするケースもありますが、その場合stepモードだと08:59:59という決まった時刻でなくntpの同期タイミングに強制的に修正されるので、サーバによって修正時刻が異なり、それが元でログの前後関係がおかしくなるケースがありますので注意してください。
ntpの同期間隔
NTPはミリ秒単位でサーバ・クライアント間で時刻を同期します。
同期間隔については起動時は64秒ですが、周波数のずれが調整されて小さくなるに従い、128秒、256秒と倍々に増えていき、最大1024秒まで間隔を延ばします。ズレが増えてサーバの時刻に再同期し直した場合は64秒間隔に戻ります。
stepモードとslewモード
stepモード
stepモードでは、NTPサーバーとシステム時刻に±128ミリ秒以上の差が生じると、NTPサーバー時刻に一気に時刻合わせを行います。
この一気に時刻合わせが同じ秒数を出してしまう原因でもあります。
slewモード
一方slewモードはズレを検知してから1秒間に最大5ミリ秒ずつシステムの時刻補正を行います。じんわーりと数分〜数十分かけてサーバの時刻と同期されます。
なのでうるう秒のズレが発生しても同じ秒数を出すといったことがありません。そのためうるう秒の補正にこのslewモードを使う人も多いです。
では「最初からslewモードのほうが良いの?」と思うかもしれないですが、1秒間に最大5ミリ秒ずつしか調整できないということは大幅にずれた時に何時間、何十時間もかけないと修正できないという問題があるので基本的にはstepモードが良いです。
パブリッククラウドの対応
前後10時間に0.0014パーセント遅いクロックを実行することで、あわせて20時間全体で1秒分をずらす運用を行うことを発表してます。
Leap Smear | Public NTP | Google Developers
slewモードに近いじんわーり型ですね。
AWS
EC2(AmazonLinux)やマネージドなサービスは59秒を2回実行します。Webコンソール自体はじんわーりと対応します。
Amazon Web Services ブログ: 事前にご確認ください - AWSでのうるう秒対応【更新】
server 0.amazon.pool.ntp.org iburst server 1.amazon.pool.ntp.org iburst server 2.amazon.pool.ntp.org iburst server 3.amazon.pool.ntp.org iburst
を見ています。自前でUbuntuなどでntpを入れている場合は
server 0.ubuntu.pool.ntp.org server 1.ubuntu.pool.ntp.org server 2.ubuntu.pool.ntp.org server 3.ubuntu.pool.ntp.org
を見ているので、注意してください。
追記(2017/11/30)
AWSでもうるう秒をLeap Smearingで対応できるようになりました。
server 169.254.169.123 prefer iburst
をntp.confに設定すれば使えます。
見てわかるように169.254.169.123
のリンクローカル IP アドレスを介してアクセスできるので、外部のインターネットアクセスする必要なくプライベートサブネット内から安全にアクセスできます。
Amazon ECS-Optimized AMI - Amazon Elastic Container Service
など、Amazonが提供している一部のAMIでは予め対応されています。
サービスとしての対応方法
a. パブリッククラウドの場合
AWSの場合は169.254.169.123
を設定
前述したようにVPCにあるサーバであれば169.254.169.123
を使えばうるう秒対応したntpを利用可能です。
それ以外はGooglePublicNTPを上位NTPサーバとして設定
ntp.conf
の上位NTPサーバを以下に設定します。注意としては他の上位NTPサーバ(non-leap-smearingな)と混ぜてはいけません。
server time1.google.com iburst server time2.google.com iburst server time3.google.com iburst server time4.google.com iburst
後はじんわーりとGoogleのNTPサーバがずれ始め、それに合わせて自分のサーバのNTPが時刻を同期してくれます。128ミリ秒以上ずれたら同期されるのでうるう秒は挿入されません。
同期されているかの確認はntpq -p
で行います。
$ ntpq -p remote refid st t when poll reach delay offset jitter ============================================================================== +time1.google.co 71.79.79.71 2 u 51 64 77 285.569 -0.418 1.205 *time2.google.co 71.79.79.71 2 u 53 64 77 269.602 -2.611 1.107 +time3.google.co 71.79.79.71 2 u 50 64 77 373.001 -2.991 1.445 -time4.google.co 71.79.79.71 2 u 53 64 77 77.777 21.552 1.468
各項目は以下の通りです。
項目 | 説明 |
---|---|
先頭の記号 | *: 同期中 +: 同期可能 -: jitterのズレがremoteの方が大きいので同期しない 空白: reject。要求が不到達、もしくは距離が遠い |
offset | remoteの時計と内部時計のズレ(ミリ秒) |
jitter | 誤差の値(ミリ秒)。小さいほど精度が高い |
delay | remoteとの通信のためにネットワーク往復にかかる通信時間(ミリ秒) |
poll | 同期する頻度(秒) |
reach | 成功回数。8進数で表示。8回全て同期成功すると377になる |
b. 59秒を2回実行することを許容する
システム的に59秒が巻き戻って2回実行されることを許容できるのであれば、ntpを利用するだけでOKです。
ただし上位NTPサーバがどこを向いているか、また上位NTPサーバがLeap Indicatorを扱っているかを確認した方が良いです。
問題が起きないよう全て同じサーバを向くようにしたほうが安全です。
c. slewモードで自分でじんわーり対応する
LIを除去し、うるう秒の挿入を防いだ後でゆっくり正しい時刻に同期させます。デメリットとしてはその時にPCに張り付いて作業する必要があるので台数が多かったりすると監視コストが大きいです。
Dockerコンテナの場合はどうすればよいのか
Dockerコンテナの内部時計はホストの内部時計と同期されるので、ホストの方できちんと設定できていれば大丈夫です。