감시 템플릿 하나를 검토하다가 같은 계열의 다른 템플릿에서 정반대 성격의 결함을 발견했다. 원래 고치려던 것은 알람이 조용히 멎는 문제였는데 그 수정이 반대편으로 넘어가 있었다.
Table of contents
Open Table of contents
변화 게이트와 침묵 버그
이 계열의 감시는 멤버 상태를 모아 오류 비율을 계산하고 마지막 정상 시각과 비교해 상태가 변했는지 판정한다. 같은 상태가 이어지면 알리지 않는 변화 게이트가 알림 피로를 막는 장치였다.
문제는 그 상태를 메모리에만 들고 있으면 프로세스가 재시작될 때 사라진다는 점이었다. 장애가 이어지는 중인데 기준 시각이 초기화되어 알람이 조용히 멎는다.
만료 없는 영속화가 만든 폭주
그래서 상태를 테이블에 저장하도록 고쳤고 재시작해도 기준 시각이 남게 됐다. 침묵은 사라졌지만 만료를 걸지 않은 것이 다음 문제를 만들었다.
전 멤버가 계속 오류인 상황에서는 비율이 최댓값에 고정되고 기준 시각이 영구히 보존되므로 게이트가 항상 참이 된다. 주기마다 알람이 발화해 나흘이면 천 건이 넘고 그만한 알림은 아무도 보지 않으므로 0건과 다르지 않다.
스스로 적어 둔 상한을 넘기는 비용
이 템플릿은 특정 비율 구간에서 판정용 외부 모델을 호출하는데 비율이 최댓값에 고정되면 매 주기 호출된다. 템플릿 주석에는 하루 스무 건 남짓을 가정한 월 비용 상한이 적혀 있었다.
실제로는 하루 수백 건이 되므로 이틀이면 그 상한을 넘는다. 자기 문서에 적어 둔 제한을 자기 동작이 깨는 구조였다.
옆 템플릿에는 있던 장치
같은 계열의 다른 템플릿을 열어 보니 한 번 알린 뒤 일정 시간 다시 알리지 않는 재알림 억제 창이 있었다. 같은 문제를 이미 막아 둔 것인데 이쪽으로는 이관되지 않았다.
더 나쁜 것은 그 템플릿의 주석이 이쪽 템플릿에는 억제가 필요 없고 변화 게이트와 비율이 자연히 제한한다고 주장하고 있었다는 점이다. 다른 파일에 대해 주장하는 주석은 읽는 사람이 확인된 사실로 받아들이게 만든다.
짝으로 도입해야 하는 장치들
그 주장을 그대로 믿지 않고 해당 코드를 직접 열어 기준 시각이 만료 없이 보존되므로 게이트가 항상 참임을 확인했다. 비용 수치도 기억이나 요약이 아니라 템플릿 원문의 해당 행을 열어 대조했다.
영속화만 넣으면 폭주하고 억제만 넣으면 재시작 시 침묵하므로 둘은 반드시 한 쌍으로 들어가야 한다. 재시도와 백오프나 캐시와 만료처럼 한쪽을 넣을 때 짝이 있는지 확인하는 것이 이 사례의 일반 규칙이었고 실제 배포 여부에 따라 실재 리스크인지 잠재 리스크인지가 갈리므로 그 확인을 결론에 함께 넣었다.
정리
- 만료 없는 상태 영속화는 침묵을 폭주로 바꾼다
- 알림 천 건은 0건과 같다
- 주기마다 붙는 외부 호출이 비용 상한을 깬다
- 다른 파일에 대해 주장하는 주석은 위험하다
- 주장은 그 코드를 직접 열어 확인한다
- 수치도 원문 행으로 교차 확인한다
- 배포 여부에 따라 실재와 잠재가 갈린다
- 영속화와 억제는 한 쌍으로 도입한다