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 = {DBInstanceClassMemory/12582880}
로 설정된다고 확인하였습니다.
그렇다면 우리 DB 인스턴스(t2.medium)는 4GB의 메모리용량을 사용하니까
(4*1024*1024*1024)/12582880 = 341.334201391
341로 설정이 되어있을 것으로 예상하고 DB에 연결하여 명령어로 확인하였는데
show variables like 'max_connections';
312개 네요.
서치결과 AWS에서 .medium 인스턴스의 최대 커넥션 갯수를 312개로 정해놓았다고 합니다.
그러면 단순히 max_connections 변수의 값을 늘려서 해결 하면될까요?
-> 정답은 No 입니다.
1. 최대 커넥션 갯수를 늘린다고 해서 처리 가능한 메모리 용량이 느는것이 아니기 때문에
연결을 허용한다해도 과부하가 걸려 처리를 못할 수 있습니다.
2. 최대 커넥션 수가 또 증가하지 말라는 법은 없습니다.
또 "Too Many Connections" 오류가 발생했을 때 다시 더늘려주고 하는것은 비효율적입니다.
그렇다면 어떻게 해결할까요?
-> DB에서 커넥션 갯수를 관리하도록 설정해주는 방식으로 해결하기로 했습니다.
1. 일정시간 요청이 없는 커넥션을 끊음
2. 커넥션이 닫히기 전 기다리는 시간을 짧게 설정함
설정 전에 기본적인 설정이 어떻게 되어있는지 확인해본 결과
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
'Study' 카테고리의 다른 글
(Java) JVM 메모리 구조 및 변수 적재 위치 (2) | 2020.04.17 |
---|---|
JPA란? 왜사용하나요? 짧은 답변 (0) | 2020.03.30 |
[2019 정보처리기사 실기 3회] 공부 방법 및 시험 후기 및 자료 (4) | 2019.11.07 |
Thread란? Process와 Thread의 차이/ Thread Pool? (0) | 2019.05.22 |
(JAVA) Java DFS 구현 Java dfs ArrayList (0) | 2019.03.16 |
댓글