批处理跑在入队之前 — 时钟快了 2.4 秒
한국어 원문으로 표시합니다.
목표
표기가 제각각인 다섯 호스트의 로그를 한 축으로 모으고, 시각 계통에서 고립된 호스트를 찾고, 요청과 응답의 모순으로 시계 오차의 하한을 구한 뒤, 보정으로 설명되는 것과 설명되지 않는 것을 갈라 시각 신뢰성 진술서를 씁니다.
왜 중요한가
조사도 감사도 "무엇이 먼저 일어났는가" 를 묻습니다. 그 답은 기록의 시각에서 나오는데, 기록의 시각은 그것을 남긴 기계의 시계가 보여 준 값입니다. 2초쯤 어긋난 시계는 아무도 눈치채지 못한 채 원인과 결과를 뒤집습니다. 폐쇄망에서는 바깥 시각원이 없어 망 안의 시각원 하나에 모두가 맞추므로, 서로의 순서는 맞아도 절대 시각은 보증되지 않습니다. 진술서에 그 한계를 쓰지 않으면 나중에 그 문서 전체가 무너집니다.
왜 자료로 판정하는가
실습 파드에는 capability 가 없어 chronyc·ntpdate 를 쓸 수 없고 시스템 시계도 바꿀 수 없습니다. 그래서 이 실습은 동기화 상태 보고와 로그만으로 판정합니다. 실제 현장에서도 감리에 내는 것은 명령 출력이 아니라 이 판정의 결과이며, chronyc tracking 과 sources 의 출력이 여기 sync.json 이 놓인 자리를 차지합니다. 이 실습의 가정입니다.
단계
python3로/root/clock/data에sync.json·meta.json·로그 다섯 개·requests.csv를 만듭니다.- 다섯 로그를
/root/clock/normalized.csv에host,seq,epoch_ms,evt로 모으고, 오프셋 없는 로그를 UTC 로 잘못 읽었을 때의 영향을/root/clock/naive.json에 적습니다. - 호스트별 시각원 사슬을
/root/clock/chain.json에, 선언된 시각원에 닿지 않는 호스트를/root/clock/isolated.txt에 적습니다. - 응답이 요청보다 앞선 건을
/root/clock/paradox.csv에, 시계 오차의 하한을/root/clock/bound.json에 적습니다. - 한 호스트의 로그 안에서 시각이 되돌아간 자리를
/root/clock/backward.csv에 적습니다. - 오프셋으로 보정한 시각을
/root/clock/corrected.csv에, 보정 전후 모순 수를/root/clock/paradox_after.json에 적습니다. - 호스트마다 기록 신뢰 등급을
/root/clock/trust.csv에host,level,reason으로 적습니다. /root/clock/statement.json과/root/clock/statement.md에 시각 신뢰성 진술서를 씁니다.
참고
- 로그 표기 규칙은
/root/clock/data/meta.json에 있습니다. 오프셋이 없는 로그를 UTC 로 읽으면 아홉 시간이 밀립니다. - 7단계 판정 규칙은 순서대로 적용합니다. 계통 미도달이면
설명안됨, 아니면 로그에 역행이 있을 때설명안됨, 아니면 보정 뒤에도 그 호스트가 낀 모순이 남으면설명안됨, 아니면 보정 전 모순에 낀 적이 있으면보정으로설명됨, 나머지는확인됨입니다.reason은 차례로계통미도달·역행·보정후모순·보정필요·없음입니다. - 보정은
참값 = 관측값 - offset_ms입니다. 부호를 뒤집으면 모순이 오히려 늘어납니다. - 흔한 실수 1:
epoch_ms를 실수로 두는 것. 정수 밀리초로 반올림해 적으세요. - 흔한 실수 2: 동기화를 타임스탬프 증명과 같은 것으로 쓰는 것. 둘은 다른 층이고 RFC 3161이 뒤쪽 자리를 맡습니다.
- 표준 문서: RFC 5905, RFC 3339, NIST SP 800-92.
동기화 보고와 다섯 호스트의 로그 만들기
python3 로 /root/clock/data 에 sync.json·meta.json·node-a.log부터 node-e.log·requests.csv 를 만듭니다. 난수를 쓰지 않는 생성 스크립트를 그대로 쓰세요.
폐쇄망에는 내려받을 표본이 없으니 자료부터 직접 만듭니다. 난수를 쓰지 않아야 누가 몇 번을 돌려도 같은 자료가 나오고 서로의 판정을 대조할 수 있습니다. 채점기는 자료를 표준형으로 바꿔 지문을 대조하므로 손으로 고치면 뒤 단계가 전부 막힙니다.
표기 넷을 한 축으로 모으기
/root/clock/normalized.csv 에 첫 줄 host,seq,epoch_ms,evt 를 두고 다섯 로그의 사건을 모두 적으세요. /root/clock/naive.json 에는 naive_utc_hosts·shifted_events·shift_hours 를 적습니다.
epoch_ms 는 UTC 기준 밀리초 정수입니다. 오프셋이 붙은 것은 그대로 읽히고, 오프셋이 없는 것은 meta.json 이 알려 주는 시간대로 읽어야 합니다. 그것을 UTC 로 읽으면 몇 시간이 밀리는지가 naive.json 의 내용입니다.
시각원 계통을 끝까지 따라가기
/root/clock/chain.json 에 호스트마다 따라간 시각원 사슬을 목록으로 적고, 선언된 시각원에 닿지 않는 호스트를 /root/clock/isolated.txt 에 한 줄에 하나씩 적으세요.
사슬은 그 호스트의 source 부터 시작해 한 걸음씩 따라갑니다. LOCAL 을 만나거나 이미 지나온 이름을 다시 만나면 거기서 멈추고, 그 이름까지 사슬에 넣습니다. 선언된 시각원 자신은 고립 판정에서 빼세요.
응답이 요청보다 앞선 건으로 오차의 하한 구하기
/root/clock/paradox.csv 에 첫 줄 req_id,sender,receiver,delta_ms 를 두고 delta_ms 가 음수인 건을 적고, /root/clock/bound.json 에 min_skew_ms·sender·receiver 를 적으세요.
delta_ms 는 수신 시각에서 전송 시각을 뺀 값입니다. 음수라면 두 시계가 최소한 그 크기만큼 벌어져 있다는 뜻이고, 가장 큰 음수의 크기가 하한입니다. 하한은 양수로 적습니다.
한 호스트 안에서 시각이 되돌아간 자리 찾기
/root/clock/backward.csv 에 첫 줄 host,seq,prev_epoch_ms,epoch_ms 를 두고, 같은 호스트의 로그에서 바로 앞줄보다 시각이 작아진 지점을 적으세요.
호스트별로 seq 순서대로 읽으며 바로 앞 줄의 시각과 견줍니다. 호스트가 섞이지 않게 나눠서 보세요. 시각이 되돌아간 구간의 기록은 순서를 근거로 쓸 수 없습니다.
오프셋으로 보정하고 남는 것 보기
/root/clock/corrected.csv 에 첫 줄 host,seq,epoch_ms 를 두고 보정한 시각을 적고, /root/clock/paradox_after.json 에 before·after·remaining 을 적으세요.
보정은 관측값에서 그 호스트의 offset_ms 를 빼는 것입니다. 부호를 뒤집으면 모순이 오히려 늘어납니다. 요청도 같은 방법으로 양쪽을 보정한 뒤 다시 음수를 세면, 남는 것이 시계로 설명되지 않는 진짜 결함입니다.
호스트마다 기록 신뢰 등급 매기기
/root/clock/trust.csv 에 첫 줄 host,level,reason 을 두고 로그가 있는 다섯 호스트를 판정하세요. 규칙은 실습 안내의 순서대로 적용합니다.
규칙은 먼저 맞는 것 하나만 적용합니다. 계통이 닿지 않는 호스트는 다른 근거를 볼 것도 없이 설명안됨입니다. 보정 전에 모순에 끼었지만 보정 뒤 사라졌다면 조건부로 쓸 수 있는 구간입니다.
믿을 수 있는 것과 없는 것을 함께 적은 진술서 쓰기
/root/clock/statement.json 에 root·root_has_external_reference·confirmed·corrected·unexplained·min_skew_ms·remaining_contradictions 를 적고, /root/clock/statement.md 에 ## 판단·## 근거·## 믿을 수 없는 것·## 남은 의심 네 절로 500자 이상 쓰세요.
진술서의 값은 손으로 세지 말고 앞 단계와 같은 계산에서 가져옵니다. 시각원이 바깥 기준을 가지고 있는지는 그 시각원의 source 가 무엇인지로 정해집니다. 믿을 수 없는 호스트는 이름을 적어야 읽는 사람이 무엇을 빼고 읽어야 하는지 압니다.