Skip to content
isdnetworks
Go back

깨진 것이 아닌 410

(수정됨)

리포트 서빙을 정리하려고 routes/api.php 의 엔드포인트를 전수로 훑다가 두 개가 abort(410) 을 돌려주고 있는 것을 발견했다. 처음에는 미구현이거나 실수로 막아 놓은 것으로 보고 되살리면 되겠다고 생각했다.

Table of contents

Open Table of contents

조사 — 커밋이 말한 의도

되살리기 전에 언제 이렇게 됐는지를 git log -S'abort(410)' 로 찾았다. 그 상태 코드를 넣은 커밋 하나가 나왔고 메시지가 리포트 서빙 경량화였다.

의도적으로 폐기한 것이었다. 그 커밋의 설명과 관련 기록을 보니 두 엔드포인트의 실측 최대 메모리가 각각 기가바이트 단위였고 ECS 태스크의 memory 할당량은 그 몇 분의 일이었다.

주의 — 되살렸을 때의 결과

동시 요청이 아니라 단독 호출 하나만으로도 메모리가 초과되는 상태였다. 깨진 엔드포인트로 보고 되살렸으면 배포 후 누가 한 번 부르는 순간 서빙이 죽는다.

그것도 그 엔드포인트만이 아니라 같은 php-fpm 프로세스의 모든 요청이 죽는데 memory_limit 초과는 프로세스 단위이기 때문이다. 안 되는 것을 고쳤다는 행위가 그대로 장애가 되는 구조였다.

원인 — 유입을 막는 역할

그 응답이 다른 일도 하고 있었다. 캐시된 옛 페이지와 북마크와 감시 스크립트가 여전히 그 주소를 부르는데 그것을 싸게 막아 주고 있었다.

두 가지 방법이 있었는데 라우트를 아예 지워 404 가 나게 두는 것과 abort(410) 을 그대로 두는 것이다. 뒤쪽을 골랐다. 이유는 RFC 9110 이 410 을 자원이 영구히 사라졌다는 뜻으로 정의하고 영구 여부를 모를 때만 404 를 쓰라고 해서다. 대신 죽은 라우트 두 줄이 코드에 계속 남는 것을 감수했다. 라우트를 없애면 유입이 다른 데로 흘러 로그를 더럽히거나 프록시 설정에 따라 다른 핸들러로 갈 수 있다.

폐기가 아니라 이전

그러면 그 기능은 어떻게 되는지도 확인했다. 전체 월을 일괄로 반환하던 것은 프런트가 단건 조회와 인덱스만 쓰므로 필요가 없었다.

당월 재집계는 일배치가 미리 만들어 S3 에 올리고 있어서 요청 시점에 계산할 이유가 없었다. 기능 손실이 없었고 폐기가 아니라 이전이었다. 살아 있는 경로를 route:list 로 전부 열거하니 몇 개 안 됐고 폐기된 것을 빼고 나서야 이 서비스가 얼마나 단순한지가 보였다.

죽은 코드의 선별

폐기의 잔해도 확인했다. 폐기된 엔드포인트가 쓰던 $reportCache 와 Cache::lock() 과 storeReport() 가 선언만 남아 있었고 grep -rn 으로 검색해도 선언 줄만 나왔다.

반면 REPORT_KEY 상수는 네 곳에서 쓰이고 있어서 못 지운다. 폐기했으니 관련된 것도 다 죽었겠거니 하고 뭉뚱그려 지우면 안 되고 하나씩 사용처를 확인해야 한다.

정리


Share this post on:

Previous Post
자리마다 따로 한 열거
Next Post
화면으로 못 푸는 상태 가드