Windows의 시각 동기화(w32time)와 업무 시스템 ── 「로그의 타임스탬프가 맞지 않는다」를 원리부터 해결하기

· · w32time, NTP, 시각 동기화, Windows, 로그, 장애 조사, 장치 연동, Active Directory

「장치가 이상 정지했다. 장치 쪽 로그와 PC 쪽 앱 로그를 대조해 보니 시각이 40초 어긋나 있어서, 장치의 오류와 앱의 통신 두절 중 어느 쪽이 먼저였는지 확정할 수 없었다」── 장치 연동 시스템의 장애 조사에서 저희가 몇 번이고 마주쳐 온 장면입니다. 네트워크 카메라, PLC, 검사 장치, 그리고 Windows PC. 각각이 자신의 시계로 로그를 새기고 있으며, 그 시계들이 맞아 있다는 보장은 사실 아무도 하지 않았다는 이야기입니다.

시각의 어긋남은 평상시에는 거의 아무도 눈치채지 못합니다. 곤란해지는 것은 언제나 장애 조사 때, 즉 「이벤트의 전후 관계」가 증거로서 필요해질 때입니다. 그리고 조사를 시작하면, 「워크그룹의 PC는 주 1회밖에 동기화하지 않았다」「가상 머신이 호스트와 NTP 양쪽에서 시각을 받아 흔들리고 있었다」「애초에 장치의 시계는 아무도 맞추지 않았다」와 같은 사실이 차례로 드러납니다.

이 글에서는 장치와 PC, 서버와 단말의 로그 대조에 어려움을 겪은 경험이 있는 개발자·정보시스템 담당자를 대상으로, Windows의 시각 동기화 서비스(w32time)의 원리, w32tm 명령어를 이용한 진단 실무, 정확도의 현실적인 기대치, 그리고 「시각은 어긋나고, 되돌아간다」는 전제 하의 업무 시스템 쪽 설계까지를, Microsoft의 1차 정보 근거와 함께 정리합니다.

1. 먼저 결론

  • Windows의 시각은 Windows Time 서비스(w32time)가 관리합니다. NTP의 엄밀한 구현은 아니지만, NTP 사양의 알고리즘들을 사용해 클록을 조정하는 NTP 클라이언트/서버이며, 통신은 UDP 123번 포트를 사용합니다.1
  • 도메인 환경에는 정해진 시각 계층이 있습니다. 멤버는 DC와, DC는 상위(부모) 도메인의 DC와 동기화하며, 정점은 포레스트 루트 도메인의 PDC 에뮬레이터입니다. 정점이 외부의 정확한 시각 소스와 동기화되어 있지 않으면, 도메인 전체가 함께 틀린 시각이 됩니다.1
  • 워크그룹(비도메인) 머신은 기본값으로 time.windows.com과 저빈도로 동기화합니다. 레지스트리 기본값인 SpecialPollInterval은 스탠드얼론 구성에서 604,800초(1주일)입니다. 수십 초의 오차는 「사양대로」 발생합니다.23
  • 진단은 w32tm 명령어 일습으로 충분합니다. w32tm /query /status로 동기화 상태와 동기화 소스를, /stripchart로 상대와의 시각 차이를 실측하고, /config /manualpeerlist로 동기화 대상을 지정하며, /resync로 즉시 재동기화합니다.2
  • w32time은 작은 오차는 클록이 흐르는 속도를 높이거나 낮춰 서서히 맞추고(슬루, slew), 큰 오차는 시계를 직접 다시 씀으로써 맞춥니다(스텝, step).시스템 시계는 앞으로도 뒤로도 튈 수 있습니다. 오차가 상한(MaxPos/MaxNegPhaseCorrection)을 넘으면 보정되지 않고 이벤트 로그에 기록만 된다는 동작도 중요합니다.12
  • 기본 설정의 정확도는 「Kerberos의 5분 제약을 충족하는」 정도가 설계 목표였습니다. Windows Server 2016 / Windows 10 1607 이후로는 크게 개선되어, 정확한 Stratum 1 시각 소스·네트워크 지연·홉 수 등의 조건을 충족하면 1초/50ms/1ms의 정확도가 지원 대상이 되었습니다.4
  • Hyper-V 게스트에는 호스트와 NTP라는 2가지 시각 제공자가 있습니다. Windows Server 2016 이후는 게스트가 최적의 쪽을 선택하도록 개선되었지만, 2012 R2 이전의 도메인 참가 게스트에서는 Hyper-V 시각 동기화 제공자의 비활성화가 권장됩니다.3
  • 앱 쪽은 「시각은 어긋나고, 되돌아갈 수도 있다」는 전제로 설계합니다. 로그의 시각은 UTC로 기록하고, 경과 시간 측정은 시스템 시계와 독립적으로 단조 증가하는 Stopwatch로 수행합니다. 이 구분 사용이 토대입니다.56

2. w32time의 원리 ── 도메인과 워크그룹에서 동작이 완전히 다르다

