Skip to content
isdnetworks
Go back

이미지 하나에 서빙 경로 셋

(수정됨)

새 등록 경로로 만든 상품의 본문을 보다가 이미지 주소가 S3 경로가 아니라 img. 도메인이라는 지적을 받았다. ImageService 를 열어 store() 와 url() 을 각각 나눠서 확인했다.

Table of contents

Open Table of contents

배경 — 저장과 응답의 불일치

store() 는 S3 에 변환 결과를 직접 경로로 넣고 있었다. 그런데 url() 은 그 경로가 아니라 img. 프록시 도메인 형태의 주소를 돌려주고 있었다.

저장하는 경로와 응답으로 나가는 주소가 서로 다른 구조였다. 그 프록시가 무엇을 하는지 확인하니 302 가 아니라 요청마다 원본을 가져와 즉석에서 변환해 스트리밍하고 있었고 Cache-Control 도 없었다.

검증 — 바이트가 알려 준 별도 경로

두 주소로 각각 curl -sI 로 받아 Content-Length 를 비교하니 같은 이름인데도 크기가 달랐다. 저장된 것과 즉석에서 변환한 것이 서로 다른 결과를 내고 있다는 뜻이다.

즉 같은 이름을 쓰지만 실제로는 별도 변환 경로였다. 전체를 정리하니 대표와 부가 이미지는 저장소 직접이고 옛 본문도 직접인데 신규 본문만 프록시였다.

원인 — 본문에 고정되는 주소

여기가 문제의 핵심인데 본문은 product_contents.html 에 텍스트로 저장되므로 <img src> 가 등록 시점에 텍스트로 박힌다. 나중에 서빙 방식을 바꿔도 이미 등록된 본문은 그대로 남는다.

신규 본문이 쌓일수록 전부 프록시 주소가 박히고 모든 상세 조회가 영구히 그 서비스에 의존하게 된다. 그 서비스가 죽거나 외부 마켓이 그 도메인을 차단하면 상세 이미지가 전부 깨지고 이미 박힌 주소는 되돌릴 수 없다.

주의 — 캐시 없는 즉석 변환

즉석 변환에 Cache-Control 까지 없으면 상세 페이지를 한 번 열 때마다 이미지 수만큼 변환이 일어난다. S3 직접이면 CloudFront 가 캐시하는데 프록시면 매번 서비스를 친다.

부하와 지연이 완전히 다른 구조가 되는 것이다. 조회가 늘수록 그 차이가 그대로 비용이 된다.

조치 — 대안을 만든 확인

S3 에 객체가 실제로 존재하는지를 HEAD 로 확인하니 직접 주소로도 200 이 왔다. 두 가지 방법이 있었는데 프록시에 Cache-Control 을 붙여 유지하는 것과 본문에 S3 직접 주소를 넣는 것이다. 뒤쪽을 골랐다. 이유는 본문에 박히는 주소는 되돌릴 수 없으므로 의존을 처음부터 안 만드는 편이 나아서다. 대신 이미 박힌 신규 본문의 주소를 치환하는 배치를 한 번 돌려야 하는 것을 감수했다.

변환이 이미 돼 있는 상태이므로 요청마다 즉석 변환을 할 이유가 없다. 저장소 객체가 없었으면 프록시가 필수였을 것이므로 그 확인 하나가 선택지를 만들었다.

정리


Share this post on:

Previous Post
목록에 섞여 있던 내부 API
Next Post
깨끗한 것과 최신인 것