Carpe Diem

備忘録

うるう秒対応

概要

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が挿入されます。

うるう秒による問題

  1. Linuxカーネルのバグを踏む可能性
  2. 「60秒」という時刻を、言語処理系やデータベース、アプリケーション等が正しく処理できるかどうか
  3. 59秒が2回生じることによるログの前後関係の逆転

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モードが良いです。

パブリッククラウドの対応

Google

前後10時間に0.0014パーセント遅いクロックを実行することで、あわせて20時間全体で1秒分をずらす運用を行うことを発表してます。

Leap Smear  |  Public NTP  |  Google Developers

slewモードに近いじんわーり型ですね。

AWS

EC2(AmazonLinux)やマネージドなサービスは59秒を2回実行します。Webコンソール自体はじんわーりと対応します。

Amazon Web Services ブログ: 事前にご確認ください - AWSでのうるう秒対応【更新】

Amazonインスタンスであればntp.conf

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で対応できるようになりました。

aws.amazon.com

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コンテナの内部時計はホストの内部時計と同期されるので、ホストの方できちんと設定できていれば大丈夫です。

stackoverflow.com

ソース