Windows Time 서비스(W32Time)는 Windows 표준 시각 동기화 컴포넌트입니다. NTP(및 도메인용의 보안 MS-SNTP)로 네트워크상의 시각 소스로부터 시각 샘플을 취득하고, NTP의 클록 필터/클록 선택 알고리즘으로 최선의 샘플을 선택해 로컬 시계를 조정합니다.1

짚고 넘어가야 할 점은, 구성에 따라 동기화 대상이 정해지는 방식이 근본적으로 다르다는 것입니다.

도메인 환경(Type=NT5DS)에서는 AD DS 포레스트에 미리 정해진 시각 계층이 있습니다. 멤버 PC/서버는 자신의 도메인의 DC와 동기화하고, DC는 부모 도메인의 DC와 동기화하며, 계층의 정점은 포레스트 루트 도메인의 PDC 에뮬레이터(또는 신뢰할 수 있는 시각 소스로 구성된 DC)입니다. NTP 패킷은 Kerberos 세션 키로 서명되며, 인증된 시각만 받아들여집니다.1 이 때문에 도메인 내의 PC끼리는 보통 어느 정도 맞춰집니다. 문제는 정점으로, PDC 에뮬레이터가 외부의 정확한 시각 소스(GPS 시계나 신뢰할 수 있는 NTP 서버)와 동기화되어 있지 않으면 「모두가 함께 틀린 시각」이 되어 버립니다. 로그를 사외 시스템이나 클라우드 쪽 기록과 대조한 순간, 이 오차가 드러납니다.

이 부분을 설정하는 것은 관리자외부의 정확한 시각 소스GPS 시계 / 신뢰할 수 있는 NTP 서버포레스트 루트 도메인의PDC 에뮬레이터자식 도메인의 DC같은 도메인의 다른 DC멤버 서버 / PC멤버 서버 / PC멤버 서버 / PC

그림 1: 도메인의 시각 계층 ── 화살표는 시각이 전달되는 방향

이 트리를 한 장의 그림으로 보면, 뿌리가 틀리면 모두가 똑같이 틀린다는 것이 명확해집니다. 게다가 모두가 함께 틀리기 때문에, 사내 로그끼리만 비교하는 한 아무도 눈치채지 못합니다. 외부와 대조한 날에야 비로소 발각됩니다. 정점의 설정을 가장 먼저 확인해야 하는 이유가 여기에 있습니다.

워크그룹 환경(Type=NTP)에서는 기본 동기화 대상이 time.windows.com,0x1입니다. 0x1(SpecialInterval)은 폴링 간격을 SpecialPollInterval 레지스트리 값으로 결정하는 플래그이며, 그 기본값은 스탠드얼론 구성에서 604,800초=1주일입니다.2 Windows 10 클라이언트에서도 하루 1회 정도이며, Windows Server 2012 R2 세대의 기본값은 주 1회였습니다.3 PC의 내장 시계(수정 발진기)는 온도 등의 환경에 따라 하루에 초 단위로 드리프트하는 일이 드물지 않으므로, 주 1회 동기화로는 수십 초의 오차가 흔히 발생합니다. 서두의 「40초 어긋남」의 정체는 대체로 이것입니다.

실무에서 중요한 것이 하나 더 있는데, 클록 규율(clock discipline)의 동작입니다. w32time은 오차가 작은 동안에는 클록이 흐르는 속도를 높이거나 낮춰 서서히 맞추고(슬루), 오차가 MaxAllowedPhaseOffset을 넘으면 시계를 직접 설정합니다(스텝).12 나아가 오차가 MaxPosPhaseCorrection/MaxNegPhaseCorrection(스탠드얼론 기본값 54,000초=15시간)을 넘으면, 보정하지 않고 이벤트만 기록하게 됩니다.2 「동기화되고 있을 텐데 고쳐지지 않는다」고 느껴질 때는, 이 상한에 걸려 있는 경우가 있습니다. 그리고 스텝 보정은 음의 방향으로도 걸리므로, 즉 Windows의 시스템 시계는 뒤로 튈 수도 있습니다 ── 이것이 후반의 앱 설계 이야기로 이어집니다.

3. w32tm 명령어 실무 ── 현재 상태 확인, 오차 실측, 동기화 대상 변경

시각 관련 조사에서 사용하는 명령어는 실질적으로 5가지입니다. 모두 관리자 권한의 명령 프롬프트에서 실행합니다.2

먼저 현재 상태 확인입니다.

w32tm /query /status

うるう秒インジケーター: 0(警告なし)
階層: 4 (二次参照 - (S)NTP で同期)
精度: -23 (ティックごとに 119.209ns)
ルート遅延: 0.0312500s
ルート分散: 7.7756348s
参照 ID: 0xC0A80A14 (ソース IP:  192.168.10.20)
最終正常同期時刻: 2026/07/22 8:14:02
ソース: dc01.example.local
ポーリング間隔: 10 (1024s)

