워치독
고친 사람 github-actions[bot]
워치독은 시스템이 멈추지 않았는지 지켜보다가 멈추면 스스로 다시 시작시킵니다. 감시받는 프로그램은 정해진 시간 안에 한 번씩 아직 괜찮다는 신호를 보내야 합니다. 신호가 끊기면 워치독은 멈춘 것으로 보고 재시작을 겁니다. 흔히는 장비 안의 전용 타이머를 가리킵니다. 서버에서 프로세스를 지켜보는 프로그램도 같은 이름으로 부릅니다.
쉽고 빠른 이해
워치독은 멈춘 시스템을 사람 손 없이 되살리는 장치입니다. 산속 중계소에 놓인 장비가 멈추면 누군가 올라가 전원을 껐다 켜야 합니다. 워치독이 있으면 장비가 알아서 다시 켜집니다.
이게 없으면 멈춘 장비는 누가 알아챌 때까지 멈춘 채로 남습니다. 프로그램이 멈추는 원인은 다 없앨 수 없습니다. 그래서 멈춘 것을 알아채고 되살리는 장치를 따로 둡니다.
어떻게 도나:
- 워치독이 정해진 시간부터 거꾸로 셉니다
- 프로그램이 제대로 돌면 시간이 다 되기 전에 셈을 처음으로 되돌립니다
- 되돌리지 못한 채 시간이 다 되면 워치독이 장비를 다시 시작시킵니다
대가가 있습니다. 다시 시작하면 하던 일과 메모리에 있던 값이 사라집니다. 멈춘 원인은 그대로 남아서 같은 멈춤이 되풀이될 수 있습니다. 멈추지 않고 틀린 값을 내는 고장은 알아채지 못합니다.
상세
이 절은 워치독이 어떻게 멈춤을 알아채고 되살리는지 봅니다. 장비 안에 든 워치독 타이머를 중심으로 봅니다. 끝에서 서버 쪽 워치독과 하트비트·헬스 체크를 견줍니다.
워치독이라는 말은 두 뜻으로 씁니다. 좁게는 임베디드 장비의 칩 안에 든 전용 타이머입니다. 넓게는 같은 원리로 다른 프로그램을 지켜보는 소프트웨어입니다. 둘은 멈춤을 알아채는 방식이 같습니다. 되살리는 대상이 장비 전체인지 프로그램 하나인지만 다릅니다.
비유로 보는 워치독
혼자 산에 오르는 사람이 집에 약속을 해 둡니다. 두 시간마다 전화를 하겠다고, 전화가 안 오면 구조대를 불러 달라고 합니다. 집에 있는 사람은 산을 지켜볼 필요가 없습니다. 전화가 오는지만 보면 됩니다.
멈춘 채로 남는 장비
프로그램은 여러 이유로 멈춥니다. 끝나지 않는 반복문에 갇히기도 합니다. 두 작업이 서로 상대가 쥔 자원을 기다리며 함께 멈추기도 합니다. 뒤엣것을 데드락이라고 부릅니다.
사람이 곁에 있는 서버라면 누군가 경보를 보고 다시 띄웁니다. 세탁기나 공장 센서나 인공위성 안의 컴퓨터는 사정이 다릅니다. 곁에 사람이 없거나, 사람이 손을 쓰기 전에 일이 커집니다.
멈추는 원인을 코드에서 전부 없앨 수는 없습니다. 전기 잡음 한 번에 메모리 값이 바뀌기도 합니다. 그래서 원인을 막는 것과 별개로, 멈춘 것을 알아채고 되살리는 장치를 하나 더 둡니다.
거꾸로 세는 타이머
워치독 타이머는 정해진 값에서 0을 향해 거꾸로 세는 카운터입니다. 0에 닿으면 칩 전체를 다시 시작시키는 신호를 냅니다. 전원을 껐다 켠 것처럼 처음부터 다시 도는 이 동작을 리셋이라고 부릅니다.
프로그램은 0에 닿기 전에 카운터를 처음 값으로 되돌려야 합니다. 이 동작을 킥(kick)이라고 부릅니다. 먹이 주기(feed)나 쓰다듬기(pet)라는 이름도 씁니다. 모두 같은 동작입니다.
sequenceDiagram
participant 프로그램
participant 워치독
프로그램->>워치독: 킥
Note over 워치독: 처음 값부터 다시 센다
프로그램->>워치독: 킥
Note over 워치독: 처음 값부터 다시 센다
Note over 프로그램: 여기서 멈춘다
Note over 워치독: 0에 닿는다
워치독->>프로그램: 칩 전체를 리셋
프로그램이 제대로 도는 동안은 킥이 제때 와서 카운터가 0에 못 닿습니다. 프로그램이 멈추면 킥이 끊깁니다. 그러면 카운터가 0에 닿는 순간 리셋이 걸립니다.
감시하는 쪽이 따로 떨어진 까닭
감시하는 쪽이 감시받는 쪽과 함께 멈추면 쓸모가 없습니다. 그래서 워치독 타이머는 프로그램을 돌리는 처리 장치와 떨어진 회로로 만듭니다. 프로그램이 통째로 멈춰도 카운터는 혼자 계속 셉니다.
같은 이유로 한번 켠 워치독은 프로그램이 끄지 못하게 만들기도 합니다. 고장 난 프로그램이 엉뚱한 코드를 돌다가 워치독을 꺼 버리면 감시가 사라지기 때문입니다.
어디서 킥하느냐가 감시 범위를 정한다
워치독이 알아채는 것은 킥이 끊겼다는 사실 하나입니다. 그래서 킥을 코드 어디에 두느냐에 따라 무엇을 지켜보는지가 달라집니다.
흔한 실수는 인터럽트 처리 함수에서 킥하는 것입니다. 인터럽트는 하던 일을 잠깐 끊고 급한 처리를 먼저 하게 만드는 하드웨어 신호입니다. 타이머 인터럽트는 본 작업이 멈춰도 제때 계속 불립니다.
void timer_isr(void) { // 1초마다 불린다
wdt_kick(); // 본 루프가 멈춰도 온다
}
위 코드에서는 본 작업이 데드락에 걸려도 킥이 계속 옵니다. 워치독은 장비가 멀쩡하다고 보고 리셋을 걸지 않습니다. 함수 이름은 설명을 위해 지은 것입니다.
킥은 본 작업이 한 바퀴를 다 돌았을 때 닿는 곳에 둡니다. 아래처럼 하면 세 일 가운데 하나만 멈춰도 킥이 끊깁니다.
while (1) {
read_sensor();
run_motor();
send_report();
wdt_kick(); // 셋 다 끝나야 닿는다
}
작업 여럿이 동시에 따로 도는 장비는 킥 한 줄을 한 루프 끝에 둘 수 없습니다. 대신 작업마다 한 바퀴를 돌았다고 표시를 남기게 합니다. 표시가 전부 모였을 때만 킥합니다. 작업 하나만 멈춰도 워치독이 알아채게 하려는 것입니다.
너무 이른 킥도 잡는 창 워치독
보통 워치독은 킥이 늦는 것만 봅니다. 창 워치독(windowed watchdog)은 킥이 너무 이른 것도 고장으로 봅니다. 킥이 정해진 시간 창 안에 와야만 받아 줍니다.
너무 이른 킥은 프로그램이 할 일을 건너뛰고 있다는 신호일 수 있습니다. 고장 난 프로그램이 킥 한 줄만 빠르게 되풀이하는 경우가 그렇습니다. 보통 워치독은 이런 고장을 멀쩡하다고 봅니다.
| 킥이 온 때 | 보통 워치독 | 창 워치독 |
|---|---|---|
| 창이 열리기 전 | 받아 준다 | 리셋 |
| 창 안 | 받아 준다 | 받아 준다 |
| 시간이 다 되도록 안 옴 | 리셋 | 리셋 |
표의 첫 줄이 둘을 가릅니다. 창 워치독은 프로그램이 제 속도로 도는지까지 봅니다.
기다리는 시간을 얼마로 잡나
카운터가 0에 닿기까지의 시간이 워치독의 타임아웃입니다. 이 값을 짧게 잡으면 멈춘 장비가 빨리 되살아납니다. 대신 오래 걸리는 정상 작업이 멈춤으로 읽힙니다.
저장 장치에 큰 데이터를 쓰는 일처럼 한 번에 오래 걸리는 작업이 있으면 그동안 킥을 못 합니다. 타임아웃이 그보다 짧으면 멀쩡한 장비가 작업 도중에 리셋됩니다. 반대로 길게 잡으면 멈춘 장비가 그만큼 오래 멈춰 있습니다.
그래서 타임아웃은 가장 오래 걸리는 정상 작업보다 넉넉히 길게, 멈춘 채로 버틸 수 있는 시간보다 짧게 잡습니다. 두 값 사이에 틈이 없으면 오래 걸리는 작업을 잘게 나눠 그 사이사이에 킥합니다.
되살린 뒤에 남는 것
리셋은 멈춤을 풀어 줄 뿐 원인을 고치지 않습니다. 같은 조건이 다시 오면 같은 곳에서 또 멈춥니다. 켜지자마자 멈추고 리셋되기를 끝없이 되풀이하는 상태를 부트 루프라고 부릅니다.
많은 장비가 켜질 때 지난번 리셋이 무엇 때문이었는지 먼저 확인합니다. 칩이 리셋 원인을 레지스터에 적어 두는 경우가 많습니다. 레지스터는 칩 안에 있는 작은 저장 칸입니다. 리셋 원인을 담는 칸은 리셋이 지우지 않습니다.
리셋 횟수처럼 프로그램이 직접 세는 값도 리셋이 지우지 않는 곳에 둡니다. 전원이 꺼져도 내용이 남는 비휘발성 메모리가 그런 곳입니다. 아래 흐름도의 횟수도 거기서 읽고 거기에 씁니다.
flowchart TD
A["켜진다"] --> B{"지난 리셋이 워치독 때문인가"}
B -->|아니다| C["평소대로 시작한다"]
B -->|그렇다| D["워치독 리셋 횟수를 하나 늘린다"]
D --> E{"횟수가 기준을 넘었나"}
E -->|아니다| C
E -->|넘었다| F["기능을 줄인 안전 모드로 시작한다"]
그림처럼 워치독 리셋이 잇달아 나면 기능을 줄인 안전 모드로 시작합니다. 안전 모드는 문제를 일으킨 기능을 빼고 꼭 필요한 일만 하는 상태입니다. 리셋 원인을 기록해 두면 나중에 사람이 무엇이 멈췄는지 추적할 수 있습니다.
워치독이 못 잡는 고장
워치독은 멈춤만 봅니다. 프로그램이 킥은 제때 하면서 틀린 값을 계산하고 있으면 워치독에게는 멀쩡해 보입니다. 이런 고장은 값을 검사하는 장치가 따로 잡아야 합니다.
리셋이 더 위험한 경우도 있습니다. 하던 일을 중간에 끊으면 데이터가 반쯤 쓰인 채로 남기도 합니다. 그래서 워치독을 두는 장비는 언제 끊겨도 다시 켜서 이어 갈 수 있게 짭니다.
서버 쪽 워치독
같은 원리를 소프트웨어로 만들어 프로세스를 지켜보기도 합니다. 프로세스는 실행 중인 프로그램 하나를 가리킵니다.
감시받는 프로세스는 정해진 간격마다 알림을 보냅니다. 장비에서 본 킥을 소프트웨어로 옮긴 것입니다. 알림이 끊기면 감시하는 프로그램이 그 프로세스를 끝내고 다시 띄웁니다.
운영체제의 커널이나 프로세스를 띄우고 관리하는 서비스 관리자가 이 일을 맡습니다. 장비 전체 대신 프로세스 하나만 되살리므로, 옆에서 도는 다른 프로세스는 영향을 받지 않습니다.
이 방식은 하트비트·헬스 체크와 닮았습니다. 셋을 가르는 것은 누가 먼저 말하느냐와 신호가 끊긴 뒤 무엇을 하느냐입니다.
| 워치독 | 하트비트 | 헬스 체크 | |
|---|---|---|---|
| 누가 먼저 말하나 | 감시받는 쪽이 알린다 | 감시받는 쪽이 알린다 | 감시하는 쪽이 묻는다 |
| 신호가 끊기면 | 감시받는 쪽을 다시 시작시킨다 | 죽었다고 판정하고 뒤처리를 맡긴다 | 요청을 보낼 후보에서 뺀다 |
표의 둘째 줄이 워치독을 가릅니다. 하트비트와 헬스 체크는 죽었는지 판정하는 데서 멈춥니다. 뒤처리는 다른 장치에 넘깁니다. 워치독은 판정과 되살리기를 한 몸에 담습니다.
관련 항목
워치독이 지켜보는 대상
임베디드 · 마이크로컨트롤러 · 펌웨어 · 프로세스 · 태스크
워치독을 이루는 부품과 동작
타이머 · 카운터 · 리셋 · 인터럽트 · 레지스터 · 타임아웃
워치독 리셋을 부르는 멈춤
데드락 · 무한 루프 · 우선순위 역전 · 라이브락 · 메모리 손상 · 소프트 에러
같은 목적을 다른 방법으로 이루는 감시 수단
하트비트 · 헬스 체크 · 데드맨 스위치 · KeepAlive · 폴링 · 라이브니스 프로브
워치독 리셋 뒤에 도는 절차
부트 루프 · 안전 모드 · 장애 감지 · 페일오버 · 자가 치유 · 크래시 덤프
워치독을 쓰는 시스템과 그 시스템이 지키려는 성질
다른 이름: watchdog · watchdog timer · 워치독 타이머 · 감시 타이머