MySQL Connection 정리

아재발자·2024년 5월 31일
0

MySQL

목록 보기
1/6

Too many connection 에러는 서비스를 운영하면서 자주 겪게되는 오류 중 하나입니다.

지금까지 개발을 하면서 직접 경험한 내용을 바탕으로 공부하고 알게된 지식을 정리하는 글입니다.


Foreground Thread

MySQL은 프로세스 기반이 아닌 스레드 기반으로 작동하며, 일반적으로 Foreground Thread와 Background Thread로 구분을 합니다.
(Background Thread는 이 글에서 다루지 않습니다.)

Client가 MySQL 서버에 연결을 요청하면 MySQL 서버는 해당 요청을 Connection Requests 대기열에 추가를 합니다. 그리고 Receiver Thread는 이러한 요청을 순차적으로 소비하면서 각 Client의 요청을 처리해줄 Thread를 생성합니다.

참고!
과거에는 Thread를 생성하고 삭제할 때 발생하는 비용이 컸기 때문에 이러한 오버헤드를 줄이고 성능을 향상시키기 위해 Thread Cache를 이용하여 Thread를 관리했습니다.

그러나 요즘에는 Thread를 생성하고 삭제할 때 발생하는 비용이 저렴해져 Thread Cache를 레거시로 보고 있습니다.

이렇게 생성된 Thread는 MySQL 앞단에서 Client와 통신을 하기 때문에 Foreground Thread라고 불립니다. 그렇기 때문에 일반적으로 Foreground Thread는 MySQL 서버에 연결된 Client 수 만큼 존재하게 됩니다.

MySQL Connection

MySQL에서 Connection은 Client가 MySQL 서버에 접속해서 데이터를 주고 받는 통신 세션을 의미합니다.

Threads_connected

MySQL 서버에서 현재 연결중인 Connection의 수를 확인하는 방법은 현재 활성화된 Foreground Thread의 갯수를 확인하는 방법입니다.

따라서 아래와 같이 현재 활정화된 Thread의 수를 확인하여 현재 연결중인 Connection의 수를 확인할 수 있습니다.

SHOW STATUS LIKE 'Threads_connected';

max_connections

max_connections는 MySQL 서버에서 동시에 연결할 수 있는 Client의 수를 제한하는 옵션입니다.

참고!
max_connections의 최대값은 아래의 요인에 따라 달라질 수 있습니다.

  • 특정 플랫폼의 스레드 라이브러리 품질
  • 사용 가능한 RAM의 양
  • 각 연결에 사용된 RAM의 양
  • OS에서 사용가능한 File Descriptor의 Limit

그리고 AWS RDS의 경우 DBInstanceClassMemory에 비례하여 max_connections의 기본값이 설정됩니다.

MySQL 서버는 위에서 언급한 Receiver Thread에서 연결 요청을 처리하는 과정에서 현재 연결된 connection 수와 max_connections 설정의 값을 참조하여 Thread를 생성할지, 아니면 Too many connections 에러를 응답할 것인지 결정하게 됩니다.

max_connections와 DB 관리자와의 관계

MySQL 서버는 모니터링 및 장애 조치를 위해 CONNECTION_ADMIN 권한을 가진 유저가 접속할 수 있도록 max_connections 값에서 +1 만큼의 여유 Connection을 미리 확보합니다.

그렇기 때문에 Too many connection 에러가 발생하는 상황에서도 CONNECTION_ADMIN 권한을 가진 계정으로 MySQL 서버에 접속을 할 수 있습니다.

만약 Too many connection 에러가 발생하는 상황일 때 MySQL 서버에 접속이 불가능하다면 CONNECTION_ADMIN 권한이 없거나 누군가가 이미 접속을 하고 있다고 볼 수 있습니다.

복제를 위한 내부 세션(Connection)과 max_connections의 관계

MySQL 8.0.18 버전까지는 복제를 위한 내부 세션(Connection)도 max_connections 제한에 포함이 되었습니다. 그렇기 때문에 Too many connections 에러가 발생하는 상황에서 복제 작업이 동작하면, 해당 작업이 실패되는 상황이 발생했습니다.

다행히도 MySQL 8.0.19 버전부터는 복제를 위한 내부 세션(Connection)은 max_connections 제한에 포함되지 않도록 변경되었습니다.

max_connections와 OS File Descriptor

파일 디스크립터(File Descriptor)
유닉스 및 유닉스 계열 운영체제(예: 리눅스)에서 파일이나 입출력 장치를 식별하는데 사용되는 정수(Integer) 값으로, 프로세스가 파일이나 파이프, 소켓 등 다양한 입출력 자원과 상호작용할 수 있게 해주는 역할을 가지고 있습니다.

아래에서 말하는 Open은 운영체제(커널)의 open 함수를 통해 ibd 파일을 열어서 File Descriptor를 반환받는 행위를 말합니다.

MySQL은 세션(Connection)별로 각기 다른 상태(트랜잭션이나 상태, 락, 캐시, user 권한 등)를 가짐으로써 발생되는 문제를 최소화하기 위해서 테이블에 접근할 때 세션(Connection)별로 테이블을 열게끔 설계가 되어있습니다.

Client가 MySQL로 CRUD SQL을 요청하면 Foreground Thread는 해당 요청을 처리하기 위해 관련이 있는 테이블의 ibd 파일을 Open하게 됩니다.

즉, N개의 세션(Connection)들이 동일한 테이블로 CRUD 요청에 해당하는 SQL 명령을 요청하게되면 동일한 ibd 파일을 N번 열게되면서 N개의 File Descriptor가 생성됩니다.

이 과정에서 MySQL 프로세스가 가질 수 있는 File Descriptor의 제한을 초과하게 되면 장애가 발생할 수 있습니다.

MySQL은 이러한 문제를 방지하기 위해서 아래의 설정을 제공하고 있습니다.

  • open_files_limit
    테이블, 로그 등을 포함하여 MySQL이 동시에 가질 수 있는 File Descriptor의 수를 지정할 수 있습니다.
  • table_open_cache
    한 번 Open된 테이블의 파일 핸들러를 캐시 레이어에 저장하여, 이후 동일한 테이블에 접근할 때 발생되는 오버헤드(디스크 I/O 등)를 줄임으로써 성능을 향상시킬 수 있습니다.
    이 변수는 캐시 레이어에 캐싱할 파일 핸들러의 개수를 설정할 수 있습니다.

참고 문서

profile
안녕하세요. 아재 개발자입니다. 공부한 내용을 기록하고 잘못된 부분에 대해서 조언을 받기 위해 velog를 시작했습니다. :)

0개의 댓글