확인해야 할 것은 3가지입니다. 「ソース」(소스)가 의도한 상대인지(Local CMOS Clock이나 Free-running System Clock이면 사실상 미동기화), 「最終正常同期時刻」(최종 정상 동기화 시각)이 최근인지(며칠 전이라면 동기화가 작동하지 않고 있다는 뜻), 「階層」(Stratum, 계층)이 타당한지(정확한 시각 소스로부터 몇 단계 떨어져 있는지. w32time은 Stratum 15 이하만 받아들입니다).7 동기화 소스만 알고 싶을 때는 w32tm /query /source, 여러 동기화 대상의 상태는 w32tm /query /peers, 설정값과 그 출처(정책인지 로컬인지)는 w32tm /query /configuration으로 확인합니다.

위 출력은 일본어 로케일 Windows의 것입니다. 영어 환경에서는 항목명이 바뀌므로, 대응 관계를 정리해 둡니다. 해외 거점 담당자와 주고받을 때나 영어로 검색할 때 활용하시기 바랍니다. 다만 표시 이름은 로케일에 따라 달라지므로, 이 출력을 기계적으로 파싱하는 스크립트는 작성하지 마시기 바랍니다.

일본어 로케일 표시 영어 로케일 표시
うるう秒インジケーター Leap Indicator
階層 Stratum
精度 Precision
ルート遅延 Root Delay
ルート分散 Root Dispersion
参照 ID ReferenceId
最終正常同期時刻 Last Successful Sync Time
ソース Source
ポーリング間隔 Poll Interval

다음으로, 상대와의 시각 차이 실측입니다. 장애 조사에서 「서버와 이 PC가 지금 얼마나 어긋나 있는가」를 수치로 파악하는 데 사용합니다.

w32tm /stripchart /computer:192.168.10.20 /samples:5 /dataonly

192.168.10.20 [192.168.10.20:123] の追跡中。
現在の時刻は 2026/07/24 9:41:03 です。
09:41:03, +28.1246875s
09:41:05, +28.1250120s
09:41:07, +28.1248533s
09:41:09, +28.1251008s
09:41:11, +28.1249517s

이 예라면 「이 PC는 상대보다 약 28초 늦어져 있다」고 바로 판단할 수 있습니다. /stripchart는 표시용 측정이며 로컬 시계는 변경하지 않으므로, 가동 중인 장치 PC에도 안심하고 사용할 수 있습니다. 로그 대조 전에 관련된 모든 머신에 대해 실행해 오차 일람표를 만들어 두는 것이, 저희가 장애 조사에서 가장 먼저 하는 일입니다.

동기화 대상을 명시하려면 /config를 사용합니다. 사내 NTP 서버(또는 DC)를 지정하는 정석은 다음과 같습니다.

w32tm /config /manualpeerlist:"ntp1.example.local,0x8 ntp2.example.local,0x8" /syncfromflags:manual /update
w32tm /resync

0x8은 클라이언트 모드로 동기화하는 플래그이며, 0x1(SpecialInterval)을 조합하면(=,0x9) SpecialPollInterval에 따른 간격으로 폴링합니다. 0x1만 단독으로 지정하면 클라이언트 모드 플래그가 빠지므로, 지정할 경우 ,0x8이나 ,0x9를 사용해야 합니다. 서버를 2대밖에 마련할 수 없는 경우에는, 한쪽에 0x2(UseAsFallbackOnly)를 붙여 우선순위를 명시하는 것이 권장됩니다(3대 이상 마련할 수 있다면 그쪽이 더 낫다는 것이 Microsoft의 안내입니다).2 수동 지정을 그만두고 도메인 계층으로 되돌리려면 w32tm /config /syncfromflags:domhier /update를 실행하고 서비스를 재시작합니다. w32tm /resync는 축적된 오차 통계를 폐기하고 즉시 재동기화시키는 명령어로, 설정 변경 후 반영 확인에 사용합니다.2

서버 이름 뒤에 붙이는 숫자가 NtpServer 플래그입니다. 흩어져 있으면 잘못 사용하기 쉬우므로 하나의 표로 정리합니다.2

플래그 이름 의미
0x1 SpecialInterval 폴링 간격을 SpecialPollInterval 레지스트리 값으로 결정
0x2 UseAsFallbackOnly 다른 시각 소스를 사용할 수 없을 때의 예비로 취급
0x8 Client 클라이언트 모드로 이 상대와 동기화
0x9 Client + SpecialInterval 0x80x1의 조합. 간격을 직접 정하고 싶을 때의 정석

0x1을 단독으로 지정하지 마십시오. 클라이언트 모드 플래그가 서지 않기 때문에, 간격만 지정하고 동기화는 하지 않는 구성이 되어 버립니다. 간격을 지정하고 싶다면 0x9를 사용합니다.

워크그룹 PC의 폴링 간격을 단축하기

7장의 판단표에서 언급하는 「SpecialPollInterval 단축」은, 레지스트리 값 변경과 서비스 재시작으로 수행합니다. 기본값인 604,800초(1주일)를 3,600초(1시간)로 바꾸는 경우의 절차는 다음과 같습니다.2

