connection 누수가 어디서 난거지?

허준현·2023년 10월 29일
0

MySQL

목록 보기
3/3
post-thumbnail

프로젝트를 진행하면서 connection pool에서 connection을 얻지 못해 timeout이 발생하는 일이 발생하였다.
단순하게 connection 수를 늘리는 것이 아닌 각자 맡은 업무에서 connection을 최대한 줄여보는 것이 목표로 하였고 해당 해결 과정을 작성하고자 한다.

먼저 스프링에서 제공하는 트랜잭션이 시작되는 과정은 아래와 같다.

OPEN-DBC jdbc:mysql
setAutoCommit(false)

~~ 비지니스 로직 실행 ~~

commit
setAutoCommit(true)
close

해당 프로젝트에서는 다중 DB를 사용하고 있었는데 당연히 해당 트랜잭션을 지정한 DB 외에 다른 DB에 접근하는 경우에는 별도의 커넥션을 가지게 된다.
사실 하나의 로직 내에서 하나의 connection을 가지기 때문에 어디서 누수가 되는지 몰랐다.

try-catch를 하면 별도의 커넥션을 가지나?

점점 원인을 찾지 못해서 엉뚱한 생각을 하게 되었다. 2PC 전략 중에서 JTA를 사용한 분산 트랜잭션을 사용하면 lock을 오래 잡고 있고 있어서 try-catch 문 안에 다른 DB 쿼리를 작성하는 방식으로 구현하였다.

앞에서 말했던 것처럼 try-catch를 사용하게 되면 트랜잭션이 해당 쿼리에 대해 찾지 못한다고 했으니 try 내부에서 별도의 커넥션을 맺는 줄 알았으나 동일한 커넥션에서 이루어지는 것을 확인하였다.

Hikari 커넥션 풀의 문제인가?

점점 원인을 찾기 위해서 프로젝트 설정까지 열어 보는 시간을 가지게 되었다. 튜닝의 요건은 mysql이 해당 connection이 사용하지 않는다고 판단하는 시간 wait_time 과 hikari 풀에서 최대 연결 시간인 maxlife-time 를 비교해야 한다.
만일 maxlife_timewait_time 보다 크게 된다면 db 인프라상에서는 연결이 끊어졌지만 spring 단에서는 연결이 되고 있다고 판단하여 비연결 connection을 제공하는 문제가 발생하기 때문이다.

아쉽게도 두개를 비교해본 결과 mysql 기본 wait_time 인 28800 와 wait_time는 30초를 사용하고 있었고 해당 문제가 아니었다.

찾아라 connection 누수

대체 어디서 별도의 connection을 가지고 있는지 확인하는 도중에 master 테이블의 채번 로직을 확인하였는데 mysql에서는 sequence를 제공하지 않아 채번 procedure를 작성하여 호출하는 방식으로 구현 되어 있으며 안에는 transaction으로 묶여 있었다.
따라서 해당 채번하는 과정에서 트랜잭션을 시작함과 동시에 connection을 추가로 불러오고 있었다.

해당 경우를 보면서 하나의 의문점을 가지게 되었다. mysql이 sequence를 제공 하지 않지만 auto-increasement를 제공하는 것으로 알고 있기 때문이다

auto-increasement는 좋지 않다?

해당 keyword로 검색하면 키가 순차적이어서 예측하기 쉽다 라던가 분산형 시스템에서 중복 key 생성으로 인해 key 중복이 발생할 수 있다는 것이다.
먼저 oracle에서는 rac을 통해서 분산형 시스템을 지원하고 있고 미리 채번한 값을 각 DB에 배분하여 중복이 발생하는 것을 막을 수 있다.
mysql은 관점을 달리 해야하는게 분산형 시스템 보다는 matser-slave 구조를 가지고 있는 DB이기 때문에 하나의 master 테이블에서 채번 하는 것이 맞다고 생각한다.

그래서 필자가 생각하기에는 전혀 문제가 없어 보였는데 우테코 및 mysql 5.* 버전에서 문제를 찾을 수 있었다.

auto-increasement counter 저장하는 위치

먼저 낮은 버전의 mysql의 경우에는 해당 counter 를 메모리에 저장하고 사용하였다.
따라서 mysql 서버를 재가동하는 경우에는 counter값이 중복나는 경우가 발생하였지만 8버전으로 올라오면서 디스크인 redo log 에 저장하게 되면서 재가동을 하는 경우에도 키 중복이 발생하지 않는다. 해당 문제에 대해서는 채번 counter blog 에서도 확인할 수 있었다.

결론

아무도 분석 설계 과정에서 재가동에서 문제가 있다고 발생하여 채번하는 로직을 추가하고 해당 키를 primary key로 지정한 것 같다. 하지만 수많은 데이터가 날라오는 프로젝트이다 보니 해당 경우로도 배치성 api가 동시에 접근하는 경우에 주키 중복 오류가 발생하기도 하며 connection 누수가 발생하였다. 이번 기회에 connection 공부를 진행하면서 mysql에 버전에 따른 counter 저장 방식에 대해서도 배우는 시간이었다.

추가적으로 해당 프로젝트에서 사용해야 하는 적절한 connecection-pool 설정은 우아한 블로그 에 자세히 나와있어 필독하는 것을 추천한다.

참고

connection 누수
게임회사 connection 관리
counter

profile
best of best

0개의 댓글