수집 서버가 네 대였다. 자료가 일부 안 들어온다는 얘기를 듣고 한 대에 접속해 로그를 봤다.
정상이었고 문제없다고 답했다. 이틀 뒤에 같은 얘기가 또 왔다.
Table of contents
Open Table of contents
나머지 세 대는 안 봤다
이번에는 네 대를 다 봤다.
srv-01 정상
srv-02 정상
srv-03 디스크 98%, 저장 실패 다수
srv-04 정상
srv-03 만 문제였다. 처음에 srv-01 을 보고 전체를 판단한 것이다.
그 한 대를 고른 이유를 되짚어 보니 아무것도 없었다. 접속 정보 목록에서 맨 위에 있어서였다.
원인 — 확인 단위와 구성 단위
srv-01 부터 srv-04 까지 네 대가 같은 일을 나눠서 한다. 각자 다른 대상을 맡고 있으니 한 대의 상태가 다른 대를 대신 말해 주지 않는다.
그런데 확인은 한 대 단위로 했다. 구성은 넷인데 확인은 하나였으니 처음부터 답이 나올 수 없는 구조였다.
한 대에서 tail 로 로그를 보고 나머지도 정상일 것이라는 가정을 세운 적도 없다. 그냥 그렇게 행동했고 그것이 가정이라는 것도 이틀 뒤에 알았다.
한 번에 보는 방법을 만들었다
네 대를 하나씩 접속하는 것이 번거로워 한 번에 돌게 묶었다.
#!/bin/sh
for h in srv-01 srv-02 srv-03 srv-04; do
echo "=== $h ==="
ssh "$h" '
echo "disk: $(df -h /data | awk "NR==2 {print \$5}")"
echo "proc: $(pgrep -c -f collector)"
echo "last: $(tail -1 /var/log/collector.log)"
'
done
df 로 남은 자리를 보고 pgrep -c 로 프로세스 수를 세고 로그 마지막 줄을 가져온다. 한 번 돌리면 네 대가 차례로 나온다.
접속이 안 되는 경우도 표시하게 했다.
if ! ssh -o ConnectTimeout=5 "$h" true 2>/dev/null; then
echo "=== $h === 접속 불가"
continue
fi
접속이 안 되는 것도 하나의 상태다. 그냥 건너뛰면 확인하지 않은 대가 목록에서 사라지고 정상이라 안 나오는 것과 구분이 안 된다.
ConnectTimeout 을 5초로 둔 것은 죽은 대에서 ssh 가 오래 붙들리지 않게 하려는 것이다. 한 대가 멈춰 있으면 나머지 세 대의 확인도 그만큼 늦어진다.
수치를 한 표로 모았다
각 대의 값을 나란히 놓고 비교했다.
호스트 디스크 수집건수(1h) 실패(1h)
srv-01 62% 12,040 3
srv-02 58% 11,890 2
srv-03 98% 8,210 412
srv-04 61% 12,110 1
srv-03 이 세 열에서 모두 튄다. 디스크가 98%이고 수집 건수는 삼분의 이 수준이고 실패는 백 배가 넘는다.
df 값에 절대 기준이 없어도 네 대를 서로 비교하면 이상이 드러난다. 실패 세 건이 많은 것인지는 혼자 보면 모르는데 옆에 나란히 놓으면 412가 무엇인지는 바로 안다.
조치 — 각 대가 상태를 보내게
손으로 돌리는 것보다 각 대가 스스로 보고하는 쪽이 나았다.
# 각 서버에서 5분마다
curl -s -X POST http://monitor/api/status \
-d "host=$(hostname)" \
-d "disk=$(df /data | awk 'NR==2 {print $5}' | tr -d '%')" \
-d "collected=$(count_recent)" \
-d "failed=$(count_failed)"
hostname 과 디스크 사용률과 최근 수집·실패 건수를 5분마다 감시 서버로 보낸다. 모이니 한 화면에서 넷을 본다.
안 보내는 대가 있으면 그것도 드러난다.
SELECT host, MAX(reg_date) FROM server_status GROUP BY host;
MAX(reg_date) 가 오래된 대가 있으면 그 대에 문제가 있다는 뜻이다. curl 을 돌리는 쪽이 죽으면 그것이 침묵으로 나타난다.
대상 목록을 자료로 뒀다
서버 목록을 스크립트에 박아 두면 대가 늘 때마다 스크립트를 고쳐야 한다.
# /etc/monitor/hosts
srv-01
srv-02
srv-03
srv-04
/etc/monitor/hosts 에서 읽게 하고 대가 늘면 한 줄을 더한다. 감시 서버에서도 이 목록과 보고를 대조했다.
SELECT h.host FROM expected_hosts h
LEFT JOIN (SELECT host FROM server_status WHERE reg_date >= DATE_SUB(NOW(), INTERVAL 15 MINUTE)) s
ON s.host = h.host
WHERE s.host IS NULL;
expected_hosts 에 있는데 최근 15분 보고가 없는 대를 뽑는다. 보고가 온 것만 보면 안 온 대를 영영 못 본다.
무엇이 빠졌는지는 있는 것만 봐서는 알 수 없다. 있어야 할 목록이 따로 있어야 그 비교가 된다.
변경 내용 — 확인 순서
문제 얘기를 들었을 때의 순서 자체를 바꿨다.
전 한 대에 접속 → 로그 확인 → 판단
후 전체 상태 조회 → 이상한 대 식별 → 그 대에 접속
server_status 를 먼저 보면 어디를 봐야 할지가 정해진다. 접속할 대를 고르는 것이 감이 아니라 표에서 나온 값이 된다.
순서를 바꾼 것뿐인데 같은 실수를 할 자리가 없어졌다. 첫 단계에서 네 대가 다 보이므로 한 대만 보고 답하는 경로 자체가 사라진다.
정리
- 여러 대가 같은 일을 하면 한 대의 상태가 전체를 대표하지 않는다
- 확인의 단위를 실제 구성의 단위에 맞춘다
- 전부를 한 번에 도는 스크립트를 만들고
ConnectTimeout을 둔다 - 접속이 안 되는 것도 상태이므로 건너뛰지 않고 표시한다
- 수치를 한 표로 나란히 놓으면 절대 기준 없이도 이상이 보인다
- 각 대가
curl로 상태를 보내게 하면 손으로 안 돌려도 된다 - 마지막 보고 시각이 오래된 대는 침묵으로 드러난다
- 대상 목록을 파일로 두고
expected_hosts와 대조한다 - 확인 순서를 전체에서 개별로 바꾸면 같은 실수를 할 자리가 없다