Skip to content
isdnetworks
Go back

같은 데로 가는 폴백

(수정됨)

한 채널의 상품 연동 실패가 폴백 로직이 있는데도 계속 쌓이고 있었다. 실패 건수를 세려고 조회를 걸었는데 한참을 기다려도 끝나지 않았다.

Table of contents

Open Table of contents

조사 — 조회부터 막힌 실행 계획

EXPLAIN 을 보니 type: ALL 전수 스캔이었다. idx_supplier 가 있는데도 안 타고 있었고 last_error LIKE '%image%' 처럼 양쪽 와일드카드가 붙은 조건 때문에 옵티마이저가 그쪽을 포기한 것으로 보였다. MySQL 8.0 매뉴얼도 LIKE 인자가 와일드카드로 시작하지 않는 상수일 때만 인덱스를 쓴다고 적고 있다.

FORCE INDEX (idx_supplier) 로 지정하니 조회가 바로 끝났다. 규모를 보니 한 달 만에 수십 배로 늘어 누적 미완료가 수천 건을 넘고 있었다.

증상 — 두 시점의 같은 오류

실패 메시지를 묶어 보니 크게 두 패턴으로 갈렸다. 상대가 이미지 크기를 계산할 때와 이미지를 내려받아 등록할 때 각각 실패하고 있었다.

둘 다 같은 IMAGE_FETCH_FAILED 코드였고 시점만 달랐다. 상대 서버가 우리 이미지 주소에 접근할 때 실패하고 있다는 뜻이었고 우리가 직접 호출하면 정상이었으므로 상대 쪽에서 대량으로 접근할 때만 간헐적으로 나는 성격으로 보였다.

원인 — 같은 곳을 가리킨 폴백

원래 의문으로 돌아가서 ImageSender 의 폴백 코드를 열어 봤다. 우리 주소가 안 되면 상대 쪽에 이미 등록된 이미지를 쓰자는 발상이었고 그 자체는 합리적이다.

문제는 이미 등록된 이미지의 주소도 우리 CloudFront 도메인이라는 점이었다. 상대가 그것을 재검증할 때 똑같이 실패하므로 폴백이 실패 원인을 피해 가지 못하고 같은 곳으로 간다.

판단 기준 — 폴백의 조건

여기가 이 건의 핵심이었다. 폴백의 조건은 실패 원인을 피해 가는 것인데 원인이 우리 도메인에 상대가 접근하지 못하는 것이면 폴백도 그 도메인을 쓰는 한 원인을 안 피한다.

결과적으로 두 번 실패하면서 시간만 두 배로 쓰게 된다. 폴백이 없는 것과 같은 상태이면서 있는 것처럼 보이므로 더 나쁘다.

조치 — 재설계와 복구

폴백을 어떻게 바꿔야 하는지는 두 가지 방법이 있었다. 다른 도메인 주소로 변환해 보내는 것과 주소를 주는 대신 이미지 바이트를 multipart/form-data 로 직접 올리는 것이다.

뒤쪽을 골랐다. 이유는 상대가 우리 서버에 접근할 필요 자체를 없애서다. 대신 상품마다 이미지를 우리가 내려받아 올리므로 전송 시간과 트래픽이 늘어나는 것을 감수했다. 밀린 수천 건은 channel_jobs.attempts 를 0 으로 리셋하면 자동 재시도가 도므로 새로 넣을 필요가 없었다.

마지막으로 순서를 정했는데 이미지 서버 인프라 확인이 코드 수정보다 먼저다. 폴백을 고쳐도 원인이 우리 서버의 간헐 실패면 다른 소비자에게서 또 터지고 서버가 정상인지 모르면 리셋해도 또 실패하므로 우리 쪽에 원인이 있을 가능성을 먼저 닫아야 한다.

정리


Share this post on:

Previous Post
해소와 통과의 차이
Next Post
인증을 시행착오로 시험하지 않는다