rem (1) 폴링 간격을 3,600초로 설정한다(REG_DWORD의 수치는 10진수로 지정)
reg add "HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient" /v SpecialPollInterval /t REG_DWORD /d 3600 /f

rem (2) SpecialPollInterval이 적용되는 것은 0x9 를 포함한 플래그가 붙은 시각 소스뿐이다. 0x9로 지정한다
w32tm /config /manualpeerlist:"ntp1.example.local,0x9 ntp2.example.local,0x9" /syncfromflags:manual /update

rem (3) 서비스를 재시작해 반영하고, 그 자리에서 동기화시킨다
net stop w32time && net start w32time
w32tm /resync

rem (4) 반영 결과와 각 설정값의 출처(정책인지 로컬인지)를 확인한다
w32tm /query /configuration
w32tm /query /status

(2)를 생략하면, 레지스트리만 바꿔도 간격은 변하지 않습니다. SpecialPollInterval0x1 플래그가 붙은 시각 소스에 대해서만 사용되기 때문입니다. 또한 그룹 정책으로 시각 설정을 배포하고 있는 환경에서는, 로컬 레지스트리 변경이 다음 정책 적용 시 덮어씌워집니다. w32tm /query /configuration의 출력으로 각 값의 출처를 확인하고, 정책 관리 하에 있다면 「컴퓨터 구성」>「관리 템플릿」>「시스템」>「Windows Time Service」>「Time Providers」>「Windows NTP 클라이언트 구성」에서 설정하시기 바랍니다.

또한 /manualpeerlist로 지정하는 외부 NTP는 도메인의 인증된 시각과는 별개이며 인증되지 않으므로, 원칙적으로 도메인 멤버에는 사용하지 않고 정점(PDC 에뮬레이터)이나 비도메인 머신에 대해 사용하는 것입니다.1

4. 정확도에 관한 이야기 ── 기본값으로 어디까지 맞는가, 1ms의 조건

「Windows의 NTP 동기화는 결국 어느 정도로 맞나요?」라는 질문에는 시대에 따라 답이 갈립니다.

Windows Server 2012 R2 / Windows 8.1 이전의 w32time은 Kerberos 인증의 요구사항(기본값 5분)을 충족하는 정확도와, 동일 포레스트 내에서의 「대체로 정확한 시각」을 제공하는 것이 설계 목표였으며, 그보다 엄격한 정확도 요구사항은 설계 사양의 범위 밖·지원 대상 외라고 명시되어 있습니다.4 즉 「초 단위로 맞으면 설계대로」인 세계입니다.

Windows Server 2016 / Windows 10 1607 이후는 알고리즘이 개선되고, 클록 갱신 빈도도 기본값으로 대폭 인상되었습니다(예: 서버는 클록 조정이 1시간에 1회에서 매초로).3 그 결과, 조건을 충족하면 1초·50ms·1ms의 정확도가 지원 경계로 정의되어 있습니다. 1ms의 주요 조건은 다음과 같으며, 반대로 말하면 이것이 갖춰지지 않은 환경에서 1ms를 기대해서는 안 됩니다.4

  • 정확하고 안정적인 Stratum 1 시각 소스(GPS 시계 등)를 정점으로 하는 NTP 계층으로, 경로상의 Windows가 모두 고정밀 구성일 것
  • 시각 소스와의 네트워크 지연이 0.1ms 미만이며, 시각 소스로부터 Stratum 5 이내·4홉 이내일 것
  • 각 계층의 CPU 사용률(1일 평균)이 80% 이하일 것(가상화 환경에서는 호스트도 포함)

또한 time.windows.com과 같은 인터넷상의 원격 시각 소스에서는, 경로의 비대칭성이나 혼잡의 영향을 받기 때문에 1ms 정확도는 기대할 수 없다고 명시되어 있습니다.7 실무의 감각으로는, 「기본값 워크그룹=초~수십 초 어긋날 수 있음」「제대로 구성한 사내 NTP 동기화=수십 ms~1초 이내」「전용 시각 소스와 설계를 갖춘 경우=ms급」의 3단계로 생각하는 것이 안전합니다. 장치 연동에서 ms 단위의 전후 관계가 필요하다면, 시각 동기화에 의존하지 말고 후술하는 대로 한쪽 클록으로 측정하는 설계로 가야 합니다.

5. 가상 머신의 시각 ── Hyper-V 시각 동기화 통합 서비스와 NTP의 이중 관계

가상 머신의 시각은 물리 머신보다 꼬이기 쉬운 영역입니다. 이유는 단순한데, 시각을 주는 상대가 2계통 있기 때문입니다. Hyper-V 게스트의 Windows에는, 호스트로부터 시각을 받는 Hyper-V 시각 동기화 통합 서비스(VMICTimeSync 제공자)와, 일반적인 NTP 클라이언트가 모두 존재하며, Windows는 계층(Stratum), 루트 지연, 루트 분산, 오프셋의 순서로 「더 나은 쪽」을 선택합니다.7

