장애 기록을 정리하다가 같은 원인이 네 번 있는 것을 발견했다. 주문 목록과 상품 검색과 정산 조회와 통계 조회가 각각 느려진 건이라 증상은 전부 달라 보였다.
Table of contents
Open Table of contents
원인 — 네 번의 같은 원인
원인을 나란히 놓고 보니 전부 인덱스 없이 대량 테이블을 조회한 것이었다. 매번 그 쿼리에 CREATE INDEX로 인덱스를 걸어 해결했고 네 번 다 그렇게 끝냈다.
왜 반복되는지를 보니 흐름이 같았다. 새 기능을 만들 때 인덱스를 안 걸고 개발 환경에는 자료가 적어 안 느리다가 운영에서 자료가 쌓이면 느려진다. 한 건씩 고치는 방식으로는 그 흐름이 없어지지 않았다.
조치 — 앞에서 막는 장치
두 가지 방법이 있었는데 코드 리뷰 체크리스트에 인덱스 항목을 넣는 것과 시험 환경에서 자동으로 걸리게 하는 것이다. 뒤쪽을 골랐다. 이유는 체크리스트는 사람이 빠뜨리면 그만이라서다. 대신 시험 환경에 운영 규모 자료를 유지하는 비용을 감수했다. 개발과 시험 환경에서 slow_query_log를 켜 long_query_time을 넘는 쿼리를 남기게 했는데 자료가 적어 안 걸리므로 시험 환경에 운영과 비슷한 양을 넣었다.
주문 100만 건 규모를 넣으니 느린 쿼리가 드러났다. 여기에 주요 조회의 EXPLAIN을 확인하는 시험을 더해 type: ALL이면 실패하게 하고 새 쿼리를 추가할 때 그 목록에 넣도록 했다.
대응 — 네 기록의 통합
흩어진 네 기록을 incidents.md 하나로 합치고 발생 시점과 원인과 대책을 한자리에 적었다. 마지막 줄에 대책 이후 recurred 재발 여부를 두고 계속 갱신했다.
재발 여부를 적어 두는 것이 대책의 성패를 재는 유일한 지표였다. 또 나면 대책이 부족한 것이므로 그 줄이 비어 있으면 아직 판정이 안 된 상태다.
판단 기준 — 모아 보기 위한 형식
같은 방식으로 다른 반복 결함도 찾으려니 형식이 걸렸다. 원인이 인덱스가 없어서라거나 인덱스 미설정이라거나 쿼리가 인덱스를 안 탄다고 제각각 적혀 있어서 같은 것인데 안 모였다.
cause를 목록에서 고르게 하고 detail은 따로 적게 바꿨다. 그러고 나서 모아 세니 인덱스 없는 대량 조회 넷과 외부 호출 시간 초과 미설정 셋과 설정 반영 안 됨 셋과 권한 확인 누락 둘이 나왔다. 한 건씩 보면 안 보이고 모아 보니 보였는데 그 전에는 형식이 달라 모을 생각조차 못 했다.
검증 — 대책이 도는지 확인
대책을 세우고 끝내지 않고 셋을 각각 확인했다. 시험 환경 자료는 넣었고 EXPLAIN 시험은 CI 빌드에서 돌고 있었다.
절차가 지켜지는지가 애매해서 새 조회가 추가된 커밋에 EXPLAIN 시험도 같이 추가됐는지를 git log -p로 셌다. 추가된 것이 있어서 지켜지고 있다고 판정했다. 절차를 적었다는 것과 절차가 돈다는 것은 다르므로 후자는 따로 재야 한다.
정리
- 같은 결함이 여러 번 기록됐다면 아직 안 고친 것이다
- 증상이 달라 보여도 원인이 같을 수 있다
- 한 건씩 고치면 원인이 안 없어진다
- 앞에서 막으려면 개발과 시험 환경을 운영과 비슷하게 만든다
EXPLAIN시험을 두고 새것을 추가할 때 같이 넣게 한다- 여러 기록을 합치고 대책과
recurred재발 여부를 적는다 - 모아 세려면
cause기록 형식이 같아야 한다 - 절차를 적었다는 것과 절차가 돈다는 것은 다르다