Skip to content
isdnetworks
Go back

없는 것을 만들어 내던 조회

(수정됨)

파일이 있는지 확인하는 코드가 항상 있다고 답하고 있었다. 없는 경로를 넣어도 참이 나왔다.

Table of contents

Open Table of contents

원인 — 확인이 만들어 낸 것

확인 로직은 해당 경로를 HEAD로 요청해서 200이 오면 있는 것으로 보고 있었다. 상대 서비스를 보니 없는 경로를 요청하면 원본에서 즉석으로 만들어 저장한 뒤 200으로 돌려주는 구조였다.

없어도 200이 오고 그 HEAD 요청 때문에 실제로 생겼다. 확인하는 행위 자체가 대상을 만들고 있었으므로 그 확인은 아무것도 확인하지 못했다.

증상 — 비용과 잘못된 결론

문제의 크기가 둘이었다. 확인만 하려던 4만여 건의 썸네일이 전부 생성되면서 저장 용량이 늘고 생성 비용이 나갔다.

더 나쁜 것은 이미 있다는 결과가 나오면서 정작 만들어야 할 것을 안 만들었다는 점이다. 확인이 자기가 찾던 것을 만들어 놓고 있다고 답하는 순환이었다.

조치 — 다른 경로로 하는 확인

두 가지 방법이 있었는데 상대가 제공하는 생성 건너뛰기 헤더를 붙여 요청하는 것과 S3 HeadObject로 저장소를 직접 보는 것이다. 앞쪽을 골랐다. 이유는 저장소 직접 조회는 상대 버킷 권한을 받아야 해서다. 대신 상대가 그 헤더를 없애면 다시 생성 경로로 돌아가는 위험을 감수했고 그래서 HeadObject 경로도 준비해 뒀다.

핵심은 생성 로직을 안 거치는 경로로 확인한다는 것이다. 같은 대상을 보더라도 어느 길로 보느냐에 따라 확인이 되기도 하고 생성이 되기도 한다.

검증 — 부작용 있는 조회의 전수

같은 성격의 것이 더 있는지 찾았다. 조회인데 상태를 바꾸는 것이 셋이었다.

썸네일 경로는 없으면 만들고 세션 확인은 호출하면 TTL이 연장되며 토큰 확인은 use_count를 센다. 두 번째가 특히 나빴는데 세션 만료를 확인하려고 부르면 만료가 미뤄져서 영영 만료되지 않는다.

우리 API에도 같은 것이 있었다. GET /orders/{id}가 view_count를 올리고 있어서 확인하려고 부르면 숫자가 변했고 조회와 POST /orders/{id}/views 두 엔드포인트로 나눴다. 상대 쪽에는 확인용 엔드포인트를 요청했는데 하나는 생겼고 둘은 안 돼서 우리 쪽에서 다른 경로를 찾았다.

대응 — 부작용 명시와 사후 정리

전부 나눌 수는 없어서 남는 것은 문서에 적었다. 부작용이 있으면 무엇인지와 확인 목적일 때 어떻게 부르는지를 적고 없으면 없다고 적었다. 없다고 적혀 있어야 안심하고 부를 수 있으므로 없다는 기록도 정보다.

확인 배치 때문에 만들어진 4만여 건도 정리했다. S3 액세스 로그로 보니 90일 안에 조회된 것이 열에 하나꼴이었고 지우기 전에 원본이 있어 다시 만들 수 있는지 확인했다. 원본이 없어진 십여 건만 남기고 나머지는 지운 뒤 Expiration 수명 주기 규칙을 걸었다.

정리


Share this post on:

Previous Post
변환본 둘, 규칙 둘
Next Post
게이트만으로 안 되는 결정