Study

(MySQL / MariaDB) Too many connections 해결 (max connections 오류)

Developer RyanKim 2020. 1. 19. 21:39

Too many connections 해결


얼마전 테스트 환경(beta)에서 사용하는 DB에 연결이 계속 실패되는 현상이 발생하였습니다.

"Too many connections"

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Too many connections

베타 DB인데 이게 무슨일이지? 하고보니 다들 로컬에서 커넥션을 유지시켜놓고 해제하지 않아
커넥션이 엄청 잡혀있는 상태였어요. (MSA 환경이어서 서비스마다 DB커넥션을 유지하기 때문에 한명당 6~7개 이상 잡아먹고 있음..)
베타 DB는 성능이 좋은 서버를 쓰지 않았기 때문에 버티지 못한것이었습니다.. ㅠㅠ

사용중인 제품은 AWS RDS MariaDB를 사용하고있고 최대 커넥션 개수가 몇개인지 찾아보았습니다.

max_connections

기본적으로 

max_connections = {DBInstanceClassMemory/12582880}
로 설정된다고 확인하였습니다.

그렇다면 우리 DB 인스턴스(t2.medium)는 4GB의 메모리용량을 사용하니까
(4*1024*1024*1024)/12582880 = 341.334201391
341로 설정이 되어있을 것으로 예상하고 DB에 연결하여 명령어로 확인하였는데

show variables like 'max_connections';

 

show variables like 'max_connections' 결과

312개 네요.

서치결과 AWS에서 .medium 인스턴스의 최대 커넥션 갯수를 312개로 정해놓았다고 합니다.


그러면 단순히 max_connections 변수의 값을 늘려서 해결 하면될까요?

-> 정답은 No 입니다. 

1. 최대 커넥션 갯수를 늘린다고 해서 처리 가능한 메모리 용량이 느는것이 아니기 때문에
연결을 허용한다해도 과부하가 걸려 처리를 못할 수 있습니다.

2. 최대 커넥션 수가 또 증가하지 말라는 법은 없습니다.
또 "Too Many Connections" 오류가 발생했을 때 다시 더늘려주고 하는것은 비효율적입니다.

그렇다면 어떻게 해결할까요?

-> DB에서 커넥션 갯수를 관리하도록 설정해주는 방식으로 해결하기로 했습니다.
1. 일정시간 요청이 없는 커넥션을 끊음
2. 커넥션이 닫히기 전 기다리는 시간을 짧게 설정함

설정 전에 기본적인 설정이 어떻게 되어있는지 확인해본 결과

wait_timeout

interactive_timeout= 28800
(interactive 모드에서 time out 을 말합니다. 
interactive 모드는 'mysql>' 과 같은 프롬프트 있는 콘솔이나 터미널 모드를 말합니다)

wait_itmeout = 28800
( interactive 모드가 아닌 경우에 해당되며,
mysqld 와 mysql client 가 연결을 맺은 후, 다음 쿼리까지 기다리는 최대 시간을 의미합니다)

*** 중요! 초 단위 입니다. (28800 -> 28800초 8시간)
위처럼 설정되어있네요. 

설정방법

1. 명령어를 통해 설정 ( 서버 재시작시 설정이 초기화됨)

set global interactive_timeout = 180;
set global wait_timeout = 180;

2. 환경변수 파일 변경

/etc/mysql/mariadb
.conf.d/50-server.cnf
내용중
wait_timeout = 180 <
interactive_timeout = 180 <

*** 중요! 초 단위 입니다. 180 -> 180초


저는 AWS가 제공하는 웹페이지에서 쉽게 환경변수 설정을 바꾸었습니다. 결과적으로 2번을 선택한 것이죠.

이제 3분간 요청이없는 커넥션은 끊도록 설정되었고 실제로

"Too Many Connections" 오류를 만나는 일은 사라졌습니다.

하지만 서버에서

HikariPool-1 - Failed to validate connection com.mysql.cj.jdbc.ConnectionImpl@198a30ae (No operations allowed after connection closed.). Possibly consider using a shorter maxLifetime value.

위와같은 warn Level의 로그가 자주 보이게 되었는데요.

커넥션풀에 커넥션을 유지하는 객체는 살아있으나 DB서버쪽에서 커넥션을 끊어버렸기 때문에
커넥션이 없는 상태의 커넥션 객체가 생기게되고, 그 객체에 요청이 발생하면 찍히는 로그라고 합니다.

아마 커넥션을 새로 연결해야해서 성능이 많이 저하되겠죠?
현재는 테스트서버를 설정한 것이라 상관없지만, 운영서버라면 정교하게 시간을 조정하여 설정해야 할것 같습니다.

읽어주셔서 감사합니다!


By. RyanKim