Q.커넥션 풀 크기를 어떤 기준으로 정하나요?
DB 가 동시에 처리할 수 있는 양에서 거꾸로 잡습니다. 크게 잡으면 빨라지는 것이 아닙니다.
| 요소 | 내용 |
|---|
| DB 코어 수 | 실제 병렬 처리 능력의 상한 |
| 쿼리 시간 | 짧으면 적은 커넥션으로 많은 요청을 처리한다 |
| 전체 인스턴스 수 | 서버 10대 × 풀 20 = DB 커넥션 200 |
| DB 최대 커넥션 | 이것을 넘으면 접속 자체가 실패한다 |
계산의 출발점은 필요 커넥션 = 목표 처리량 × 평균 쿼리 시간입니다. 초당 500건에 쿼리가 20밀리초면 10개면 됩니다.
크게 잡으면 나빠지는 이유가 있습니다. 커넥션이 늘면 DB 안에서 경합이 생겨 개별 쿼리가 느려지고, 결과적으로 처리량이 떨어집니다. 그래서 코어 수의 두 배에서 네 배 정도가 실용적인 상한입니다.
| 주의 | 내용 |
|---|
| 인스턴스 수를 곱해서 본다 | 오토스케일링이면 최대 대수로 계산한다 |
| 대기 시간에 상한을 둔다 | 무한정 기다리면 장애가 전파된다 |
| 트랜잭션 밖에서 외부 호출을 하지 않는다 | 커넥션을 쥔 채 기다리면 풀이 마른다 |
흔한 실수: 요청이 밀리니 풀을 늘리는 것. 원인이 느린 쿼리면 풀을 늘려도 DB 대기만 길어집니다. 쿼리를 고치는 것이 먼저입니다.
Q.커넥션 풀이 고갈되면 어떤 증상이 나타나나요?
| 증상 | 내용 |
|---|
| 응답 지연 급증 | 쿼리는 빠른데 풀에서 기다린다 |
| 타임아웃 오류 | 대기 시간 초과 예외가 몰린다 |
| 자원은 한가하다 | CPU 와 메모리는 여유인데 느리다 |
| 특정 API 만 정상 | DB 를 쓰지 않는 경로는 멀쩡하다 |
| 전파 | 그 서비스를 부르는 다른 서비스도 함께 느려진다 |
세 번째가 판별 지점입니다. 자원이 한가한데 느리면 어딘가에서 기다리는 것이고, 커넥션 풀이 첫 번째 후보입니다.
원인은 대개 셋 중 하나입니다.
| 원인 | 확인 |
|---|
| 쿼리가 느려졌다 | 쿼리 시간이 길어져 커넥션 회전이 느려진다 |
| 커넥션을 반납하지 않는다 | 예외 경로에서 닫지 않거나, 트랜잭션이 길다 |
| 트래픽이 늘었다 | 처리량 대비 풀이 작다 |
두 번째가 가장 위험합니다. 조금씩 새면 며칠 뒤에 갑자기 고갈되고, 재시작하면 잠시 정상으로 보여 원인을 놓칩니다.
흔한 실수: 풀 대기 시간을 지표로 남기지 않는 것. 남기지 않으면 이 증상을 "DB 가 느리다"로 오진하게 됩니다.
Q.외부 API 호출에 어떤 타임아웃을 설정하나요?
세 층을 따로 정해야 합니다. 하나만 걸면 나머지에서 무한정 기다립니다.
| 타임아웃 | 대상 | 기준 |
|---|
| 연결 | TCP 연결 수립 | 짧게. 수백 밀리초에서 1초 |
| 읽기 | 응답 대기 | 상대의 p99 를 기준으로 |
| 전체 | 재시도까지 포함한 총 시간 | 우리 API 의 응답 목표 안에 들어와야 한다 |
가장 중요한 것이 세 번째입니다. 우리 API 가 3초 안에 응답해야 하는데 외부 호출에 5초 타임아웃을 걸면 이미 약속을 못 지킵니다. 상위 목표에서 거꾸로 나눠야 합니다.
| 함께 갈 것 | 이유 |
|---|
| 차단기 | 상대가 죽었을 때 계속 기다리지 않고 즉시 실패한다 |
| 대체 동작 | 캐시된 값이나 축소된 응답을 준다 |
| 격리 | 외부 호출용 스레드나 커넥션을 따로 둔다 |
격리가 장애 전파를 막습니다. 외부 호출이 느려질 때 같은 풀을 쓰면 무관한 요청까지 함께 막힙니다.
흔한 실수: 기본값에 맡기는 것. 많은 HTTP 클라이언트가 읽기 타임아웃 기본값이 없거나 매우 깁니다. 상대가 응답을 안 주면 우리 스레드가 그만큼 잡혀 있습니다.
Q.재시도를 넣을 때 주의할 점은 무엇인가요?
재시도는 상대가 이미 힘들 때 부하를 더 얹는 행위입니다. 조건을 좁게 걸어야 합니다.
| 주의 | 내용 |
|---|
| 안전한 요청만 | 같은 요청을 두 번 해도 결과가 같아야 한다. 결제 생성은 그렇지 않다 |
| 재시도할 오류를 구분 | 연결 실패나 5xx 는 재시도, 4xx 는 하지 않는다 |
| 간격을 늘린다 | 즉시 재시도를 반복하면 상대를 밀어붙인다 |
| 편차를 더한다 | 여러 클라이언트가 같은 시점에 몰리는 것을 막는다 |
| 횟수에 상한 | 2회에서 3회. 그 이상은 대개 무의미하다 |
| 차단기와 함께 | 실패가 지속되면 재시도 자체를 멈춘다 |
| 계층을 겹치지 않는다 | 각 층이 3회씩 하면 최종 27회가 된다 |
마지막이 실제 장애를 키우는 자리입니다. 클라이언트, 게이트웨이, 서비스가 각자 재시도하면 원래 요청 하나가 수십 개가 되어 상대를 완전히 무너뜨립니다.
첫 번째는 요청에 고유 키를 붙여 서버가 중복을 걸러내게 만들면 해결됩니다. 그러면 안전하지 않은 요청도 재시도할 수 있습니다.
흔한 실수: 타임아웃 후 재시도하면서 전체 시간 예산을 늘리지 않는 것. 5초 타임아웃 3회면 최악의 경우 15초이고, 그 시간 동안 우리 스레드와 커넥션이 잡혀 있습니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
성능 최적화 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.