<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>HTTP Client on jyukki's Blog</title><link>https://jyukki.com/tags/http-client/</link><description>Recent content in HTTP Client on jyukki's Blog</description><generator>Hugo -- 0.147.0</generator><language>ko-kr</language><lastBuildDate>Mon, 20 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jyukki.com/tags/http-client/index.xml" rel="self" type="application/rss+xml"/><item><title>백엔드 커리큘럼 심화: 커넥션 풀 사이징과 포화 해석 플레이북</title><link>https://jyukki.com/learning/deep-dive/deep-dive-connection-pool-sizing-saturation-playbook/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0000</pubDate><guid>https://jyukki.com/learning/deep-dive/deep-dive-connection-pool-sizing-saturation-playbook/</guid><description>DB 풀과 HTTP 클라이언트 풀을 감으로 늘리다 장애를 키우지 않도록, 커넥션 풀 사이징과 포화 해석 기준을 숫자 중심으로 정리합니다.</description><content:encoded><![CDATA[<p>서비스가 느려질 때 많은 팀이 제일 먼저 하는 일은 커넥션 풀 최대값을 올리는 것입니다. HikariCP의 <code>maximumPoolSize</code>를 30에서 80으로 올리고, HTTP 클라이언트 풀도 같이 키웁니다. 처음 몇 분은 나아진 것처럼 보일 수 있습니다. 대기열이 잠깐 줄고, 몇몇 요청은 더 빨리 풀을 얻기 때문입니다. 그런데 조금만 지나면 DB CPU가 오르고 락 대기가 길어지고, 느린 쿼리가 더 오래 시스템 안에 머물면서 오히려 p95, p99가 악화되는 경우가 많습니다.</p>
<p>실무에서 커넥션 풀은 &ldquo;많을수록 좋은 버퍼&quot;가 아니라 <strong>DB와 애플리케이션이 동시에 감당할 수 있는 동시성 예산을 나누는 장치</strong>에 가깝습니다. 스레드 풀, 큐 길이, 타임아웃, 재시도 정책이 그대로인데 커넥션 풀만 키우면 병목을 없애는 것이 아니라 병목 위치를 뒤로 미루는 것에 그칠 수 있습니다. 그래서 풀 튜닝은 <a href="/learning/deep-dive/deep-dive-capacity-planning-littles-law-saturation/">용량 계획과 Little&rsquo;s Law 기반 포화도 해석</a>, <a href="/learning/deep-dive/deep-dive-thread-pool/">Thread Pool 튜닝</a>, <a href="/learning/deep-dive/deep-dive-timeout-retry-backoff/">Timeout/Retry/Backoff 설계</a>, <a href="/learning/deep-dive/deep-dive-connection-storm-thundering-herd-playbook/">Connection Storm과 Thundering Herd 플레이북</a>과 같이 봐야 정확합니다.</p>
<p>이 글은 &ldquo;풀 크기를 몇으로 할까&quot;라는 질문에 하나의 정답 숫자를 주려는 글이 아닙니다. 대신 어떤 조건에서 풀을 키워야 하고, 어떤 조건에서는 오히려 줄이거나 대기시간 제한을 먼저 걸어야 하는지, 그리고 DB 풀과 HTTP 클라이언트 풀이 어떻게 서로 영향을 주는지까지 실무 기준으로 정리합니다.</p>
<h2 id="이-글에서-얻는-것">이 글에서 얻는 것</h2>
<ul>
<li>DB 커넥션 풀과 HTTP 클라이언트 풀을 단일 숫자가 아니라 <strong>전체 요청 경로의 동시성 예산</strong>으로 해석하는 기준을 잡을 수 있습니다.</li>
<li><code>pool wait time</code>, <code>in_use</code>, <code>pending</code>, <code>timeout</code>, DB active session 같은 지표를 보고 지금이 &ldquo;풀 부족&quot;인지 &ldquo;하류 병목&quot;인지 구분할 수 있습니다.</li>
<li>커넥션 풀을 늘리기 전에 무엇을 먼저 확인해야 하는지 우선순위를 정할 수 있습니다.</li>
<li>장애 시 임시 완화와 구조 개선을 구분하는 런북 초안을 가져갈 수 있습니다.</li>
</ul>
<h2 id="핵심-개념이슈">핵심 개념/이슈</h2>
<h3 id="1-커넥션-풀은-성능-옵션이-아니라-동시성-상한선이다">1) 커넥션 풀은 성능 옵션이 아니라 동시성 상한선이다</h3>
<p>풀은 놀고 있는 연결을 재사용해 연결 생성 비용을 줄이는 기능이기도 하지만, 운영에서는 더 중요한 역할이 하나 있습니다. 바로 <strong>동시에 하류 자원을 때릴 수 있는 요청 수를 제한하는 상한선</strong>입니다. DB가 안정적으로 처리할 수 있는 active query 수가 40인데, 애플리케이션 4대가 각각 50개씩 DB 커넥션을 열 수 있으면 최악의 순간에는 200개의 활성 쿼리가 쏟아질 수 있습니다. 이때 문제는 연결 생성 비용이 아니라 DB 스케줄러, 락, 버퍼 캐시, I/O 대기가 한꺼번에 흔들리는 것입니다.</p>
<p>그래서 풀 크기는 보통 &ldquo;애플리케이션 하나가 바쁠 때 편한 숫자&quot;가 아니라 아래 질문으로 정해야 합니다.</p>
<ul>
<li>DB 또는 외부 API가 안정적으로 감당 가능한 동시 실행 수는 얼마인가</li>
<li>애플리케이션 인스턴스 수가 늘어날 때 총합 동시성이 얼마가 되는가</li>
<li>풀을 다 못 얻은 요청은 어디에서 얼마나 기다리게 할 것인가</li>
<li>기다리는 동안 상위 타임아웃과 재시도가 어떻게 반응하는가</li>
</ul>
<p>핵심은 커넥션 풀이 부족해서 느린 경우와, <strong>하류가 이미 느린데 풀이 그 사실을 숨기고 있는 경우</strong>를 구분하는 것입니다. 후자의 경우 풀을 키우면 체감은 잠깐 나아져도 전체 장애는 더 커질 가능성이 큽니다.</p>
<h3 id="2-db-풀-http-풀-워커-수는-따로-보면-안-된다">2) DB 풀, HTTP 풀, 워커 수는 따로 보면 안 된다</h3>
<p>실무에서 자주 놓치는 점이 하나 있습니다. 요청 하나가 DB만 쓰는 것이 아니라는 점입니다. 예를 들어 주문 API 하나가 아래처럼 흘러간다고 해 봅시다.</p>
<ol>
<li>애플리케이션 워커 1개 점유</li>
<li>DB 커넥션 1개 사용</li>
<li>외부 결제 API 호출을 위한 HTTP 커넥션 1개 사용</li>
<li>후속 이벤트 발행 또는 캐시 갱신</li>
</ol>
<p>이 구조에서 워커는 200개인데 DB 풀은 80, HTTP 풀은 20이라면 병목은 HTTP 클라이언트에서 먼저 날 수 있습니다. 반대로 HTTP 풀은 넉넉하지만 DB 락 경합이 심하면 DB 풀이 오래 잡혀 워커가 순식간에 묶입니다. 그래서 커넥션 풀 튜닝은 <strong>단일 계층 최적화가 아니라 체인 균형 맞추기</strong>입니다.</p>
<p>실무 기본 원칙은 아래처럼 잡는 편이 안전합니다.</p>
<ul>
<li>워커 수가 DB 풀의 여러 배라면, 풀 대기시간과 요청 큐 길이를 반드시 같이 봅니다.</li>
<li>한 요청이 평균적으로 DB 1회, 외부 API 2회를 호출한다면 HTTP 풀의 상한이 실제 처리량을 먼저 결정할 수 있습니다.</li>
<li>DB 풀과 HTTP 풀을 동시에 늘릴 때는 상류 워커 또는 ingress 제한도 같이 봐야 합니다.</li>
<li>풀 확장보다 먼저 <a href="/learning/deep-dive/deep-dive-admission-control-concurrency-limits/">Admission Control과 동시성 제한</a>이 필요한 경우가 많습니다.</li>
</ul>
<p>즉, &ldquo;DB 풀만 20 늘리자&quot;는 결정은 대개 너무 좁습니다. 최소한 워커, DB, HTTP, 큐, 재시도까지 한 묶음으로 봐야 실제 효과를 예측할 수 있습니다.</p>
<h3 id="3-풀을-크게-잡을수록-좋은-것이-아니라-느린-작업을-더-오래-붙들-수도-있다">3) 풀을 크게 잡을수록 좋은 것이 아니라, 느린 작업을 더 오래 붙들 수도 있다</h3>
<p>커넥션 풀 확대가 위험한 이유는 풀 자체가 느려서가 아니라 <strong>느린 작업을 더 많이 동시에 허용</strong>하기 때문입니다. 예를 들어 평균 30ms이던 쿼리가 락 대기와 I/O 병목 때문에 200ms로 늘어나면, 같은 처리량을 내려면 더 많은 active connection이 필요해집니다. 이때 풀을 늘리면 당장의 pending은 줄 수 있습니다. 하지만 DB 입장에서는 동시에 더 많은 느린 작업을 처리해야 하므로 컨텍스트 스위치, 락 대기, shared buffer miss, WAL flush 압력이 올라갈 수 있습니다.</p>
<p>그래서 풀 확대는 아래 조건을 모두 확인한 뒤에 하는 편이 맞습니다.</p>
<ul>
<li>DB CPU가 아직 <strong>60~70% 이하</strong>로 여유가 있다.</li>
<li>주요 쿼리의 p95 실행시간이 최근 1주 기준에서 크게 악화되지 않았다.</li>
<li>락 대기나 row lock contention이 주요 원인이 아니다.</li>
<li>풀 대기시간이 길지만 DB active session은 상대적으로 낮다.</li>
<li>애플리케이션의 timeout이 풀 대기보다 먼저 터지지 않는다.</li>
</ul>
<p>반대로 아래 상황이면 풀 확대보다 다른 조치가 먼저입니다.</p>
<ul>
<li>DB CPU <strong>75~80% 이상</strong>이 지속되고 있다.</li>
<li><code>pg_stat_activity</code>의 active session과 lock wait가 동시에 높다.</li>
<li>풀 획득 대기와 함께 쿼리 실행시간 p95가 같이 오른다.</li>
<li>재시도 비율이 <strong>5~10% 이상</strong>으로 올라가 있다.</li>
<li>상류 서비스 타임아웃이 짧아 대기 요청이 retry storm으로 번진다.</li>
</ul>
<p>이 구간에서는 <a href="/learning/deep-dive/deep-dive-tail-latency-engineering-playbook/">Tail Latency 엔지니어링 플레이북</a>과 <a href="/learning/deep-dive/deep-dive-timeout-retry-backoff/">Timeout/Retry/Backoff 설계</a>를 먼저 손보는 편이 훨씬 효과적입니다.</p>
<h3 id="4-사이징-출발점은-트래픽-평균이-아니라-목표-처리량과-체류시간이다">4) 사이징 출발점은 트래픽 평균이 아니라 목표 처리량과 체류시간이다</h3>
<p>풀 크기를 추정할 때는 감보다 간단한 계산이 낫습니다. 가장 실전적인 출발점은 Little&rsquo;s Law 식으로 보는 것입니다.</p>
<ul>
<li>필요 동시성 ≈ 처리량(RPS) × 평균 체류시간(초)</li>
</ul>
<p>예를 들어 특정 API가 초당 120건을 처리하고, DB를 잡고 있는 시간이 평균 40ms라면 평균 동시성은 <code>120 × 0.04 = 4.8</code> 정도입니다. 하지만 평균만 믿으면 안 됩니다. p95에서 120ms, 피크 시간대 2배 트래픽이 온다면 실제 필요 동시성은 훨씬 커집니다. 그래서 운영에서는 대개 아래 순서로 계산합니다.</p>
<ol>
<li>평시 RPS, 피크 RPS, 이벤트 시 RPS를 분리</li>
<li>DB 점유시간 평균과 p95를 분리</li>
<li>쿼리 수가 API별로 다른 경우 상위 20% API를 따로 계산</li>
<li>계산값에 안전 여유 **20~30%**만 더하고, 나머지는 큐와 admission control로 처리</li>
</ol>
<p>예시를 들어보겠습니다.</p>
<ul>
<li>피크 RPS: 180</li>
<li>요청당 평균 DB 점유시간: 35ms</li>
<li>p95 DB 점유시간: 90ms</li>
<li>애플리케이션 인스턴스: 3대</li>
</ul>
<p>평균 기준 총 동시성은 <code>180 × 0.035 = 6.3</code>입니다. p95 기준으로는 <code>180 × 0.09 = 16.2</code>입니다. 여유를 25% 넣으면 총 DB 풀 상한은 대략 20 전후에서 출발할 수 있습니다. 이를 3대로 나누면 인스턴스당 6~8 수준부터 시작해 실제 wait time을 보고 조정할 수 있습니다. 여기서 핵심은 <strong>대개 처음부터 40, 50을 줄 필요가 없다는 점</strong>입니다. 오히려 낮게 시작하고 지표로 올리는 편이 안전합니다.</p>
<h3 id="5-진짜로-봐야-하는-지표는-풀-크기가-아니라-기다림의-질이다">5) 진짜로 봐야 하는 지표는 &ldquo;풀 크기&quot;가 아니라 &ldquo;기다림의 질&quot;이다</h3>
<p>운영 대시보드에서 <code>maxPoolSize=30</code>, <code>active=30</code>만 보고 &ldquo;풀이 꽉 찼네&quot;라고 말하면 절반만 본 것입니다. 진짜로 중요한 것은 아래 조합입니다.</p>
<ul>
<li><code>pool_acquire_p95/p99</code>: 커넥션을 얻기까지 기다린 시간</li>
<li><code>pending_threads</code> 또는 <code>pending_acquires</code>: 풀을 기다리는 요청 수</li>
<li><code>in_use / max</code> 비율: 현재 점유율</li>
<li>DB active session, lock wait, slow query 비율</li>
<li>애플리케이션 전체 latency p95/p99와 timeout 비율</li>
<li>재시도율, 큐 길이, 워커 사용률</li>
</ul>
<p>권장 해석 기준은 아래처럼 잡을 수 있습니다.</p>
<ul>
<li><code>pool_acquire_p95</code>가 <strong>10ms 이하</strong>면 대체로 양호</li>
<li><code>pool_acquire_p95</code>가 <strong>20~50ms</strong>로 오르기 시작하면 피크 패턴과 함께 관찰</li>
<li><code>pool_acquire_p99</code>가 <strong>100ms 이상</strong>이면서 API latency도 같이 오르면 병목 조사 시작</li>
<li>pending이 <strong>지속적으로 0이 아닌 상태가 5분 이상</strong> 이어지면 일시적 스파이크인지 구조 병목인지 분리</li>
<li>DB active session이 낮은데 acquire latency만 높다면 애플리케이션 풀 설정 또는 커넥션 누수 의심</li>
<li>DB active session과 lock wait가 함께 높다면 하류 병목이므로 풀 확대는 보수적으로</li>
</ul>
<p>즉, 풀은 숫자 하나로 보는 것이 아니라 <strong>대기시간이 어디서 생기는지</strong>를 읽는 센서로 써야 합니다.</p>
<h3 id="6-장애에서-자주-보이는-패턴은-커넥션-부족보다-커넥션-체류시간-증가다">6) 장애에서 자주 보이는 패턴은 &ldquo;커넥션 부족&quot;보다 &ldquo;커넥션 체류시간 증가&quot;다</h3>
<p>현장에서 더 흔한 문제는 풀 크기가 원래 너무 작았던 경우보다, 평소에는 맞던 풀이 특정 상황에서 갑자기 오래 점유되는 경우입니다.</p>
<p>대표 패턴은 이렇습니다.</p>
<ul>
<li>느린 쿼리 또는 인덱스 미스 때문에 DB 점유시간 증가</li>
<li>긴 트랜잭션이 커넥션을 오래 보유</li>
<li>외부 API 타임아웃이 길어 DB 트랜잭션을 연 채로 대기</li>
<li>배포 직후 connection storm으로 새 인스턴스들이 동시에 하류 연결 시도</li>
<li>재시도가 겹쳐 동일한 하류에 중복 부하 발생</li>
</ul>
<p>이때 커넥션 풀을 늘리는 것은 원인을 치우는 것이 아니라 증상을 옮기는 것에 가깝습니다. 특히 &ldquo;DB 트랜잭션을 잡은 채 외부 API 호출&quot;은 풀 포화의 고전적인 원인입니다. 이 문제는 쿼리 튜닝이나 락 개선보다 먼저 <strong>트랜잭션 경계 정리</strong>로 해결되는 경우도 많습니다.</p>
<p>그래서 사고 때는 &ldquo;풀이 모자라다&quot;보다 먼저 아래를 봐야 합니다.</p>
<ol>
<li>풀을 오래 점유한 상위 요청은 무엇인가</li>
<li>그 요청이 실제로 DB 일을 오래 한 것인가, 아니면 외부 대기 때문에 붙들린 것인가</li>
<li>타임아웃 순서와 재시도 정책이 대기를 증폭시키고 있지 않은가</li>
<li>신규 인스턴스 기동, 배치 시작, 캐시 만료 같은 이벤트가 같이 있었는가</li>
</ol>
<p>이 질문을 먼저 던지면 문제 절반은 방향이 잡힙니다.</p>
<h2 id="실무-적용">실무 적용</h2>
<h3 id="1-사이징-의사결정-기준숫자조건우선순위">1) 사이징 의사결정 기준(숫자·조건·우선순위)</h3>
<p>커넥션 풀 관련 의사결정 우선순위는 보통 아래 순서가 안전합니다.</p>
<p><strong>1순위, 체류시간 원인 확인</strong></p>
<ul>
<li>쿼리 p95, 락 대기, 외부 API 대기, 트랜잭션 길이를 먼저 봅니다.</li>
<li>체류시간 증가가 원인이면 풀 확대보다 원인 제거가 우선입니다.</li>
</ul>
<p><strong>2순위, 대기 한도와 타임아웃 정렬</strong></p>
<ul>
<li>풀 대기 타임아웃은 전체 API timeout의 <strong>20~30% 이내</strong>로 두는 편이 좋습니다.</li>
<li>예를 들어 API deadline이 1초면 pool wait는 150~250ms 안에서 먼저 실패시키는 편이 낫습니다.</li>
</ul>
<p><strong>3순위, 총합 동시성 상한 관리</strong></p>
<ul>
<li>인스턴스당 풀 크기보다 <code>인스턴스 수 × 풀 크기</code>의 총합을 먼저 관리합니다.</li>
<li>총합이 DB 안정 active session의 <strong>1.2~1.5배</strong>를 넘기면 보수적으로 봅니다.</li>
</ul>
<p><strong>4순위, 풀 확대는 여유가 확인된 뒤</strong></p>
<ul>
<li>DB CPU 70% 이하, 락 대기 낮음, 쿼리 p95 안정, retry low 상태에서만 단계적으로 확대합니다.</li>
<li>한 번에 2배 올리기보다 <strong>10~20% 단위</strong>로 조정하고 1~2일 관찰합니다.</li>
</ul>
<h3 id="2-추천-시작값과-경계-조건">2) 추천 시작값과 경계 조건</h3>
<p>정답 숫자는 아니지만, 출발점으로는 아래 기준이 실전적입니다.</p>
<ul>
<li>단순 CRUD API, 인스턴스당 CPU 2코어: DB 풀 <strong>8~16</strong>에서 시작</li>
<li>읽기 비중 높고 쿼리 짧음: <strong>12~20</strong> 범위 검토 가능</li>
<li>긴 트랜잭션, 배치, 분석 쿼리 혼재: 온라인 트래픽 풀은 더 작게, 별도 워크로드 분리 우선</li>
<li>HTTP 클라이언트 풀은 대상 서비스별로 분리하고, 상류 워커 수의 <strong>30~60% 수준</strong>에서 시작</li>
<li>풀 대기 p95가 20ms 아래이고 DB 여유가 충분하면 소폭 확대 검토</li>
<li>풀 대기 p95가 높아도 DB CPU/lock wait가 높으면 확대보다 쿼리/락/재시도 점검 우선</li>
</ul>
<p>특히 DB와 HTTP를 모두 쓰는 API는 두 풀의 곱이 아니라 <strong>더 작은 쪽이 실제 상한</strong>이 됩니다. 이 기본 사실을 놓치면 한쪽만 늘리고 &ldquo;왜 개선이 없지&quot;라는 상황이 반복됩니다.</p>
<h3 id="3-장애-대응-런북">3) 장애 대응 런북</h3>
<p>커넥션 풀 포화가 의심될 때는 아래 순서가 빠릅니다.</p>
<p><strong>1단계, 대기와 실행을 분리해서 본다</strong><br>
풀 획득 대기시간과 실제 쿼리/외부호출 시간을 분리합니다. 기다림이 길어진 것인지, 하류 실행이 길어진 것인지 먼저 구분해야 합니다.</p>
<p><strong>2단계, 총합 동시성과 인스턴스 변화 확인</strong><br>
오토스케일링, 롤링 배포, 배치 시작으로 전체 커넥션 총합이 갑자기 늘지 않았는지 봅니다.</p>
<p><strong>3단계, 재시도와 timeout 증폭 차단</strong><br>
재시도율이 올라가면 풀 포화는 더 빨리 악화됩니다. 상위 timeout과 retry budget을 임시로 줄여 증폭을 먼저 끕니다.</p>
<p><strong>4단계, 오래 잡고 있는 상위 요청 식별</strong><br>
상위 5개 슬로우 경로가 전체 점유시간의 대부분을 차지하는 경우가 많습니다. 대개 여기서 빠르게 이득이 납니다.</p>
<p><strong>5단계, 풀 확대는 마지막 카드로 쓴다</strong><br>
DB 여유가 분명하고 대기만 병목일 때만 소폭 늘립니다. 그 외에는 원인 치료 없이 문제 면적만 넓어질 수 있습니다.</p>
<h3 id="4-팀-운영-규칙으로-문서화할-것">4) 팀 운영 규칙으로 문서화할 것</h3>
<p>지속적으로 덜 흔들리려면 아래 항목을 런북이나 운영 표준에 적어 두는 편이 좋습니다.</p>
<ul>
<li>서비스별 DB 풀 상한과 근거 지표</li>
<li>인스턴스 수 증가 시 총합 동시성 계산 방식</li>
<li>풀 대기 타임아웃과 API deadline 관계</li>
<li>배포 시 connection warm-up, preStop, connection storm 완화 절차</li>
<li>슬로우 쿼리와 장기 트랜잭션을 주간으로 점검하는 루틴</li>
</ul>
<p>이걸 문서화해 두면, 트래픽이 늘 때마다 사람마다 다른 감으로 풀 숫자를 올리는 일을 꽤 줄일 수 있습니다.</p>
<h2 id="트레이드오프주의점">트레이드오프/주의점</h2>
<p>첫째, 풀을 너무 작게 잡으면 정상 피크에서도 대기가 과도해질 수 있습니다. 그래서 무조건 작은 풀을 선호하면 안 됩니다. 중요한 것은 작은 숫자 자체가 아니라 <strong>측정 가능한 근거로 키우는 방식</strong>입니다.</p>
<p>둘째, 풀을 너무 크게 잡으면 DB가 느린 요청을 더 많이 동시에 처리하게 되어 tail latency와 락 경합이 악화될 수 있습니다. 특히 쓰기 비중이 높거나 긴 트랜잭션이 섞이면 더 위험합니다.</p>
<p>셋째, 애플리케이션 풀만 보고 판단하면 오판하기 쉽습니다. DB 내부 active session, lock wait, slow query, 외부 API timeout을 같이 봐야 합니다.</p>
<p>넷째, 풀 포화는 자주 &ldquo;부족&rdquo; 문제가 아니라 &ldquo;보유 시간이 길어진 문제&quot;입니다. 트랜잭션 범위, 쿼리 계획, 재시도, 배치 간섭을 같이 봐야 합니다.</p>
<p>다섯째, 같은 서비스라도 평시와 이벤트 시간대의 최적값이 다를 수 있습니다. 그래서 하드코딩된 숫자보다 경보 기준과 재평가 주기가 더 중요합니다.</p>
<h2 id="체크리스트-또는-연습">체크리스트 또는 연습</h2>
<h3 id="체크리스트">체크리스트</h3>
<ul>
<li><input disabled="" type="checkbox"> 서비스별로 DB 풀 상한의 근거 지표가 문서화되어 있다.</li>
<li><input disabled="" type="checkbox"> <code>pool_acquire_p95/p99</code>, pending, timeout, DB active session을 같은 화면에서 본다.</li>
<li><input disabled="" type="checkbox"> 인스턴스 수 변화 시 총합 동시성 상한을 계산한다.</li>
<li><input disabled="" type="checkbox"> API deadline, pool wait timeout, DB query timeout 순서가 정렬돼 있다.</li>
<li><input disabled="" type="checkbox"> 재시도 정책이 풀 포화를 증폭시키지 않는지 주기적으로 점검한다.</li>
<li><input disabled="" type="checkbox"> 장기 트랜잭션과 슬로우 쿼리 상위 목록을 주간으로 검토한다.</li>
</ul>
<h3 id="연습-과제">연습 과제</h3>
<ol>
<li>현재 운영 중인 API 하나를 골라 <code>피크 RPS × DB 점유시간 p95</code>로 필요한 총 동시성을 계산해 보세요. 지금 풀 상한과 얼마나 차이 나는지 숫자로 확인해 보면 감 대신 기준이 생깁니다.</li>
<li>HikariCP나 클라이언트 풀 메트릭에서 <code>acquire p95</code>, <code>pending</code>, <code>timeout</code>을 한 화면에 모아 보세요. 그다음 같은 시간대의 DB lock wait를 붙여 보면 풀 부족과 하류 병목이 분리됩니다.</li>
<li>최근 한 달간 배포 직후 latency가 튄 적이 있다면, 신규 인스턴스 기동 시점과 커넥션 생성 급증 시점을 겹쳐 보세요. connection storm가 원인이면 풀 숫자보다 기동 절차를 먼저 손봐야 합니다.</li>
</ol>
<h2 id="관련-글">관련 글</h2>
<ul>
<li><a href="/learning/modules/backend-resilience-phase/">백엔드 커리큘럼: 회복탄력성 단계</a></li>
<li><a href="/learning/deep-dive/deep-dive-capacity-planning-littles-law-saturation/">용량 계획과 Little&rsquo;s Law 기반 포화도 해석</a></li>
<li><a href="/learning/deep-dive/deep-dive-thread-pool/">Thread Pool 튜닝</a></li>
<li><a href="/learning/deep-dive/deep-dive-timeout-retry-backoff/">Timeout/Retry/Backoff 설계</a></li>
<li><a href="/learning/deep-dive/deep-dive-connection-storm-thundering-herd-playbook/">Connection Storm과 Thundering Herd 플레이북</a></li>
<li><a href="/learning/deep-dive/deep-dive-admission-control-concurrency-limits/">Admission Control과 동시성 제한</a></li>
</ul>
]]></content:encoded></item></channel></rss>