본 포스트는 WAS에서 커넥션 풀 부족 현상을 개선하는 방법 및 스프링(Spring Framework)에서 트랜잭션을 설정하는 방법에 대한 글입니다.

 

 

'22년 초부터는 마이데이터 사업자(토스나 뱅크샐러드 등)의 스크래핑이 금지되어 각 금융사의 Open API 서비스로 연결하도록 전환한 상태이지만 '21년까지는 스크래핑에 대한 규정이나 법률이 없었던 관계로 자산 관리 앱들은 각 금융사의 서버를 직접 스크래핑하는 구조였습니다.

 

특히나 해당 자산 관리 서비스들이 나름대로 성공했기 때문에 제법 많은 DAU를 보유하고 있었고, 그래서 해당 서비스들이 무언가 이벤트를 한다던가 PUSH를 발송한다던가 하면 그 트래픽은 고스란히 원천 데이터를 서비스하는 은행, 카드 등의 금융사들로 몰리게 됩니다.

 

사실 각 금융사에서는 시스템을 구축하기 위한 용량 산정을 할 때 이 스크래핑에 대한 부분을 잡지 않고 산정한 금융사가 대부분이므로  예상 TPS보다 150%, 200%의 거래가 유입되면 재미있는(?) 순간들이 많이 발생합니다.

 

그 중 하나였던 WAS Connection Pool 부족 현상에 대한 이야기입니다.

 

WAS Connection Pool 동작

WAS Connection Pool은 인스턴스를 시작할 때 설정한 개수만큼의 Connection Pool을 생성하여 가지고 있습니다. DB를 사용하는 거래가 유입되면 이 때 생성해 둔 Connection을 빌려서 사용하고 (Active), commit이나 rollback을 수행하면 해당 Connection을 Pool에 반납합니다.

 

지금 IDLE이 없고 전체 Connection이 모두 Active라는 이야기는 DB를 사용하는 거래가 유입되어도 Pool에 있는 모든 Connection이 사용 중이니 다른 거래가 완료되어야 현재 대기 중인 거래를 수행할 수 있다는 의미가 됩니다.

 

상태 확인

이런 현상들이 처음 발생했을 때는 특정 Query가 지연되거나 DB 사용률이 높아서 모든 Connection이 Active 상태인가? 라고 생각해서 DB 모니터링 툴을 확인했지만 전체적으로 CPU 도 2-30% 수준에 Running Session이 쌓이는 현상도 없었습니다.

 

일단 조치가 필요했으므로 유입되는 거래랑 특정 비율로만 통과시켜서 지연 상태를 해소시킨 후 Framework의 Transaction 설정을 확인했는데 아래와 같이 설정되어 있었습니다.

<aop:config>
	<aop:pointcut id="requiredTx"
    	expression="execution(* com..impl.*ServiceImpl.*(..))" />
    <aop:advisor advice-ref="txAdvice"
    	pointcut-ref="requiredTx" />
</aop:config>

위 설정은 전체 ServiceImpl 하위의 모든 method를 Transaction 처리한다는 설정입니다. 보통 SI를 하게 되면 특별히 요건으로 요청하지 않는 이상 기본적으로 저런 형태로 초기 설정을 많이들 하게 됩니다.

 

문제점

사실 대고객의 접점에 있는 채널 시스템(홈페이지나 앱 등)은 원천 데이터를 가지고 있지 않습니다. 기본적인 로그인에 필요한 정보나 부가 정보 등은 가지고 있지만 대부분의 데이터는 계정계나 승인 시스템에서 보유하고, 채널 시스템은 해당 시스템들과 연계하여 고객에게 정보를 제공합니다.

 

무슨 이야기인고 하니, 생각보다 자체적으로 DB Transaction 처리를 할 필요가 있는 업무가 많지 않다는 의미입니다. 하지만 타 시스템과 인터페이스를 할 때 DB를 늘 사용하게 되어 해당 거래들이 언제나 하나의 Transaction으로 묶이게 됩니다.

1. 전문 추적번호 채번 및 Logging을 위해 DB를 사용합니다.
2. ServiceImpl class에서 수행합니다.

위와 같은 이유로 타 시스템 인터페이스는 모두 Transaction으로 묶이므로 거래가 급증하여 내부에 있는 타 시스템들이 거래가 지연되어 응답이 늦게 되면 Pool에 있는 모든 Connection들이 Active 상태로 유지되어 전체 채널 거래의 지연으로 이어집니다.

 

해결 방법