Windows Server 2016에서 이 구조는 크게 개선되었습니다. VM 시작·복원 시의 초기 시각이 정확해지고, 인터럽트 지연을 보정한 샘플이 w32time에 전달되게 되어, 호스트 대비 10µs 정도의 정확도를 유지할 수 있습니다. 호스트가 게스트에 보고하는 Stratum도 「호스트의 Stratum+1」이라는 실태에 맞는 값이 되었고, 도메인에 참가한 2016 이후의 게스트는 호스트에 맡기지 않고 가장 정확한 클록을 선택하게 되었습니다.3

한편, Windows Server 2012 R2 이전의 게스트를 도메인에서 동작시키는 경우에는, Hyper-V 시각 동기화 제공자가 도메인의 시각 동기화를 어지럽힐 수 있기 때문에, Microsoft는 제공자를 비활성화하도록 안내하고 있습니다.3

reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\VMICTimeProvider /v Enabled /t REG_DWORD /d 0 /f
net stop w32time && net start w32time

Azure VM에 대해서도 정리되어 있으며, 요점은 「도메인 참가 VM(특히 가상화 DC)은 TimeSync를 비활성화하고 도메인 계층으로 일원화하며, 비도메인 단독 VM은 기본값 그대로 호스트 동기화를 사용」입니다.3 서드파티 하이퍼바이저(VMware 등)에서도 사고방식은 동일하며, 도메인 참가 게스트에서는 호스트 쪽의 시각 동기화 기능을 끄는 것이 권장됩니다.3 「NTP와 호스트 동기화가 번갈아 시계를 잡아당겨서 로그 시각이 왔다 갔다 한다」는 증상은 이 이중 관계를 의심해 보시기 바랍니다. VM의 저장된 상태로부터의 복원이나 라이브 마이그레이션 직후에는 시각이 크게 어긋난 상태에서 보정이 시작되므로, 복원 직후의 로그 시각은 특히 신뢰하지 않는다는 운영상의 주의도 덧붙여 둡니다.

6. 업무 시스템 쪽의 설계 ── 시각은 「어긋난다·되돌아간다」는 전제로 만든다

여기까지가 인프라 쪽 이야기지만, 시각 동기화를 아무리 정비해도 오차는 제로가 되지 않습니다. 장치 연동 소프트웨어를 만드는 쪽은 시각은 어긋나고, 되돌아가기도 한다는 전제로 로그와 시간 측정을 설계합니다.

첫 번째 원칙은, 로그의 타임스탬프는 UTC로 기록한다는 것입니다. 로컬 시각으로 기록하면 시간대나 서머타임, 기기별 설정 차이가 대조를 방해합니다(이 이야기는 「업무 앱의 날짜/시간과 시간대」에서 자세히 다루고 있습니다). 두 번째 원칙은, 「언제 일어났는가」와 「얼마나 걸렸는가」로 클록을 구분해서 사용한다는 것입니다.

// 【함정】 시스템 시계로 경과 시간을 측정한다
// w32time의 스텝 보정이 들어가면, 이 차이는 실제보다 길어지거나 짧아지거나, 음수가 될 수도 있다
var start = DateTime.UtcNow;
ExecuteInspection();
var elapsed = DateTime.UtcNow - start;   // 타임아웃 판정에 사용하면 오작동한다

// 【정석】 경과 시간은 Stopwatch(단조 증가 클록)로 측정한다
long t0 = Stopwatch.GetTimestamp();
ExecuteInspection();
TimeSpan elapsed2 = Stopwatch.GetElapsedTime(t0);   // .NET 7 이후. 그 이전은 Stopwatch.StartNew()

Stopwatch는 고분해능 성능 카운터(QueryPerformanceCounter에 상당)로 틱을 세는, 경과 시간 측정 전용 클래스이며, 시스템 시계의 보정 영향을 받지 않습니다.5 반면 DateTime.UtcNow는 시스템 시계 그 자체이며, 분해능도 시스템 타이머에 의존합니다(대략 0.5~15ms).6 타임아웃 판정, 재시도 간격, 성능 계측, 장치의 응답 시간 측정 ── 「길이」를 다루는 처리는 모두 Stopwatch 쪽으로 몰아 줍니다.

로그에는 양쪽을 함께 기록합니다. 벽시계(UTC)와 단조 클록을 한 쌍으로 남겨 두면, 나중에 NTP의 스텝 보정을 넘나드는 구간에서도 순서와 간격을 복원할 수 있습니다.

public sealed class OpLog
{
    private static readonly long _baseTimestamp = Stopwatch.GetTimestamp();
    private static long _seq;

    public static void Write(string message)
    {
        long seq = Interlocked.Increment(ref _seq);
        // UTC 시각(언제 일어났는가) + 시작 이후의 단조 경과 ms(순서와 간격) + 일련번호(같은 시각 내의 순서)
        var line = $"{DateTime.UtcNow:yyyy-MM-dd'T'HH:mm:ss.fff'Z'}\t" +
                   $"{Stopwatch.GetElapsedTime(_baseTimestamp).TotalMilliseconds:F1}\t" +
                   $"{seq}\t{message}";
        // ... 파일/ETW로 출력
    }
}

