QandA
Q

業務システム内のWindows 2000 ServerやWindows Server 2003マシンの時刻を同期させる方法に苦慮しています。業務要件上の整合性を確保するため,時刻の後戻りは許されない状況にあります。

 当初,Windows Timeサービスで時刻を同期していたところ,時刻が後戻りする現象がまれに発生することが分かりました。そのため,暫定的にWindows Timeサービスを停止して運用していたのですが,それでもサーバーの時刻が後戻りするという事象が発生してしまい,原因と対処策に苦慮しています。

 Windows Timeサービス以外に勝手に時刻を同期してしまう機能が存在するのでしょうか,また,確実に後戻りさせずに時刻を同期させる方法はないのでしょうか?

A

最近はセキュリティに対する意識が向上してきており,ログを適切に監視するためにシステムの時刻同期を実施するケースが増えてきています。ただし,コンピュータの時刻が実際より進んでいる場合に単純に時刻を同期すると,ご質問のように対象のコンピュータ上では時刻が戻るという現象が発生することがあります。

 時刻が後戻りしてしまうと,未来の日付のファイルやデータが存在してシステム・トラブルが発生したり,ログ・ファイルの日付が戻ってしまうことでログ・ファイルの監視製品が異常動作したりする,といった様々な問題が発生する原因となります。このため,特に重要なサーバーで時刻が後戻りすることは望ましくありません。

後戻りがあり得る標準機能での同期
 WindowsマシンやUNIX上のSambaの間ではSMBプロトコルを使って時刻を同期させることも可能です。しかし,ネットワーク機器なども含めてシステム全体の時刻を同期したい場合は,通常RFCで標準化されているNTP(RFC1305)やNTPを簡易化したSNTP(RFC2030)を利用します。


△ 図をクリックすると拡大されます
図2 ●Windowsで時刻の後戻りが発生するケース
 Windows 2000以降のActive Directoryドメインでも,Kerberos認証を用いているため,デフォルトではドメインに所属するコンピュータとドメイン・コントローラ(DC)との間でSNTPプロトコルやNTPプロトコルを使って自動的に時刻を同期する実装になっています(サポート技術情報224799参照)。このときに使うSNTPクライアント/サーバーがWindows Timeサービスです。

 Windows Timeサービスは,時刻のずれが3分以内の場合は時刻の後戻りを発生させずに同期するようになっています。しかし,それ以上の時刻のずれがあった場合は,後戻りさせて即座に時刻を同期してしまいます(図2)。

 システムを安定運用している状態で,常時Windows Timeサービスを使って時刻を同期していれば,通常は時刻が3分もずれてしまうような事態は発生しにくいでしょう。しかし,可能性が全くないわけではありません。コンピュータの内蔵時計の問題以外に,明示的に時刻を同期しなくても実行しただけで時刻が進んでしまうといったアプリケーションによる問題が発生することもあります。このため,“絶対に”時刻の後戻りを発生させたくない場合は,Windows Timeサービスによる時刻同期は避けるべきでしょう。

ハードとの強制同期でずれることも
Windows Timeサービスを停止させれば,OSが勝手に外部のコンピュータと時刻を同期することはなくなります。そのため,コンピュータ単体でみれば,一見時刻の後戻りは発生しなくなるように思います。しかし,この場合でも実はご質問のように時刻の後戻りが発生してしまうケースがあります。

 Windows 2000などのOSでは,コンピュータがハードウエア的に保持している時刻を起動時に読み込んだ後,ハードウエアの時計とは独立してOSが時刻を管理します。これはLinuxなどのOSも同様です。

 しかし,Linuxの場合,起動後はhwclockコマンドなどで明示的に操作しない限りハードウエアの時刻を参照しません。このため,OS実行中に時刻の後戻りすることは原理的にあり得ませんが,Windows NT系列のOSでは,起動後も1時間ごとにハードウエアを参照しています(サポート技術情報の232488参照)。そして,OSとハードウエアの間で時刻のずれが1分以上ある場合は,ハードウエアに合わせて時刻を同期します。このため,OSの時刻がハードウエアよりも大きく進んでしまうと,やはり時刻の後戻りが発生してしまう可能性があります。

ntpdのslewモードで後戻りせずに同期
 残念ながら,現在のところWindows2000/XP/2003単体で時刻の後戻りを発生させずに同期を保証するツールはありません。UNIXでは標準として広く用いられているntpd(該当サイト)のフリーウエア版を使うことでNTP/SNTPによる時刻同期を実施するのが現実的でしょう。

 ntpdには,即座に時刻を同期するstepモード以外に,時刻を徐々に同期させるslewモードが用意されています。デフォルトでは,slewモードは時刻のずれが128ミリ秒(ms)以内のときのみ用いられますが,「-x」オプションでslewモードによる時刻同期を強制可能です。なお,SNTPによる時刻同期を実現する「ntpdate」というntpdの付属コマンドは通常-Bオプションでslewモードの強制が可能ですが,WindowsではAPIの実装に起因する制約で利用できませんのでご注意ください。

 ntpdの実装では,slewモードによる時刻のずれの補正は毎秒0.5msに制限されています。このため,1秒の時刻のずれを補正するのに2000秒(33分20秒)という長い時間が必要となり,1日で修正できるのは最大でも43秒です。分単位で時刻が進んでしまっている場合は,対象のコンピュータを一度停止させ同期元の時刻が追い付くのを待ってから起動するか,別にプログラムを組み合わせたほうがよいでしょう。

後戻りを発生させない時刻同期の詳細


△ 図をクリックすると拡大されます
図3●時刻の後戻りを発生させずに時刻を同期の方法
 最後に,ntpdのslewモードやWindowsTimeサービスの180秒以内の同期で,なぜ時刻を後戻りさせずに同期できるかを説明します。

 一般的なPC互換機の場合,約10msごとにハードウエアによる通知(ハードウエア的なタイマー割り込み)が発生します(図3)。OS側ではこれを受けてOSの保持する時刻を約10ms進めるという処理を繰り返します(Linuxなどでも同様)。また,Windowsでは,デフォルトで前述したハードウエアとの時刻の補正処理も有効になっています。

 しかし,SetSystemTimeAdjustment()というWin32 APIの関数を使えば,ハードウエアからの通知に合わせて加算するOSの時刻を自由に設定できます。例えば,通知の度に進めるOSの時刻を半分の5msにすればOSの時刻は実際よりゆっくりと進むので,結果として時刻の後戻りを発生させずに時刻を同期できます。この場合,前述した時刻の補正処理は自動的に無効となり,意図しない時刻の後戻りが発生することもありません。


△ 図をクリックすると拡大されます
図4●SetSystemTimeAdjustment()関数の動作を確認するために作成した独自ツール「timeadjx」
 筆者は,このAPIの動作を検証するために「timeadjx」と呼ぶ簡単なツールを作ってみました(該当サイト)。このツールをgetオプションで実行すると,GetSystemTimeAdjustment()関数を呼び出して該当コンピュータの割り込み発生時の加算時刻,ハードウエア割り込み間隔,自動補正の状態を表示します(図4)。setオプションでSetSystemTimeAdjustment()関数を呼び出し割り込み発生時に加算する時刻を2倍にしてからgetオプションを実行すると,確かに加算時刻が2倍になるとともに,自動補正が無効となっています。この状態で日付と時刻のプロパティで時計を確認してみると,秒針が通常の2倍の速度で動作していることが分かります。

高橋 基信