해결은 단순히 '분리' 밖에 없습니다. Transaction으로 묶어야 하는 서비스와 Transaction으로 묶지 않아도 되는 서비스를 분리하여 설정해야 합니다. 예를 들어 채널 DB에서 관리하는 로그인이나 회원가입 등, INSERT 및 UPDATE가 있는 서비스는 All or Nothing이 보장되어야 하므로 Transaction 처리가 필요합니다.

 

하지만 타 시스템에서 값을 조회한다거나, 타 시스템에 데이터를 처리 요청하는 서비스의 경우에는 타 시스템에서 Transaction 처리한 후 결과를 응답하므로 채널 시스템에서는 Transaction 처리가 필요하지 않습니다. 이런 부분을 초기 설계에 반영해서 구축했다면 이런 지연 현상들은 많이 방지할 수 있었을테지만 보통 이런 문제는 '운영' 단계에 접어들어야 발생하곤 합니다.

 

운영 중인 시스템은 영향도 검토도 정말 만만치 않은 작업이고 전체 시스템에 영향을 주는 이런 설정을 변경하기는 정말 손 떨리는 작업이 됩니다.

 

분리 방향

분리 방향은 크게 두 가지로 나눌 수 있습니다.

1. 전체 ServiceImpl transaction을 해제 후
   transaction 처리가 필요한 ServiceImpl만 TxServiceImpl로 변경
2. 전체 ServiceImpl transaction 설정을 유지한 상태에서
   transaction이 불필요한 ServiceImpl만 aop 설정에서 제외 처리

먼저 1번 방향을 목표로 하고, 분석을 위해 프로젝트를 최신 상태로 Sync 해보니 현재 사용 중인 ServiceImpl이 500본 정도가 되었습니다. (ㅎㄷㄷ)  ServiceImpl 하나 당 method도 여러 개가 있으니 분석이 가능할까 싶었지만 팀원들과 공유하여 분석해 보기로 하였습니다.

 

각자 담당하고 있는 업무 영역이나 담당하지 않는 부분까지도 다들 바쁜 시간을 쪼개어서 분석에 참여하였기에 생각보다 잘 정리가 되는 듯 했지만 분석된 내용을 샘플링해서 검토해 보니, 잘못된 분석들이 꽤나 있었습니다. 예를 들면 이벤트 응모 같은 서비스는 채널의 DB에서 자체적으로 응모 데이터를 관리하므로 Transaction 처리가 필요하지만, 타 시스템과의 인터페이스도 있어 Transaction 불필요 업무로 분류되어 있었습니다.

 

시스템의 안정성이 위협을 받고 있는 상황에서 전체를 시니어들만으로 재분석 할 수는 없었기에 2번으로 방향을 급선회 했습니다.

 

Default는 Transaction 처리. 일부만 제외.

일단 일부만 제외하는 것으로 방향을 잡았으니 Impact가 있는 대상으로 선정이 필요했습니다. 하여 아래 기준을 적용하여 제외할 대상을 선정하고 진행했습니다.

1. 거래량 순위 TOP 40 안에 드는 거래 중
2. 타 시스템 인터페이스만 사용하고 DB 거래가 불필요한 서비스

Spring 설정은 아래와 같은 식으로 제외할 대상을 선언했습니다.

<aop:pointcut id="requiredTx"
	expression="execution(* com..impl.*ServiceImpl.*(..))
           and !execution(* com.a.AServiceImpl.*(..))
           and !execution(* com.b.BServiceImpl.*(..))" />

 전체 ServiceImpl은 기본적으로 Transaction 처리 후 !execution으로 원하는 ServiceImpl만 제외하는 설정입니다.

 

결과

효과는 정말 드라마틱 했습니다. 전체 3,000개 정도의 서버 인터페이스 중 TOP 40이 차지하는 비중은 80%가 넘었기에, 대부분의 거래에서 Connection을 점유하는 시간 자체를 줄였기 때문에 거래가 집중되어도 Active Connection이 증가하지 않았습니다.

 

집중이 아닌 시간 대에도 평소 Active Connection이 인스턴스 당 20-30 정도였지만 설정 변경 후에는 인스턴스 당 5-7 정도로 아주 안정적인 시스템으로 변신해 버렸습니다.

300x250

'Trouble shooting' 카테고리의 다른 글

Sequence order 옵션에 따른 성능  (0) 2022.06.25
Partition truncate 시 온라인 거래 지연 이슈  (0) 2022.06.24
MAX + 1 채번 이슈  (0) 2022.06.22
중복 로그인 체크 오류  (0) 2021.10.07
JS UI Rendering, Data bind  (0) 2021.10.06

+ Recent posts