여러 머신·장치의 로그를 대조하려면, 여기에 2가지를 더합니다. 하나는 상대 시계와의 오프셋을 정기적으로 기록하는 것입니다. 카메라나 PLC처럼 독자적인 시계를 가진 장치는 통신 프로토콜을 통해 장치 시각을 읽을 수 있는 경우가 많으므로, 앱 시작 시와 정기적으로(예: 1시간마다) 「PC의 UTC 시각과 장치 시각의 차이」를 로그로 남깁니다. 이는 w32tm /stripchart의 장치판에 해당하며, 장애 후 「이 기간에는 장치 로그의 시각에 +12.3초의 보정을 걸어서 읽는다」는 대조를 기계적으로 할 수 있게 됩니다. 다른 하나는 이벤트 로그·ETW 쪽의 기록과 자체 로그의 시각 체계를 맞춰 두는 것입니다(「Windows 이벤트 로그·ETW 입문」 참조). 크래시 시의 증적 설계(「크래시 시에 로그와 덤프를 남기는 설계」)나, 카메라 통신 두절과 같은 네트워크 기인 장애 조사(「TCP 재전송으로 산업용 카메라 통신이 멈추는 경우」)에서는, 시각 체계가 맞춰져 있는지에 따라 조사 시간이 자릿수 단위로 달라집니다.

오프라인 공장 LAN(인터넷 비연결)에서는 time.windows.com에 닿지 않으므로, LAN 내에 로컬 NTP 서버를 세워 모든 기기를 그곳에 맞추는 것이 정석입니다. GPS 시계가 있으면 이상적이지만, 없더라도 「절대 시각은 다소 틀리더라도, 모든 기기가 같은 기준에 맞춰져 있다」는 상태로 만들 수 있으면, 로그 대조의 목적은 거의 달성됩니다. 기준 서버에는, 외부와 동기화할 수 없는 동안의 자체 신고 정확도를 정하는 LocalClockDispersion의 조정도 검토합니다.2

7. 환경별 판단표

환경 기본 동기화 대상·빈도 흔히 발생하는 증상 권장 조치
도메인 참가 PC/서버 DC(NT5DS)→정점은 PDC 에뮬레이터1 도메인 전체가 함께 외부와 어긋남 PDC 에뮬레이터에 /manualpeerlist로 외부의 정확한 시각 소스를 설정. 멤버는 기본값 그대로
워크그룹 PC time.windows.com, 기본값은 주 1회 정도로 저빈도2 수십 초의 어긋남이 상시화 사내 NTP를 /manualpeerlist(,0x9=Client+SpecialInterval)로 지정하고, SpecialPollInterval을 단축(예: 3,600초). 명령어 절차는 3장 「워크그룹 PC의 폴링 간격을 단축하기」
Hyper-V/Azure VM(도메인 참가) 호스트(VMIC)와 NTP의 2계통7 이중 보정으로 시각이 흔들림, 복원 직후에 큰 어긋남 2016 이후끼리라면 기본값으로 공존 가능. 2012 R2 이전 게스트는 VMICTimeProvider를 비활성화3
Hyper-V/Azure VM(단독) 위와 동일 거의 문제없음 기본값 그대로 호스트 동기화를 사용3
오프라인 공장 LAN 동기화 대상 없음(각 기기의 내장 시계에 의존) 모든 기기가 제각각 드리프트 로컬 NTP 서버를 기준으로 모든 기기(PC·장치)를 맞춘다. 장치 시계와의 오프셋을 정기적으로 기록
ms급 전후 관계가 필요 ── 시각 동기화 정확도로는 부족 Windows Server 2016 이후+고정밀 구성의 조건 확인4. 가능하면 한쪽 머신의 Stopwatch로 측정하는 설계로

8. 정리

  • Windows의 시각은 w32time이 관리하며, 도메인에서는 PDC 에뮬레이터를 정점으로 하는 계층 동기화, 워크그룹에서는 기본값으로 time.windows.com과의 저빈도 동기화입니다. 수십 초의 어긋남은 고장이 아니라 기본값이 초래하는 결과입니다.
  • 조사는 w32tm /query /status로 동기화 소스와 최종 동기화 시각을 확인하고, w32tm /stripchart로 상대와의 차이를 실측하는 데서 시작합니다. 동기화 대상의 명시는 /config /manualpeerlist, 즉시 반영은 /resync입니다.
  • w32time은 작은 오차를 슬루로, 큰 오차를 스텝으로 보정합니다. 시스템 시계는 뒤로도 튈 수 있다는 것, 상한을 초과하면 보정되지 않는다는 것을 기억해 두어야 합니다.
  • 기본 설정의 정확도 목표는 역사적으로 「Kerberos의 5분」을 충족하는 정도였습니다. 1ms급은 Windows Server 2016 이후, 정확한 시각 소스·지연·홉 수·CPU 부하의 조건을 충족한 경우의 지원 범위입니다.
  • 가상 머신은 호스트 동기화와 NTP의 2계통을 가집니다. 도메인 참가 VM은 도메인 동기화로 일원화(구형 OS 게스트는 VMICTimeProvider 비활성화), 단독 VM은 호스트 동기화 그대로가 원칙입니다.
  • 앱 쪽은 타임스탬프는 UTC, 경과 시간은 Stopwatch로 구분해서 사용하고, 장치의 독자적인 시계와의 오프셋을 정기적으로 기록해 둡니다. 이 3가지로 「어느 쪽이 먼저인지 모른다」는 장애 조사에서 벗어날 수 있습니다.

