w32time における SLEW モード / STEPモードでの時刻同期条件について

Last Update: feedback 共有

本記事はマイクロソフト社員によって公開されております。

こんにちは。Windows Commercial Support Directory Services チームです。
本記事では、各 Windows OS バージョン別に、w32time 時刻同期 における SLEW モード及び STEP モードの判定条件についてご紹介いたします。

既にご存知の方も多くいらっしゃるかと存じますが、Windows OS において時刻同期処理を行う w32time サービスでは、SLEW モード / STEP モード いずれかを明示的に指定して時刻同期を行う設定は無く、w32time 関連の各種レジストリ値や、時刻ずれの大きさより算出される計算式 (条件式) から SLEW モード / STEP モード のどちらで時刻同期を行うかが動的に決定される仕組みとなっています。

しかしながら、運用やアプリケーション要件によっては時刻の巻き戻りが許容できず、出来る限り SLEW モードで時刻同期を行いたいといったご要望を弊社サポート窓口でも多くお伺いしております。
今回の記事では、各 Windows OS バージョンにおける条件式や既定値での条件についてお纏めしておりますので、本内容が時刻同期設計の一助になれば幸いでございます。

条件式

以下 2 つの条件をいずれも満たす場合に、SLEW モードで時刻同期処理が行われます。

■ Windows Server 2012 R2/Windows 8.1 以前

// 条件式
1. CurrentTimeOffset / (PhaseCorrectRate * UpdateInterval) <= System Clock Rate / 2
2. CurrentTimeOffset <= MaxAllowedPhaseOffset

■ Windows Server 2016/Windows 10 以降 (※)

// 事前計算式
PhaseCorrection = CurrentTimeOffset / (16 * PhaseCorrectRate * pollIntervalInSeconds)
MaximumCorrection = CurrentTimeOffset / (UpdateInterval / 100)
PhaseCorrection = min(PhaseCorrection, MaximumCorrection)

※ いずれかの小さい値を PhaseCorrection に代入します。

// 条件式    
1. PhaseCorrection <= System Clock Rate / 2
2. CurrentTimeOffset <= MaxAllowedPhaseOffset

※ 条件式 1 は、事前計算式にて、MaximumCorrection が利用されない場合には、以下と同一になります。
1. CurrentTimeOffset / (16 * PhaseCorrectRate * pollIntervalInSeconds) <= System Clock Rate / 2
※ <注意> Windows Server 2019 及び、Windows 10 1809 の条件式について

Windows Server 2019 及び、Windows 10 1809 につきましては、計算式に不具合があり、上記条件式とは異なり以下の計算式となります。

// 事前計算式
PhaseCorrection = CurrentTimeOffset / (PhaseCorrectRate * pollIntervalInSeconds / 4)
MaximumCorrection = CurrentTimeOffset / (UpdateInterval / 100)
PhaseCorrection = min(PhaseCorrection, MaximumCorrection)

※ いずれかの小さい値を PhaseCorrection に代入します。

// 条件式    
1. PhaseCorrection <= System Clock Rate / 2
2. CurrentTimeOffset <= MaxAllowedPhaseOffset

※ 条件式 1 は、事前計算式にて、MaximumCorrection が利用されない場合には、以下と同一になります。
1. CurrentTimeOffset / (PhaseCorrectRate * pollIntervalInSeconds / 4) <= System Clock Rate / 2

なお、本問題は 2021 年 10 月のセキュリティ以外の修正プログラム (KB5006744) にて修正されております。そのため、KB5006744 含め以降の更新プログラムを適用している環境の場合には、上述の "Windows Server 2016/Windows 10 以降" の計算式と同一となります。混乱を招き大変恐れ入りますが、ご注意頂けますようお願いいたします。

条件式で利用する値について

上記の条件式にて利用する値の概要と、設定値の確認場所は下記の通りです。

■ CurrentTimeOffset

NTP Client が NTP Server に対してポーリングした際の NTP Client と NTP Server の時刻の差です。計算式では、clock ticks に変換して計算を行います。

(例: 1 秒 = 1 * 10^7 clock ticks = 10,000,000 clock ticks)

■ MaxAllowedPhaseOffset

各条件式 2 の通り、SLEW モードで時刻同期を行うことが許容される時刻差を定義した値です。
本値は、下記のレジストリで設定されており、単位は sec のため、clock ticks に変換して計算を行います。

  • レジストリ キー: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config
  • 値の名前: MaxAllowedPhaseOffset
■ PhaseCorrectRate / UpdateInterval

NTP Server から受け取った時刻サンプルをもとに、どのくらいの間隔で、どのくらいの速度で時刻をあわせていくかの傾きを示す設定値です。
これらの値は、下記のレジストリで設定されています。計算式においては10進数に変換した値でそのまま計算を行います。

  • レジストリ キー: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config
  • 値の名前: PhaseCorrectRate
  • 値の名前: UpdateInterval
■ pollIntervalInSeconds

NTP Server への現在のポーリング間隔です。現在の時刻の差等に依存して MaxPollInterval 及び MinPollInterval の間で動的に変化します。現在の pollIntervalInSeconds の値は、”w32tm /query /status” コマンドで確認することが可能です。
(出力結果の “ポーリング間隔:” に記載の値です)
計算式では、sec に変換して計算を行うため、現在のポーリング間隔を n とした場合、2^n を計算式で利用します。
例えば、現在のポーリング間隔が、10 の場合、 2^10 = 1024 sec となります。

■ System Clock Rate

