개발노트

고즐의 개발 및 서버 개발 노트

DB 서버 시간 동기화 문제 분석: 웹서버는 정상인데 DB만 틀어졌던 이유

# db서버시간 # ntp동기화 # chronyd # udp123 # outbound방화벽

Server 2026.01.16 1시간 전 2 회 읽음 1



처음 문제는 입력 오류처럼 보였던 메시지에서 시작됩니다

거래처에서 뉴스를 등록하는 과정에서 “미래의 시간은 등록할 수 없다”는 메시지가 표시되었습니다. 처음에는 단순한 입력값 문제처럼 보였고, 실제로 웹 화면에서 보이는 현재 시간과 비교해도 특별히 미래 시각을 입력한 것처럼 보이지는 않았습니다. 이 시점에서는 서버 시간 자체를 의심하기보다, 입력 로직이나 검증 조건을 먼저 떠올리게 되는 흐름이 자연스러워 보입니다.

하지만 같은 작업을 여러 차례 반복해도 동일한 메시지가 발생했고, 그 과정에서 웹서버의 시간은 정상적으로 표시되고 있다는 점이 오히려 혼란을 키웠습니다. ‘웹서버 시간이 맞다면 문제는 어디에 있을까’라는 질문이 뒤늦게 떠오른 지점이기도 합니다.


웹서버 시간이 맞아도 서비스 기준 시간이 맞는 것은 아닙니다

웹과 DB를 분리한 구조에서는, 눈에 보이는 웹서버 시간이 곧 서비스 기준 시간이 되는 것처럼 느껴지기 쉽습니다. 그러나 실제 데이터의 유효성 판단이나 예약 여부, 현재 시각과의 비교는 DB 서버 기준으로 수행되는 경우가 많습니다. 특히 SQL 레벨에서 NOW()나 CURRENT_TIMESTAMP를 기준으로 검증하는 로직이 있다면, DB 서버의 시간이 실질적인 기준이 됩니다.

이 지점에서 웹서버와 DB 서버의 시간을 각각 확인해보기로 했습니다.


웹서버 시간 확인

date timedatectl 

웹서버에서는 현재 시간이 정상적으로 표시되고 있었고, 시스템 시계 역시 동기화된 상태로 보였습니다. 이 결과만 보면 “시간 문제는 아닌 것 같다”는 결론에 도달하기 쉽습니다.


DB 서버 시간 확인

date timedatectl 

DB 서버에서는 웹서버와 몇 초에서 수십 초 정도 차이가 나는 상태가 확인되었습니다. 이 자체로는 큰 문제처럼 느껴지지 않을 수도 있지만, ‘미래 시간 등록 불가’와 같은 조건이 걸려 있는 경우에는 충분히 오류를 유발할 수 있는 차이로 해석됩니다.


DB 서버 내부에서 보는 시간은 또 한 번 확인이 필요합니다

DB 서버의 시스템 시간이 실제로 DB 엔진에서도 동일하게 사용되고 있는지 확인하는 과정이 이어졌습니다. 이때는 MySQL/MariaDB 내부에서 직접 현재 시간을 조회해보는 방식이 필요해 보입니다.

mysql -e "SELECT NOW(), @@global.time_zone;" 

여기서 출력된 NOW() 값이 웹서버 기준 시간보다 과거로 표시되고 있다면, 애플리케이션 레벨에서 “미래 시간”으로 판단되는 이유가 어느 정도 설명됩니다. 웹서버 기준으로는 현재 시각이지만, DB 기준으로는 아직 도달하지 않은 시각이기 때문입니다.


이제 시간 동기화 자체가 이루어지고 있는지를 확인하게 됩니다

시간 차이가 확인된 이후에는, 단순히 수동으로 시간을 맞추는 것이 아니라 “이 서버가 외부 기준 시간과 동기화되고 있는 상태인가”를 확인하는 단계로 넘어가게 됩니다. 이때 사용된 명령어는 다음과 같습니다.

timedatectl 

출력 결과에서 System clock synchronized: no 라는 문구가 보인다면, 이는 시간 동기화가 정상적으로 이루어지고 있지 않다는 신호로 해석됩니다. 이 상태에서는 Webmin에서 시간을 한 번 맞춰도, 그것이 ‘동기화된 시간’이라고 보기는 어렵습니다.


chronyd가 멈춘 것이 아니라, 기준에 도달하지 못하고 있었던 흐름

시간 동기화 데몬인 chronyd의 상태를 확인해보았습니다.

systemctl status chronyd chronyc tracking 

여기서 Reference ID가 00000000으로 표시되고, Stratum이 0으로 유지된다면 이는 chronyd가 동작은 하고 있으나 외부 시간 서버와 통신하지 못하고 있다는 상태로 해석됩니다. 설정 문제라기보다는, 통신 경로 자체에 문제가 있을 가능성이 떠오르는 지점입니다.


방화벽 설정을 확인하면서 Inbound가 아닌 Outbound로 시선이 이동합니다

처음에는 자연스럽게 Inbound 방화벽 규칙을 확인하게 됩니다. SSH, MySQL, 웹 포트들이 정상적으로 열려 있는지 살펴보는 과정은 익숙하기 때문입니다. 하지만 NTP는 서버가 외부로 질의를 보내는 구조이기 때문에, Inbound가 아니라 Outbound 규칙이 실제 관건이 됩니다.

DB 서버에서는 ‘한국을 제외한 모든 국가 차단’ 정책이 적용되어 있었고, 이 설정이 Outbound에도 영향을 주고 있었습니다. 이로 인해 UDP 123 포트가 외부로 나가지 못하고 있었던 상황으로 보입니다.


Outbound UDP 123 허용 후 확인

systemctl enable chronyd
systemctl start chronyd
chronyc makestep
chronyc tracking

이후 Reference ID가 실제 한국 NTP 서버 주소로 표시되고, Leap status가 Normal로 전환되면서 시간 동기화가 정상적으로 이루어지고 있음을 확인할 수 있었습니다.


하드웨어 시계(RTC)까지 반영하며 정리합니다

마지막으로 시스템 시간만 맞춰진 상태에서 끝내지 않고, 하드웨어 시계에도 반영하는 과정이 이어졌습니다. 재부팅 시 시간을 유지하기 위해 필요한 단계로 보입니다.

hwclock --systohc hwclock 

이 과정을 통해 웹서버와 DB 서버 모두 동일한 기준 시간으로 동작하는 상태가 되었고, 이후 뉴스 등록 시 “미래 시간 등록 불가” 오류는 재현되지 않았습니다.


정리해보면, 문제는 시간보다 ‘기준’에 가까웠던 듯합니다

이번 흐름에서 인상적인 지점은, 웹서버 시간이 맞다는 사실이 오히려 문제 원인을 가리는 역할을 했다는 점입니다. 실제 기준은 DB 서버였고, DB 서버는 외부 기준 시간과 동기화되지 않은 채 고립된 상태로 시간을 유지하고 있었습니다.

시간 동기화는 평소에는 눈에 띄지 않지만, 예약·게시·검증처럼 시간 비교가 개입되는 순간 문제를 드러내는 요소로 보입니다. 특히 서버를 분리해 운영하는 구조에서는, “웹서버 시간만 보면 된다”는 생각을 한 번쯤 다시 점검해볼 필요가 있어 보입니다.

chronyc makestep
chronyc tracking
hwclock --systohc
문의답변