관련 글

관련 상담 영역

합동회사 코무라소프트에서는 「장치와 PC의 로그 시각이 맞지 않아 장애의 전후 관계를 특정할 수 없다」와 같은 조사 상담, 공장 LAN·장치 연동 환경에서의 시각 동기화 설계, 타임아웃이나 시간 측정 관련 결함을 포함한 장치 연동 소프트웨어의 개발·개선을 다루고 있습니다.

참고 링크

  1. Microsoft Learn, How the Windows Time Service Works. w32time이 NTP 사양의 알고리즘들을 사용하는 Windows 표준 시각 동기화 서비스라는 점, AD DS 포레스트의 시각 계층(멤버→DC→부모 도메인 DC→포레스트 루트의 PDC 에뮬레이터), 비도메인 머신이 기본값으로 time.windows.com과 동기화한다는 점, Kerberos 세션 키에 의한 시각 인증, 수동으로 지정한 시각 소스가 인증되지 않는다는 점, 슬루/스텝에 의한 클록 규율, UDP 123번 포트 사용에 대해.  2 3 4 5 6 7 8

  2. Microsoft Learn, Windows Time service tools and settings. w32tm 명령어의 각 옵션(/query /status·/source·/peers·/configuration, /stripchart, /resync, /config /manualpeerlist /syncfromflags), NtpServer 플래그(0x1 SpecialInterval·0x2 UseAsFallbackOnly·0x8 Client)와 2대 구성 시 0x2 권장, 스탠드얼론 기본값이 time.windows.com,0x1이며 SpecialPollInterval 기본값이 604,800초라는 점, MaxAllowedPhaseOffset에 의한 슬루/스텝 전환, MaxPos/MaxNegPhaseCorrection(스탠드얼론 기본값 54,000초) 초과 시에는 이벤트 기록만 이루어진다는 점, LocalClockDispersion에 대해.  2 3 4 5 6 7 8 9 10 11 12 13

  3. Microsoft Learn, Time accuracy improvements for Windows Server 2016. Hyper-V TimeSync 서비스의 개선(VM 시작/복원 시의 초기 시각, 인터럽트 지연 보정, 호스트+1의 Stratum 보고, 도메인 참가 2016 게스트가 최적 클록을 선택한다는 점), 2012 R2 이전의 도메인 참가 게스트에서의 Hyper-V 시각 제공자 비활성화 권장과 VMICTimeProvider 레지스트리 설정, Azure VM(도메인 참가는 TimeSync 비활성화·단독 VM은 호스트 동기화 유지)에 대한 지침, 기본 폴링/클록 갱신 빈도의 버전별 비교(2012 R2 세대의 스탠드얼론은 주 1회, 2016은 매초 클록 갱신)에 대해.  2 3 4 5 6 7 8 9 10

  4. Microsoft Learn, Support boundary for high accuracy time. Windows 10 1607 / Windows Server 2016보다 이전의 w32time은 Kerberos v5의 요구사항을 충족하는 정확도가 설계 목표였고 고정밀도는 지원 대상 외였다는 점, 2016 이후는 조건을 충족하면 1초/50ms/1ms 정확도가 지원된다는 점, 그리고 1ms 정확도의 조건(Stratum 1 시각 소스, 네트워크 지연 0.1ms 미만, Stratum 5 이내·4홉 이내, CPU 사용률 80% 이하 등)에 대해.  2 3 4

  5. Microsoft Learn, Stopwatch Class (System.Diagnostics). Stopwatch가 경과 시간을 정확하게 측정하기 위한 클래스이며, 하드웨어와 OS가 지원하면 고분해능 성능 카운터로 틱을 센다는 점, Frequency/GetTimestamp가 QueryPerformanceFrequency/QueryPerformanceCounter 대신 사용될 수 있다는 점, GetTimestamp와 GetElapsedTime을 이용한 측정에 대해.  2

  6. Microsoft Learn, DateTime.UtcNow Property. DateTime.UtcNow가 컴퓨터의 현재 일시(UTC), 즉 시스템 시계를 반환한다는 점, 그 분해능이 시스템 타이머에 의존하며 대략 0.5~15ms라는 점에 대해.  2

  7. Microsoft Learn, Accurate Time for Windows Server 2016. Hyper-V 게스트가 호스트의 VMIC 제공자와 NTP라는 여러 제공자로부터 Stratum 등을 기준으로 최선의 시각 소스를 선택한다는 점, 스탠드얼론 머신의 기본값이 time.windows.com이라는 점, 원격 시각 소스에서는 1ms 정확도에 의존할 수 없다는 점, w32time이 Stratum 15 이하만 받아들인다는 점, 정확한 시각의 3가지 요건(안정적인 시각 소스·안정적인 클라이언트 클록·대칭적인 NTP 통신)에 대해.  2 3 4

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