システムのクロック レートを表す値です。通常であれば、シングル プロセッサーでは約 10ms (100,000 clock tics)、マルチ プロセッサーでは約 15ms (150,000 clock tics) となりますが、”w32tm /query /status /verbose” コマンドにて、実際の Sytem Clock Rate を確認することが可能です。
(出力結果の “クロック レート:” に記載の値です)
計算式では、clock ticks に変換して計算を行います。

計算例

実際に計算式に合せて、実際の計算例をご紹介します。
ここでは例として、Windows Server 2016 WORKGROUP 環境における既定値にて計算を行います。

  • 計算式に利用するレジストリ値の抜粋 (計算式では10進数に変換した値を利用します)
    “PhaseCorrectRate”=dword:0x1
    “MinPollInterval”=dword:0x6
    “MaxPollInterval”=dword:0xa
    “UpdateInterval”=dword:0x64
    “MaxAllowedPhaseOffset”=dword:0x1

※前項の記載の通り、pollIntervalInSeconds は変化しますので、今回の例では、pollIntervalInSeconds = 10 (1024) として計算を行います。
※また、System Clock Rate は、15 ms で計算を行います。初めに、”事前計算式” に値を代入します。

//事前計算式:
PhaseCorrection = CurrentTimeOffset / (16 * PhaseCorrectRate * pollIntervalInSeconds)
PhaseCorrection = CurrentTimeOffset / (16 * 1 * 1024)
PhaseCorrection = CurrentTimeOffset / 16384

MaximumCorrection = CurrentTimeOffset / (UpdateInterval / 100)      
MaximumCorrection = CurrentTimeOffset / (100 / 100)
MaximumCorrection = CurrentTimeOffset / 1

PhaseCorrection = min(PhaseCorrection, MaximumCorrection)

上記の結果から、元の PhaseCorrection の方が小さい値となるため、PhaseCorrection = CurrentTimeOffset / 16384 となります。
得られた結果を元に、”条件式” に値を代入します。

//条件式:
1. PhaseCorrection <= System Clock Rate / 2

CurrentTimeOffset / 16384 <= 150000 / 2
CurrentTimeOffset <= (150000 / 2) * 16384
CurrentTimeOffset <= 1228800000 clock tics

2. CurrentTimeOffset <= MaxAllowedPhaseOffset

CurrentTimeOffset <= 10000000 clock tics

上記の結果から、条件式1及び条件式2を満たす、10000000 clock tics (1 秒) 以内の時刻の差であれば、SLEW モードで時刻同期される結果となります。
※ 上記結果の通り、既定値の場合、MaxAllowedPhaseOffset = 1 により、条件式2 がより厳しい条件となるため、NTP サーバーとの時刻差が1秒以内の場合のみ、SLEW モードで時刻同期される動作となります。なお、条件式 1 については、122.88 秒となりますため、MaxAllowedPhaseOffset でのみ調整する場合には、おおよそ 122 までとなります。(つまり、MaxAllowedPhaseOffset のみで、SLEW モードによる時刻同期を制御する場合には、条件式1よりも低い値の範囲内でのみとなる点にご注意ください)

各 Windows Server OS バージョンごとの既定値における条件の一覧

最後に、参考情報として、各 Windows Server OS バージョン毎の既定における条件式を記載させていただきます。
なお、既定値については、ドメイン コントローラー / メンバー サーバー / ワークグループ にて差異がありますので、それぞれの設定値をベースに記載いたします。

※ Windows Server 2016 以降は pollIntervalInSeconds によって揺らぎが発生します。条件式1の初めの値は、”MinPollInterval” が採用された場合の値、() 内は、”MaxPollInterval” が採用された場合の値となります。
※ また、System Clock Rate を、15ms で計算を行った場合の例となりますので、実環境の動作と若干の誤差がございますので、ご留意ください。
※ 前述の通り、2021 年 10 月のセキュリティ以外の修正プログラム 適用以前の Windows Server 2019 におきましては、不具合により計算式が異なりますため、以下の表に当てはまらない点にご注意ください。

Windows Server 2012/Windows Server 2012 R2 Windows Server 2016 以降
ドメイン コントローラー 1. CurrentTimeOffset <= 5.25 sec
2. CurrentTimeOffset <= 300 sec
時刻差が 5.25 秒以下の場合は SLEW モードとなる
1. CurrentTimeOffset <= 53.76 (860.16) sec
2. CurrentTimeOffset <= 300 sec
時刻差が 約 53 秒 ~ 300 秒以下の場合は SLEW モードとなる
メンバー サーバー 1. CurrentTimeOffset <= 225 sec
2. CurrentTimeOffset <= 300 sec
時刻差が 225 秒以下の場合は SLEW モードとなる
1. CurrentTimeOffset <= 7.68 (122.88) sec
2. CurrentTimeOffset <= 300 sec
時刻差が 約 7 秒 ~ 122 秒以下の場合は SLEW モードとなる
ワークグループ 1. CurrentTimeOffset <= 2700 sec
2. CurrentTimeOffset <= 1 sec
時刻差が 1 秒以下の場合は SLEW モードとなる
1. CurrentTimeOffset <= 7.68 (122.88) sec
2. CurrentTimeOffset <= 1 sec
時刻差が 1 秒以下の場合は SLEW モードとなる

今回の記事が少しでも皆様のお役に立てば幸いでございます。
※ 本記事内容は、今後予告なく変更される場合があります。変更時には、更新履歴にて変更内容を記載いたします。

更新履歴

2021/3/1 : 本ブログの公開
2021/11/29 : Windows Server 2019 /Windows 10 1809 の不具合修正に合わせ記事を修正