linux time synchronization
Published by Nineye under learning os on April 30, 2009얼마전까지 필자의 블로그를 띄워 놓은 서버의 시스템 시간이 맞지 않아서 이리 저리 찾아 본 내용에 대해 적어 보도록 하겠다.
우선, 나타난 현상은 rdate명령어로 time.bora.net의 시간과 맞춰줘도 언젠가는 날짜가 약 3일 후의 날짜로 변경되어 버리는 현상이었다.
따라서 자동으로 날짜를 바꾸는 daemon이 있는지, 동작하고 있는 process들을 모두 체크해 보고, 혹시 cron에 날짜바꾸는 내용이 있는지 찾아봤지만 전혀 찾을 수가 없었다.
최근에 시간이 좀 나서, 혹시나 하고 hardware clock을 확인해 보니, 헉! hardware clock이 며칠 후의 날짜로 되어있었다. 따라서 hardware clock을 system clock으로 맞춰놓긴 했는데… system clock은 재부팅 하기전에는 hardware clock으로 세팅되진 않을텐데… 어떻게 될지 며칠 동안 지켜봤는데, 역시 의심했던 대로 정답은 아니었다.
결국 이리저리 삽질하다가, 결국 system clock의 정확도와 관련된 /etc/adjtime 파일에 문제가 있다는 것을 발견하고, 이를 바로 잡아서 문제를 해결 했다.
여기서 부터는 system clock과 hardware clock에 대한 기본적인 내용과, 위 문제를 정확히 해결한 방법을 정리하도록 하겠다.
Clocks and Time in Linux
hardware clock(RTC(real-time clock)이라고도 함)과 system clock
일반적으로 컴퓨터에는 두가지 time이 있는데, 그것은 배터리 기반으로 항상 동작하고 있는 hardware(또는 BIOS, CMOS) clock과, os에서 유지하는 system clock이다. hardware clock은 일반적으로 os를 부팅할 때 system clock을 맞추는 용도로만 사용되며, 부팅 이후부터 system을 끄거나 재부팅 할 때 까지, system clock은 맞춰진 시간을 유지 시키는데 사용된다.
linux system에서, 관리자는 hardware clock을 UTC, GMT, local time 중에서 선택할 수 있다. 이 중에서, 일반적으로 UTC time으로 hardware clock을 유지하는데, 그 이유는, UTC time은 daylight-saving time(보통 여름에, 주간 시간을 늘이기 위해서 표준 시간보다 한 시간 더 일찍 맞추는 시간)을 자동으로 적용되게 해주기 때문이라고 한다. 선택 기준으로는 좀 부족한 것 같지만…
UTC time에도 한 가지 단점이 있다고 하는데 그것은, local time을 hardware clock으로 세팅해 버리는 os와 듀얼 부팅을 할 때, 그 os에서는 시간이 항상 틀리게 된다는 것이다. 왜나면 local time과 UTC time은 시간의 기준 자체가 다른데, linux 커널은 hardware clock을 항상 UTC로 인식하기 때문이다.
timezone 설정
linux에서의 timezone은 symbolic link 파일인 /etc/localtime에 연결되어 있는 파일로 세팅되며, /etc/localtime은 /usr/share/zoneinfo 디렉토리 내의 특정 timezone 파일에 연결될 수 있다. 필자의 경우 대한민국/서울이므로, /etc/localtime은 /usr/share/zoneinfo/Asia/Seoul 에 연결되어 있다. 이 링크를 설정하려면 다음의 명령어 라인을 입력하면 된다.
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
구 버전의 시스템에서는 /usr/share/zoneinfo 대신에 /usr/lib/zoneinfo 를 사용하는 시스템도 있다. 이는 아래의 “다른 시스템에서의 설정” 섹션을 참고하자.
UTC나 local time의 설정
linux가 부팅될 때, 초기화 스크립트들 중의 하나가, hardware clock을 system clock으로 복사하기 위해서 /sbin/hwclock을 실행시킬 것이다. hwclock은 –utc 옵션으로 실행되지 않는다면, hardware clock이 local time으로 설정 되었다고 가정한다. 따라서 Red Hat Linux에서는, 시작 스크립트를 수정하기 보다는 /etc/sysconfig/clock 파일을 수정하고 “UTC” 문자열이 들어 있는 라인을 “UTC=true”나 “UTC=false”로 적절히 변경해야 한다.
system clock의 설정
linux에서 system clock을 설정하려면, date 명령어를 이용하면 된다. date 명령어의 사용법은 간단하니, manual을 찾아 보자.
hardware clock의 설정
hardware clock을 설정의 일반적인 방법은, 우선 system clock을 설정하고, “/sbin/hwclock –systohc(hardware clock을 UTC로 사용하고 있으면 –utc를 붙이자)” 명령으로 현재 system clock을 hardware clock으로 설정할 수 있다. 옵션없이 hwclock명령을 실행시키면 –show 옵션을 실행시킨 것과 같이 현재 세팅되어 있는 시간을 보여준다. 그리고 –utc나 –localtime 옵션은 해당 시간의 타입으로 현재 설정되어 있는 시간을 보여준다.
다른 시스템에서의 설정
Red Hat Linux 5.0이나 5.1에서, date와 같은 특정 어플리케이션에서 정확한 시간을 보여주나, 또 다른 어플리케이션에서는 그렇지 않을 때, /usr/lib/zoneinfo에서 /usr/share/zoneinfo로의 timezone 정보의 이동으로 야기된 버그일 가능성이 크다. 해결 방법은, /usr/lib/zoneinfo에서 /usr/share/zoneinfo로 symbolic link를 만들면 된다.
기타
linux 커널은, 현 시스템에서 hardware clock이 UTC로 저장되어 있든 아니든, 상관 없이 1970년 1월 1일 자정부터의 초단위의 UTC 시간으로 저장되고 계산된다. 그리고 UTC와 localtime으로의 변환은 실시간으로 행해진다.
이 부분과 관련된 깔끔한 하나의 방법은, 해당 시스템을 사용하는 누군가가 다른 timezone에 있을 때, TZ 환경 변수를 설정할 수 있고, 이로 인해 모든 날짜와 시간은 사용자의 timezone에 정확히 나타나게 할 수 있는 것이다.
1970년 1월 1일 자정으로부터의 초단위 숫자가 signed 32-bit integer(linux/intel system)로 저장된다면, 그 시스템에서의 clock은 2038년 어느 때 동작을 멈출 것이다. 따라서 linux는 본래부터 Y2K의 문제는 없었으나, 2038년의 문제는 가지고 있다. 하지만 요즘, 64bit 시스템이 많이 나오고 있으며, 그때가 되기 전에 모두 64-bit 시스템으로 바꾼다면 대략 2922억년까지의 clock을 보장받을 수 있다.
hwclock과 시간 동기화
hardware clock은 100% 정확하지는 않다. 하지만 그 오차(systematic drift라 불림)는 일정하기 때문에 특정 조정값(/etc/adjtime 에 저장)으로 오차를 최소화 할 수 있으며, hwclock 명령어에 그러한 기능이 있다.
필자의 삽질 원인이 바로 /etc/adjtime에 맞춰 커널의 time variable이 변경된 것이 원인이었던 것 같다. 시작 스크립트에 adjtimex명령과 비슷한 역할을 하는 명령을 수행하는 부분이 있었던 것 같은데, adjtimex 명령어는 /etc/adjtime파일내의 내용과 커널의 time variable을 맞추는 기능이 포함되어 있다.
hwclock을 이용한 시간 동기화 방법을 알아보면,
- /etc/adjtime을 삭제한다(지우지 않고도 맞출 수 있지만, 그냥 깔끔한 것을 좋아하기 때문에..)
- hwclock명령을 –set이나 –systohc 옵션으로 실행하여, system clock을 hardware clock으로 맞추고 /etc/adjtime 파일을 생성하여 최종 조정된 시간을 기록한다
- 일정 시간이 경과 후, hwclock –set[or --systohc] 명령을 실행하면 hardware clock이 system clock으로 맞춰지는 동시에, /etc/adjtime 에는 시간의 오차가 기록된다
- 그 후에는 hwclock –adjust만 실행하면, /etc/adjtime에 기록된 오차만큼 hardware clock을 조정해 준다
여기서 주의해야 할 점은 어떤(?) linux 시스템은 24시간 이내의 hwclock –set [or --systohc] 실행은 최종 조정 시간만 갱신하고, 오차는 무시해 버리는 시스템도 있다고 한다. 따라서 24시간 이내의 주기적인 hwclock 명령 수행은 시간 동기화에 아무런 도움이 되지 못한다는 것이다(이 내용은 hwclock의 manual에서 본 것이 아니라 구글링을 통해 본 것이라 완전 신뢰할 수는 없지만…).
그리고 이런 방법으로 /etc/adjtime을 잘 맞춰놨다면, 시스템 재구동 시, 시작 스크립트에서 hwclock –hctosys(일반적인 경우 이렇게 동작하게 되어 있음) 명령 수행 이전에 hwclock –adjust를 수행하면, 오차를 보정한 시간을 system clock으로 적용할 수 있을 것이다.
NTP(Network Time Protocol)과 시간 동기화
일반적으로 NTP를 이용한 시간 동기화는 ntpd(NTP daemon)을 많이 이용한다. ntpdate는 rdate와 비슷한 역할을 하는 놈이라 생각하면 될 것 같고, ntp~ 명령어들이 많은데, 그냥 ntpd만 알아도 될 것 같다.
ntpd 프로그램은 인터넷 표준 시간 서버와 system clock과의 동기화를 맞추는 프로그램이다. 인터넷 시간 서버와 동기화 시키는 것이라, 여러 가지 문제(네트웍 성능, 응답 속도 등)가 영향을 줄 거라 생각할 수도 있지만, ntpd는 다양한 방법으로 이러한 문제를 해결하고 있다. 이는 ntpd manual을 참고해 주기 바란다. 인터넷 시간 서버의 시간 자체에 의심이 드는 사람도 manual을 참고하면, 기준으로 삼는 시간에 대한 history를 알 수 있다.
ntpd의 동작은 일반적으로 ntp.drift 파일명으로 저장되는 frequency 파일의 존재에 따라 다르며, 이 파일은 /etc/adjtime과 비슷하게, 최종 시간 오차의 추정 값을 가지고 있다.
ntpd 시작 시, ntp.drift 파일이 없으면, 특정 system clock 진동 시간과 오차에 빨리 적응하기 위해 만들어진 special 모드에 들어간다. 이 모드는 대략 15분 정도가 걸리며, 이 시간동안 인터넷 시간 서버와 동기화 시켜서, 시간과 frequency가 일반적인 값을 가지도록 하며, 그 이후에는 일반 모드에 들어간다. 한 시간 이후에는 frequency 파일이 만들어지며, 현재 frequency offset을 파일에 쓴다.
이후에, ntpd가 시작될 때, 미리 생성된 frequency 파일이 있으면, ntpd의 frequency는 파일의 내용으로 초기화 되고, ntpd는 바로 일반 모드로 들어간다. 그 이후에 ntpd는 한 시간마다 현재 frequency offset을 frequency 파일에 써서, 다음 실행시의 오차 보정을 준비한다.
ntpd에 의해 보정된 system clock을 system clock으로 설정하는 방법은 여러 가지가 있는데, 그 중, 디폴트이면서 일반적인 방법은 커널의 11분 모드(11분 마다 system clock을 hardware clock으로 설정하는 모드)를 이용하는 것이다.
이것이 왜 디폴트냐면, 일반적으로 11분 모드는 꺼져있는 상태인데, ntpd가 실행되면 11분 모드를 켠다. 그래서 내부 동작에 신경을 쓰지 않는 사용자의 시스템이라면 대부분 11분 모드가 켜져있다고 생각할 수 있다.
필자가 겪은 문제가 발생한 원인을 위 정보를 통해 처음부터 정리해 보면,
- 자동 시간 동기화를 위해 ntpd를 띄움
- 누군가(?)가 hwclock –set [or --systohc]를 실행하여 오차를 /etc/adjtime에 기록하는데, 설정 시 시간 오차가 컸기 때문에 오차가 큰 조정값이 /etc/adjtime에 저장 됨
- ntpd는 자동으로 커널의 11분 모드를 켜기 때문에 hardware clock도 빠른 system clock과 동기화 됨
- ntpd 대신에 주기적인 rdate를 이용하려고 ntpd를 disable 시키고 재부팅
- 시작 스크립트에서 /etc/adjtime의 내용을 커널의 time variable에 맞춤
- 커널의 time variable의 오차만큼 system clock이 빨리 감
이 문제의 원인이었던 것 같다. 위의 상태에 대해서 모두 테스트 해보지는 않아서 원인이 다른 데 있을 수도 있는데 거의 위의 이유 때문일 것 같다.
결국, 문제를 어떻게 해결했냐면,
- ntpdate로 system clock을 인터넷 시간 서버에 맞춤
- /etc/adjtime 파일 삭제
- hwclock –systohc 로 hardware clock을 system clock에 맞춤
- 몇 분 후, 다시 hwclock –systohc 로 hardware clock을 system clock에 맞춤
- ntpd가 시작 스크립트에 포함되었는지 확인하고 재부팅
간단히 설명하면, /etc/adjtime 파일을 지우고 hwclock을 두 번 호출함으로써 /etc/adjtime을 대충 맞춘 다음, 재부팅 후 ntpd가 system clock을 맞춰가는 동안, hwclock을 호출하여, 맞춰지는 system clock에 hardware clock도 점점 맞추어간다는 것이다.
주의해야 할 점은, system clock의 시간과 인터넷 시간 서버의 시간이 1000초 이상 차이가 나면, ntpd는 뭔가 오동작 한 것일 수 있다고 판단하고 자동 조정을 중단한 뒤 log를 남기고 종료된다. 따라서 위처럼 어느 정도 맞게 조정하고 다시 시스템을 재부팅 시킨 것이다.
Visiting your Blog today. Thanks for this information. Pleased to meet you.
Thanks for your visiting.
Pleased to meet you too.
I hope that you often visit my blog.
제꺼는 우분투(9.04)에요. 저도 ntpd 가 돌아가고 있었는데 안생긴 걸 보면 ntpd 가 hwclock 을 수행한 건 아닌거 같네요.
흠.. 그러게.. 앞서 말했듯이 정확히 누가 /etc/adjtime을 생성하는 hwclock을 실행하는 지는 잘 모르겠어..
근데 11분모드는 켜져 있는 상태야? 아님 꺼져 있는 상태야?
켜져 있는 상태라면 적어도 11분 모드가 system clock을 hardware clock으로 수정 시, /etc/adjtime이 조정되지는 않는 것이겠네…
ntpd는 system clock을 조정하는 역할도 하니까, 위 상태대로라면 ntpd가 직접 ntp.drift 정보를 토대로 커널 time variable을 수정한다고 생각할 수도 있을 것 같네.. ntpd 메뉴얼에서는 커널 time variable에 대한 내용은 명시되어 있지 않아서 정확한지는 잘 모르겠지만…
제꺼는 /etc/adjtime 파일이 없네요. hwclock –systohc 실행해 주니까 생성되긴 하는데… 없어도 문제가 없는데 애초에 왜 hwclock 이 수행됐는지 궁금하군요.. 글고 다른 시스템의 설정에 red hat 5.0, 5.1 얘기가 나오는데 이건 enterprize 말하는건가요?
흠.. 어떤 시스템인지 모르겠네…
어쨌든 ntpd를 동작시키면, 11분 모드가 작동해서 11분 마다 system clock을 hardware clock으로 맞추는데,
이게 hwclock 명령어를 수행해서 맞추는 건지는 잘 모르겠어… 만약 그렇다면 그 명령어를 통해서 /etc/adjtime 이 생성되었겠지…
어쨌든 누군가가 수행했고, 그 때 엉망이었던 system clock의 오차 값이 그대로 저장되었나봐..
그리고 내 os는 centos-64야… redhat 계열이지… redhat이랑 거의 비슷할거야..