연산 장비 여러 대를 지켜보는 화면을 만들었고 각 장비가 지표를 보내면 그래프로 그린다.
며칠 뒤 한 장비의 그래프가 비어 있었다. 멈춘 것인지 할 일이 없던 것인지 알 수 없었다.
Table of contents
Open Table of contents
구분이 안 됐다
수집 스크립트를 봤다.
for dev in $(list_active_devices); do
hashrate=$(read_hashrate "$dev")
send_metric "device.$dev.hashrate" "$hashrate"
done
list_active_devices 가 내놓는 목록을 돌면서 send_metric 을 부른다. 장비가 그 목록에서 빠지면 반복이 안 돌고 지표도 안 나간다.
그런데 목록에서 빠지는 이유가 여럿이었다.
장비가 실제로 죽었다
연결이 끊겼다
목록을 가져오는 명령이 실패했다
수집 스크립트 자체가 안 돌았다
넷이 전부 그래프가 빈다로 보인다. 특히 마지막이 문제인데 스크립트가 죽으면 모든 장비가 동시에 비고 그것이 전부 죽은 것인지 감시가 죽은 것인지 안 갈린다.
화면을 보는 사람 입장에서는 up 값이 없는 넷이 같은 그림이다. 빈 구간 앞에서 무엇을 해야 하는지가 안 정해진다.
그래서 빈 그래프를 볼 때마다 사람이 ssh 로 장비에 붙어 확인해야 했다. 감시를 만든 이유가 그 확인을 없애는 것이었는데 그 자리가 그대로 남아 있었다.
원인 — 데이터가 키를 정하는 구조
문제의 뿌리는 무엇을 보낼지를 그때그때 조회 결과가 정한다는 데 있었다. list_active_devices 결과가 비면 보낼 것도 없어진다.
그러면 없다는 사실 자체가 안 나간다. 말해 줄 값이 없으니 받는 쪽은 침묵만 본다.
보낼 목록은 미리 알고 있어야 했고 장비 구성은 우리가 정한 것이지 발견할 대상이 아니다.
조회로 목록을 만드는 것이 편해 보인 이유가 있다. 장비가 늘어도 코드를 안 고쳐도 된다. 대신 무엇이 빠졌는지를 알 방법을 잃었다.
편의를 얻고 확인 능력을 내준 셈인데 감시에서는 그 거래가 손해였다.
조치 — 없어도 보내는 값
목록을 선언으로 바꾸고 없을 때도 보내게 했다.
DEVICES="dev0 dev1 dev2 dev3 dev4 dev5" # 선언
for dev in $DEVICES; do
if hashrate=$(read_hashrate "$dev" 2>/dev/null); then
send_metric "device.$dev.hashrate" "$hashrate"
send_metric "device.$dev.up" 1
else
send_metric "device.$dev.up" 0 # 없어도 보낸다
fi
done
DEVICES 를 미리 적어 두고 read_hashrate 가 실패하면 up 0 을 보내므로 장비가 죽어도 그래프가 0으로 떨어진다.
이 차이가 큰데 빈 것은 해석이 여럿이고 up 0 은 하나다.
up 값이 있는 것과 없는 것은 받는 쪽에서 처리가 다르다. 있으면 그 값을 그대로 해석하면 되고 없으면 왜 없는지를 먼저 따져야 한다.
보내는 쪽에서 한 번 판단해 0으로 적어 주면 받는 쪽의 그 단계가 사라진다. 판단을 앞으로 옮긴 것이다.
수집기 자신의 신호
DEVICES 를 도는 스크립트가 죽으면 이것으로도 안 잡힌다. 아무것도 안 나가기 때문이다.
그래서 수집기 자신이 살아 있다는 심장박동을 하나 더 넣었다.
send_metric "collector.heartbeat" 1
장비가 몇 대든 하나도 없든 매 주기마다 collector.heartbeat 하나는 무조건 나가게 했다.
collector.heartbeat 가 안 오면 수집기가 죽은 것이다. 장비 지표가 안 오는 것과 구분된다.
| 관측 | 해석 |
|---|---|
heartbeat 있음 + up 1 | 정상 |
heartbeat 있음 + up 0 | 그 장비가 죽음 |
| heartbeat 있음 + 지표 없음 | 선언 목록에서 빠짐 — 설정 문제 |
| heartbeat 없음 | 수집기가 죽음 |
네 줄이 전부 다른 대응으로 이어지고 지표 하나를 더 보내 침묵을 넷으로 쪼갠 셈이다.
알림 조건을 바꿨다
원래 알림은 값이 임계 아래로 떨어질 때만 울리게 돼 있어 값이 안 오면 알림도 안 왔다.
그래서 일정 시간 안에 값이 안 오면 울리는 조건을 새로 추가했다.
device.*.up 이 5분간 없음 → 알림
collector.heartbeat 이 3분간 없음 → 알림
부재를 조건으로 만든 것인데 이것이 없으면 감시 시스템은 조용한 상태를 정상으로 본다.
가장 위험한 상태가 가장 조용한 상태였고 값이 튀는 것보다 끊기는 것을 먼저 봐야 했다.
값이 튀는 것은 적어도 무언가가 돌고 있다는 뜻이다. 끊기는 것은 돌고 있는지조차 모른다는 뜻이다.
그래서 임계 조건보다 collector.heartbeat 부재 조건을 더 짧게 잡았다. 먼저 알아야 할 것을 먼저 울리게 했다.
선언 목록을 어디에 두나
장비 목록을 스크립트에 박아 두면 장비를 늘릴 때마다 스크립트를 고쳐야 한다. 별도 파일로 뺐다.
# devices.conf — 감시 대상. 여기 없으면 감시되지 않는다.
dev0
dev1
...
devices.conf 가 곧 대장이라고 문서에 적었고 장비를 추가하면 여기 넣어야 하며 안 넣으면 조용히 빠진다.
그래서 물리 장비 대수와 devices.conf 의 줄 수를 대조하는 점검을 돌렸다. 사람이 빠뜨리는 것을 기계가 잡게 했다.
정리
- 0일 때 아무것도 안 보내면 정지와 무작업이 안 갈린다
- 보낼 키를 조회 결과에서 만들면 없음이 침묵으로 나온다
- 구성은 발견할 대상이 아니라 우리가 미리 선언할 것이다
- 장비가 죽어도
up 0을 보내면 빈 그래프가 0으로 바뀐다 - 빈 것은 해석이 여럿이고 0은 하나다
collector.heartbeat로 수집기 자신의 생존을 따로 보낸다- 그 둘의 조합이 침묵 하나를 네 가지 해석으로 쪼갠다
- 알림에 값이 안 오면을 넣지 않으면 조용한 상태가 정상으로 보인다
devices.conf가 대장이므로 실제 대수와 대조하는 점검을 따로 돌린다