본문 바로가기

Loopers/WIL

Week 6. 이론과 수치

결제 흐름을 짜고 나서 "이 정도면 됐다" 싶었다.

 

@Transactional 하나가 전체를 감싸고, PG 호출이 실패하면 자동으로 롤백된다.

 

구조도 단순하고, 동작도 맞다.

 

k6를 돌리기 전까지는 그랬다.


DB 커넥션은 유한하다.

 

HikariCP 기본 풀 사이즈는 10이다.

트랜잭션이 커넥션을 들고 있는 동안 다른 요청은 기다린다.

평소엔 트랜잭션이 짧아서 문제가 없다. PG처럼 응답이 100~600ms씩 걸리는 외부 호출이 트랜잭션 안에 있으면 얘기가 다르다.

 

커넥션 10개가 전부 PG 응답을 기다리는 순간, 나머지 요청들은 줄을 선다.

k6로 80명의 가상 유저를 붙여봤다.

pool_timeout_rate가 7.02%였다. 100건 중 7건이 커넥션을 얻지 못하고 503으로 떨어지고 있었다.


트랜잭션을 나눴다.

 

PG 호출 전에 커밋하고, 결과가 돌아오면 새 트랜잭션을 열어 저장하는 방식이다.

 

같은 조건에서 다시 돌렸다.

 

 

지표 분리 전 분리 후
pool_timeout_rate 7.02% (48 / 683건) 2.37% (16 / 674건)
payment_duration p(95) 3.57s 2.55s
payment_duration max 5.52s 3.94s

 

66% 감소.

 

이론으로는 알고 있었다.

"외부 호출을 트랜잭션 안에 두면 커넥션 점유 시간이 길어진다." 수치로 보는 건 다르다.

7.02%가 2.37%가 되는 걸 직접 확인하고 나서야 이론이 실제가 됐다.


트레이드오프가 생긴다.

 

나누고 나면 이미 커밋된 상태를 되돌리는 보정 코드를 직접 짜야 한다.

그리고 그 보정 자체가 실패할 수 있다.

 

하나를 고치면 다른 곳이 복잡해진다.

 

"완벽한 설계"를 고르는 게 아니라 어떤 리스크를 감수할지 고르는 것이다. 수치가 그 판단의 근거가 됐다.


CB 설정을 다룰 때도 비슷한 일이 있었다.

"slowCallDurationThreshold를 넘으면 CB가 열린다"는 걸 알고 있었다.

 

설정하고 돌렸는데 CB가 열리지 않았다. TimeLimiter가 먼저 호출을 끊어버렸기 때문이다.

TimeLimiter가 끊은 호출은 slowCallRate가 아닌 failureRate로 집계된다.

두 채널이 다르다.

 

문서가 틀린 게 아니었다.

 

직접 돌려보기 전까지는 이해한 게 아니었다.


이론과 실측 사이에는 항상 간격이 있다.

 

설정 파일은 의도를 적은 것이지, 동작을 보장하는 게 아니다.

 

수치가 나오기 전까지 나는 이해했다고 생각했을 뿐이다.

'Loopers > WIL' 카테고리의 다른 글

머물러 있던 자리를 벗어난 10주  (0) 2026.07.23
Week 5. 인덱스와 캐시  (0) 2026.06.19
Week 4. 동시성 제어  (0) 2026.06.12
Week 3. 도메인 주도 설계  (0) 2026.05.29
Week 2. 설계는 선택의 연속이다.  (0) 2026.05.22