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

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

수정 이력(5건, 최종 수정 2026년 09월 03일)

이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.

Codex 리뷰에 따라 상담·문의 링크에 /ko/ 로케일 접두를 붙였습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
permalink·저자 표기·지식 맵 래퍼·깨진 내부 링크 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
기사 서두에 「이 기사의 지식 맵」 절을 추가했습니다. 본문에서 다루는 개념과 그 관계를 요약·그림·상세 페이지 링크로 정리한 것입니다. 본문의 주장은 바꾸지 않았습니다.
외부 리뷰(1283건)에 대응해 본문을 업데이트했습니다. 개별 변경 내용은 아래 이력을 참조하세요.
워크그룹 PC의 폴링 간격을 줄이는 절을 새로 만들었습니다(레지스트리 설정만으로는 효과가 없고, `0x9`로 `/manualpeerlist`를 지정해야 하는 이유를 포함합니다). 도메인 시각 계층 그림, NtpServer 플래그 표(`0x1` 단독이 잘못된 이유), `w32tm /query /status` 항목명의 일본어와 영어 대응표를 추가했습니다.
최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22174905)

아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.

Go Komura (2026). 「Windows의 시각 동기화(w32time)와 업무 시스템 ── 「로그 타임스탬프가 맞지 않는다」를 원리부터 해결하기」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/windows-time-sync-w32time-guide/

DOI(등록된 아카이브)
10.5281/zenodo.22174905
DOI(마지막 등록 버전)
10.5281/zenodo.22174906

「장치가 이상 정지했다. 장치 쪽 로그와 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
  • 워크그룹(비도메인) PC는 기본값으로 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라는 두 시각 공급자가 있습니다. Windows Server 2016 이후에는 게스트가 더 나은 쪽을 고르도록 개선되었지만, 2012 R2 이전의 도메인 가입 게스트에서는 Hyper-V 시각 동기화 공급자를 끄는 것이 권장입니다.3
  • 앱 쪽은 「시각은 어긋나고 되돌아간다」는 전제로 설계합니다. 로그 시각은 UTC로 기록하고, 경과 시간 측정은 시스템 시계와 독립적으로 단조 증가하는 Stopwatch로 합니다. 이 역할 나눔이 토대입니다.56

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 23건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

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 클라이언트에서도 하루 한 번 정도이고, Windows Server 2012 R2 세대의 기본값은 주 1회였습니다.3 PC 내장 시계(수정 발진기)는 온도 등 환경에 따라 하루에 초 단위로 드리프트하는 일이 드물지 않으므로, 주 1회 동기화에서는 수십 초 오차가 흔히 일어납니다. 서두의 「40초 오차」의 정체는 대개 이것입니다.

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

3. w32tm 명령 실무 ── 현황 확인, 차이 실측, 동기화 대상 변경

시각 관련 조사에 쓰는 명령은 사실상 다섯 가지입니다. 모두 관리자 권한 명령 프롬프트에서 실행합니다.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)

볼 것은 세 가지입니다. 「소스」가 의도한 상대인지(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입니다. 서버를 두 대밖에 준비하지 못할 때는 한쪽에 0x2(UseAsFallbackOnly)를 붙여 우선순위를 명시하는 것이 권장됩니다(세 대 이상 준비할 수 있다면 그쪽이 낫다는 것이 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이 적용되는 것은 0x1을 포함한 플래그를 붙인 시각원뿐이다. 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 에뮬레이터)이나 비도메인 PC에 대해 쓰는 것입니다.1

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

「Windows NTP 동기화는 결국 얼마나 맞나요」라는 질문에는 시대에 따라 답이 갈립니다.

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

Windows Server 2016 / Windows 10 1607 이후에는 알고리즘이 개선되고 클록 갱신 빈도도 기본값에서 크게 올라갔습니다(예: 서버의 클록 조정이 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급」의 세 단계로 생각하는 것이 안전합니다. 장치 연동에서 ms 단위 전후 관계가 필요하면 시각 동기화에 기대지 말고, 뒤에서 말하듯 한쪽 클록으로 재는 설계로 옮겨야 합니다.

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

가상 머신 시각은 물리 머신보다 꼬이기 쉬운 영역입니다. 이유는 단순합니다. 시각을 주는 상대가 두 경로이기 때문입니다. 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. 업무 시스템 쪽 설계 ── 시각은 「어긋나고 되돌아간다」는 전제로 만든다

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

첫 번째 원칙은 로그 타임스탬프는 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로 출력
    }
}

여러 머신·장치의 로그 대조를 위해서는 두 가지를 더 넣습니다. 하나는 상대 시계와의 오프셋을 정기 기록하는 것입니다. 카메라나 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 두 경로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 두 경로를 갖습니다. 도메인 가입 VM은 도메인 동기화로 일원화(구 OS 게스트는 VMICTimeProvider 비활성화), 단독 VM은 호스트 동기화 그대로가 원칙입니다.
  • 앱 쪽은 타임스탬프는 UTC, 경과 시간은 Stopwatch로 나눠 쓰고, 장치의 독자 시계와의 오프셋을 정기 기록해 둡니다. 이 세 가지로 「어느 쪽이 먼저인지 모른다」는 장애 조사에서 벗어날 수 있습니다.

관련 기사

관련 상담 영역

합동회사 小村ソフト에서는 「장치와 PC에서 로그 시각이 맞지 않아 장애의 전후 관계를 특정하지 못한다」는 조사 상담, 공장 LAN·장치 연동 환경의 시각 동기화 설계, 타임아웃이나 시간 측정 관련 문제를 포함한 장치 연동 소프트웨어의 개발·개선을 다룹니다.

참고 링크

  1. Microsoft Learn, How the Windows Time Service Works. w32time이 NTP 사양의 알고리즘 군을 쓰는 Windows 표준 시각 동기화 서비스라는 점, AD DS 포리스트의 시각 계층(멤버→DC→부모 도메인 DC→포리스트 루트의 PDC 에뮬레이터), 비도메인 PC가 기본값으로 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 등을 기준으로 가장 좋은 시각원을 고른다는 점, 스탠드얼론 PC의 기본이 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 클라이언트에서도 하루 한 번 정도입니다. PC 내장 시계는 하루 단위로 초~수십 초 어긋나는 일이 드물지 않으므로, 이 빈도로는 업무 로그 대조에 견딜 정확도를 기대할 수 없습니다. 로그의 시각 정확도가 필요한 현장에서는 w32tm /config /manualpeerlist로 사내 NTP 서버를 지정하고 SpecialPollInterval을 줄이는 것이 정석입니다.
Hyper-V 위 가상 머신의 시각은 호스트와 NTP 중 어디에 맞춰야 하나요?
Hyper-V 게스트에는 Hyper-V 시각 동기화 통합 서비스(VMICTimeSync)와 NTP 클라이언트라는 두 시각 공급자가 있고, 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 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기