
Data source rejected establishment of connection, message from server: "Too Many Connection"
> DB의 커넥션 풀이 부족해서 일시적으로 발생한 문제
현재 하고 있는 프로젝트에서 발생한 이슈였다.
현재까지 프로젝트를 진행하면서 이런 에러가 발생한 적은 없었다.
사용자들로부터 웹사이트 접속이 안된다고 연락을 받았고 확인을 해보니까 DB에 연결이 되질 않았다.
DBeaver로도, 인텔리제이로도 접속이 전혀 되지 않았다. 위와 같은 에러 메시지만 발생시킨채.
이름도 SQLNonTransientConnectionException 이라고, 처음 봤다. 그리고 새로운 것을 경험하는 아주 좋은 기회라고 생각이 들었다.
SQLNonTransientConnectionException
- Transient: 일시적인, 순간적인
일시적으로 SQL 서버에 연결을 할 수 없어서 발생한 Exception이라는 것이다.
에러의 원인은 DB의 커넥션 풀이 부족해서 일시적으로 발생한 문제라고 했다.
시간이 조금 지나서 다시 연결을 접속해보니 그때는 또 연결이 잘 됐다.
현재 사용하고 있는 DB의 max_connections값을 확인해봤더니 현재는 90이었다.
이 문제를 해결하기 위해서는 커넥션 풀 값을 직접 늘려서 재설정을 해주면 되긴 하지만 이는 근본적인 해결 방법은 아니라고 한다.
보통 DB의 메모리가 가용한 커넥션 풀을 설정해 둔 것이기 때문이 이를 단순히 늘려주기만 하면 메모리 부족 문제가 발생할 수 있다고 한다.
또한 커넥션 풀 값을 변경을 하게 되면 DB서버 재부팅을 해야 한다고 하는데 지금 서비스 중인 DB가 1개 뿐이라 재부팅을 하는 것도 불가능하다고 생각했다.
내가 선택한 해결 방법
어떻게 해야 할지 고민을 한 끝에 aurora DB 클러스터에 readOnly DB를 추가해서 요청을 2개로 분산시켰다.
이전까지는 1개의 DB에서 read와 write를 같이 사용했는데 사용자가 늘어남에 따라 (게다가 현재 회사에서 특정 기간동안 이벤트를 하고 있었기 때문에 더더욱 트래픽이 몰렸을 것이다) 커넥션 풀 또한 부족했던 것 같다.
read DB와 write DB를 분리하는 작업은 사용자가 많아짐에 따라 필수적으로 해야 하는 작업이라고 생각하고 있고,
또 우리의 서비스 사용자들이 계속해서 늘어나고 있기 때문에
조금 이른 감이 있을지라도 앞으로 발생할 문제를 대비하는 차원에서 이 방법을 선택했다.
가능한 추가 원인
그리고 조금 더 찾아본 결과,
커넥션 풀이 부족한 원인 중 또 하나는 쿼리를 날릴 때 사용했던 커넥션을 바로 반환하지 않고 잡아두고 있는 시간이 존재하기 때문이라는 것을 알게 됐다. 이 값이 wait_timeout 값이다. 한 번 커넥션을 맺고 나면 쿼리를 날릴 수 있는 ‘커넥션 지속시간’인 것이다.
MySQL 환경 변수(파라미터) : wait_timeout, connect_timeout ...
wait_timeout값도 존재하고 connect_timeout 이라는 값도 존재한다.
wait_timeout은 한 번 커넥션을 맺고 나서 추가 쿼리를 날릴 수 있는 ‘커넥션 유지 시간’이라고 할 수 있고,
connect_timeout은 db와 클라이언트가 커넥션을 맺기 위해 대기할 수 있는 시간을 의미한다.
이 값보다 대기 시간이 늘어지면 connection timeout과 같은 connection fail이 뜨는 것이다.
mysql서버에는 위와 같은 환경 변수 값들이 많이 있고,
'DB를 튜닝'하는 것은 이러한 환경 변수 값들을 변경함으로써 자신의 상황에 맞게 설정한다는 것이다.
다음은 DB를 튜닝하는 데에는 고려해야 하는 것들이다.
실제로 좀더 정확하게 튜닝하기 위해서는,
- 시스템 전체 상황(실제 어느 정도로 바쁜지에 대한 상대적 수치),
- 초당 connections 수,
- 커넥션당 평균 쿼리 요청수,
- 커넥션당 생성된 평균 쓰레드 수
- 초당 평균 전송량
- DISK에 생성된 임시 테이블 생성 비율
- Slow_queries
- 한계 도달 N 초 계산
- 커넥션 life time
이런 값들을 계산 및 고려하여,
- max_connections
- wait_timeout
- back_log
- thread_cache_size
- key_buffer_size
- record_buffer (read_buffer_size)
- record_rnd_buffer
- sort_buffer_size
- 기타 메모리 설정
이런 파라메터에 설정을 해줘야 합니다.
실제 MySQL 서버의 파라메터 설정은,
1) 사용가능한 최대 전체 데이터베이스 크기와 각 테이블 평균 크기 계산
2) MySQL 이 사용하는 시스템 물리적 메모리 크기
3) 1)에 의한 shared 메모리와 쓰레드 메모리 할당 및 계산
4) 2)과 3)에 의한 최대 동시 접속 가능한 max_connections 계산
5) time out 설정
6) 그 외 설정
7) 시스템을 운영하면서 지난 통계 데이터에 의한 설정값 다시 튜닝
이와 같은 순서로 튜닝해 나가야 합니다.
참고
https://knight76.tistory.com/entry/30031445050
'Infra' 카테고리의 다른 글
| Slack Webhook with Node.js (1) | 2024.02.14 |
|---|---|
| centos계열 Linux에 Docker 설치 (0) | 2023.11.28 |