경력·사례·글은 한국어 원문으로 제공됩니다.

← 모든 에피소드

통합 인증 이후 · 회사 업무 · 정합성·멱등성

앱의 재시도가 서버를 두드린 일

앱의 로그인 재시도 버그를 서버와 앱 양쪽에서 고쳤다. 같은 데이터베이스를 쓰던 다른 서비스도 느려진 일을 돌아본다.

그때
앱의 로그인 반복으로 요청이 쌓였고, 공유 DB를 쓰는 다른 서비스까지 느려졌다.
지금
이후 나라별 DB를 나눠 적용했다. 나눈 뒤에도 공통으로 의존하는 곳은 함께 살펴야 한다.

사양을 올린 뒤에도 남아 있던 일

사용자가 몰리는 정해진 시점에 장애가 몇 차례 났다. 앱 화면은 로딩만 계속 돌았고, 어떤 사용자는 강제로 로그아웃됐다. 한 서비스의 특정 보상 기능을 쓰는 요청이 중심이었다. 같은 데이터베이스를 쓰는 다른 서비스도 함께 느려졌다.

급한 불은 데이터베이스 사양을 올려 껐다. 비슷한 조치를 몇 번 한 뒤 원인을 확인했다. 어뷰징이나 외부 공격도 의심했지만, 로그와 데이터베이스, 요청 패턴을 살펴보며 앱의 반복 동작으로 좁혀 갔다.

로그인 요청이 실패하면 앱이 곧바로 다시 로그인을 시도하고 있었다. 접근 토큰이 만료된 경우도 포함됐다. 서버가 아직 처리 중인데 같은 요청이 계속 들어왔다. 이때의 반복은 앱의 버그였다.

사양을 올리면 당장 처리할 여유는 늘릴 수 있다. 하지만 실패할수록 요청을 더 보내는 동작은 그대로 남는다. 그 동작을 고치지 않은 채 서버가 얼마나 더 버틸지를 보는 것으로는 끝낼 수 없었다.

서버와 앱을 함께 고쳐야 했다

서버는 요청을 오래 붙잡지 않고 빠르게 실패하도록 바꿨다. 앱에서는 재시도 간격을 늘리고 횟수를 제한했다. 서버를 먼저 적용했고 앱도 이어서 고쳤다. 반복되던 요청을 수정한 뒤 문제는 대부분 해결됐다.

빠른 실패(fail-fast)는 성공할 수 없는 요청을 오래 기다리게 두지 않고 실패를 알리는 방식이다. 요청 하나가 기다리는 동안에도 연결이나 메모리 같은 자원을 사용한다. 계속 붙잡고 있으면 다른 요청이 쓸 여유까지 줄어들 수 있다. 빨리 실패를 돌려주는 것은 그런 대기를 줄이려는 선택이다. 빠른 실패와 자원 사용

그런데 앱이 그 실패를 받자마자 다시 요청하면 어떻게 될까. 서버가 빨리 답할수록 앱도 더 빨리 다음 요청을 보낼 수 있다. 서버가 언제 실패할지와 앱이 언제 다시 시도할지를 함께 정해야 하는 이유다. 당시에는 간격과 횟수를 제한해 반복을 멈추게 했다.

타임아웃도 같은 맥락에서 봐야 한다. 타임아웃은 정해진 시간 안에 응답을 받지 못했을 때 기다리기를 끝내는 기준이다. 앱의 기다림이 끝났다고 서버의 작업까지 반드시 끝난 것은 아니다. 너무 짧게 잡으면 원래 끝날 수 있던 요청에도 재시도가 붙고, 너무 길면 사용자가 계속 기다리게 된다. 요청 시간 제한의 고려사항

다시 점검한다면 오류 종류도 나눠볼 만하다. 잠깐 연결이 끊긴 경우와, 입력이나 권한을 바꾸지 않으면 계속 실패할 경우를 똑같이 재시도할 필요는 없다. 서버가 돌려주는 실패의 뜻을 앱이 어떻게 받아들이는지까지 확인해야 한다. 재시도할 오류와 중단 조건

같은 데이터베이스에 묶여 있었다

요청을 반복한 앱만 문제가 된 것은 아니었다. 데이터베이스를 함께 쓰던 다른 서비스도 영향을 받았다. 함께 관리하면 개발과 운영은 편하지만, 한쪽에서 생긴 부하를 다른 쪽도 감당해야 했다.

이후 서비스에서는 로직을 공통으로 두더라도 나라별 데이터베이스는 따로 두고 인증은 통합하는 방식으로 설계했다. 나라별로 데이터베이스를 나누는 구조는 실제로 적용했다. 같은 기능을 다시 구현하는 일과 같은 실행 자원을 나눠 쓰는 일은 별개로 볼 수 있었다.

이런 분리의 목적을 설명할 때 벌크헤드(bulkhead)라는 설계 방법을 참고할 수 있다. 한쪽의 과부하가 다른 쪽 자원까지 소모하지 않도록 구획을 나누는 방법이다. 예를 들어 두 서비스가 같은 연결 자원을 쓰면 한쪽의 대기가 다른 쪽을 막을 수 있다. 사용할 자원을 나누면 영향을 가둘 여지가 생긴다. 다만 어디까지 분리했는지에 따라 효과도 달라진다. 자원 분리와 운영 부담

데이터베이스를 따로 뒀다고 모든 장애가 분리되지는 않는다. 인증이나 다른 공통 서비스에 함께 의존한다면 그곳의 문제는 다시 여러 서비스에 영향을 줄 수 있다. 나눈 만큼 각각의 설정과 상태를 살펴야 하는 부담도 생긴다. 이 부분은 분리의 일반적인 한계다. 당시 나눈 뒤 장애가 얼마나 줄었는지나 관리 비용이 얼마나 늘었는지를 수치로 비교한 기록은 없다.

큐에 넣는 것까지는 하지 않았다

그때 큐를 넣는 방법도 생각했다. 다만 변경 위험이 있고 일이 커질 것 같아 보류했다. 당시 해결한 내용에 큐 도입까지 포함할 수는 없다.

큐는 들어온 일을 잠시 담아 두고 뒤에서 처리하도록 나누는 방법이다. 한꺼번에 온 일을 순차적으로 처리하는 데 쓸 수 있지만, 처리하는 속도보다 들어오는 속도가 계속 빠르면 대기열이 쌓인다. 또 큐에 담았다는 응답과 처리가 끝났다는 응답은 다르다. 특히 로그인처럼 다음 동작을 위해 결과를 기다리는 일이라면, 큐를 쓴다는 것만으로 사용자 대기가 사라지지 않는다. 큐를 둘 때 남는 대기 문제

이 일을 돌아보면 사양 상향, 반복 요청 수정, 데이터베이스 분리는 각각 다른 일을 했다. 당장 처리할 여유를 늘렸고, 계속 요청을 만드는 원인을 고쳤고, 이후에는 함께 영향을 받는 범위를 줄이려 했다. 서버와 앱의 반복을 고친 것만큼, 관련 없는 서비스까지 같이 느려졌다는 사실도 다음 설계에 남았다.

다시 만난 문제

이 글의 연결

푸시 직후 접속 폭주와 직접 만든 인증푸시 직후 접속 폭주와 …중복 요청을 처리할 때, 무엇을 보존할 것인가중복 요청을 처리할 때,…

댓글

댓글은 GitHub 토론을 사용하며, 열면 GitHub 로그인이 필요합니다. 고객·사람이 드러나는 정보는 남기지 말아 주세요.

작성 2026-10-05 · 수정 2026-10-06

기억에 의존한 회고이며 당시 문서로 확인하지 못했다.