PC 로그와 장치 로그의 시각이 어긋나 있습니다. 먼저 무엇을 확인해야 하나요?
먼저 PC 쪽에서 w32tm /query /status를 실행해 「소스」(어디와 동기화하고 있는가)와 「최종 정상 동기화 시각」을 확인합니다. 소스가 Local CMOS Clock으로 되어 있거나 마지막 동기화가 며칠 전이라면, 그 PC는 사실상 아무 곳과도 동기화되지 않은 상태입니다. 다음으로 w32tm /stripchart /computer:상대 /dataonly로 상대(서버나 장치의 NTP 포트)와의 시각 차이를 실측해, 어느 쪽이 얼마나 어긋나 있는지를 수치로 파악합니다. 장치 쪽이 독자적인 시계를 가지고 있다면, 장치의 시각 설정 화면이나 통신을 통해 시각을 읽어와 PC 시각과의 차이를 기록해 두면, 과거 로그를 대조할 때도 활용할 수 있습니다.
워크그룹 환경의 Windows는 어느 정도의 빈도로 시각 동기화를 하나요?
도메인에 참가하지 않은 Windows는 기본값으로 time.windows.com과 동기화하지만, 빈도는 상당히 낮게 설정되어 있습니다. 레지스트리 기본값인 SpecialPollInterval은 스탠드얼론 구성에서 604,800초(1주일)이며, Windows 10 클라이언트에서도 하루 1회 정도입니다. PC의 내장 시계는 하루 단위로 초~수십 초 어긋나는 일이 드물지 않기 때문에, 이 빈도로는 업무 로그의 대조를 견딜 수 있는 정확도를 기대할 수 없습니다. 로그의 시각 정확도가 필요한 현장에서는 w32tm /config /manualpeerlist로 사내 NTP 서버를 지정하고 SpecialPollInterval을 단축하는 것이 정석입니다.
Hyper-V상의 가상 머신 시각은 호스트와 NTP 중 어느 쪽에 맞춰야 하나요?
Hyper-V 게스트에는 Hyper-V 시각 동기화 통합 서비스(VMICTimeSync)와 NTP 클라이언트라는 2가지 시각 제공자가 있으며, Windows가 계층(Stratum) 등을 기준으로 더 나은 쪽을 선택합니다. 도메인 참가 게스트의 원칙은 도메인 계층(DC)과의 동기화이며, Windows Server 2016 이후의 호스트/게스트 조합이라면 두 가지가 공존할 수 있도록 개선되어 있습니다. Windows Server 2012 R2 이전의 게스트를 도메인에서 사용하는 경우에는, VMICTimeProvider를 비활성화해 도메인 동기화로 일원화하도록 Microsoft가 안내하고 있습니다. 워크그룹의 단독 VM이라면 기본값 그대로 호스트 동기화를 사용하는 것이 간단하고 확실합니다.
도메인 환경에서 시각이 크게 어긋나면 어떤 일이 일어나나요?
Active Directory의 인증에 사용되는 Kerberos는 기본값으로 클라이언트와 서버 사이에 5분 이내의 시각 일치를 요구합니다. 이를 넘어서 어긋나면 인증이 실패해, 공유 폴더 접근이나 그룹 정책 적용 등 도메인의 기본 기능이 동작하지 않게 됩니다. 도메인 참가 PC는 기본값으로 DC, 최종적으로는 포레스트 루트의 PDC 에뮬레이터를 정점으로 하는 계층에서 동기화하기 때문에, 보통은 여기까지 어긋나는 일은 없습니다. 반대로 말하면, PDC 에뮬레이터 자체가 외부의 정확한 시각 소스와 동기화되어 있지 않으면 도메인 전체가 「함께 틀린 시각」이 되므로, 정점의 설정 확인이 중요합니다.
경과 시간 측정에 DateTime.UtcNow를 사용하면 안 되는 이유는 무엇인가요?
DateTime.UtcNow는 시스템 시계를 읽기 때문에, w32time의 보정 영향을 그대로 받기 때문입니다. 시각 차이가 크면 w32time은 서서히 보정(슬루)하지 않고 시계를 직접 설정(스텝)하며, 이때 시각은 앞으로도 뒤로도 튈 수 있습니다. 즉 UtcNow의 뺄셈으로 측정한 경과 시간은 실제보다 길어지거나, 짧아지거나, 음수가 되는 일까지 모두 일어날 수 있습니다. 경과 시간이나 타임아웃 측정에는 시스템 시계와 독립적으로 단조 증가하는 Stopwatch(또는 Stopwatch.GetTimestamp)를 사용하고, UtcNow는 「언제 일어났는가」를 기록하는 용도로만 한정하는 것이 안전합니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기