원문: https://d1.awsstatic.com/whitepapers/RDS/amazon-aurora-connection-management-handbook.pdf

-----------1--1

Aurora DNS endpoint 구조

Aurora는 DB 클러스터로 존재하며
하나의 Primary instance 와
최대 15개 까지 지원 가능한 (read only) Replica instance가 있다.
이 Aurora cluster는 DNS endpoint가 4가지로 구성되는데

  1. 클러스터 엔드포인트: Primary instance를 자동으로 연결해주며, failover 시 자동으로 replica 중 하나가 primary로 승격되어 붙게 된다. (이 경우에 JDBC 드라이버 종류에 따라 커넥션 유실이 발생하는 경우가 있다.)

  2. 읽기전용 엔드포인트: Reader instance들만 묶인 DNS CNAME으로 구성되어 있으며 round robin으로 부하가 순차적으로 분산되게 할 수 있다.

  3. 인스턴스 엔드포인트: 각각의 instance를 가르키는 엔드포인트

  4. 커스텀 엔드포인트: 사용자가 클러스터 상에서 특정 instance들만 묶어서 별도의 엔드포인트를 제공할 수 있다.


MySQL과 Aurora MySQL의 커넥션 제어의 차이

MySQL은 1유저 1스레드 원칙이다.

이로 인해 Idle 상태의 커넥션이라도 유저들이 많으면 메모리 사용이 지나치게 발생한다.

지나친 내부 서버 자원 경쟁이 발생하고, (커넥션 풀에서) 컨텍스트 스위칭 비용으로 인한 오버헤드가 발생한다.

Aurora는 위의 이슈를 해결하고자 하는 방향으로 커넥션을 관리한다.

스레드를 멀티플렉스로 사용한다. 워커 스레드들은 유저 세션간에 교체가 가능하다. 즉, 스레드가 특정 유저 세션에 귀속되지 않는다. (Aurora는 1유저 1스레드가 아님)

스레드풀이 자동적으로 스케일한다.스레드 풀을 계속 감시해 늘리거나 줄이는 행위를 한다. 이를 통해 사용자가 별도의 스레드 풀 튜닝을 필요로 하지 않게 한다.

서버의 스레드 풀링이 커넥션 유지보수 비용을 줄여주는 효과를 가져다 준다.

그렇지만 여전히 최초 커넥션을 생성하는 곳에서 발생하는 비용 자체는 해소되지 않았다.

패킷을 열고 닫는 건 단순 TCP 패킷 하나가지고 해결이 되지 않는다. 짧은 연결 주기에다가 매우 빈번하게 발생하는 커넥션은 여전히 어플리케이션의 커넥션 풀이 담당해야 하는 부분이다.

커넥션 오버헤드는 서버에서 스레드 풀링을 통해서는 해결할 수 없는 유형의 문제이다.


자주 착각하는 부분

지금부터 다룰 부분은 커넥션 관리에서 자주 착각하는 부분이다. 굵은 글씨는 착각이라는 의미.

1.데이터베이스 서버가 커넥션 풀을 관리한다면 어플리케이션 쪽에선 커넥션 풀을 관리할 필요가 없다.

연결을 자주 맺고 끊는 식의 구성에서는 반드시 커넥션 풀이 필요하다. (일반적인 경우의 웹 서비스에 해당) 반대로 아주 오래 연결이 유지되어야 하는 경우라면 어플리케이션에서의 커넥션 풀이 붎필요 할 수도 있다. 커넥션을 열고 닫는 시간 보다 연결을 사용하는 시간이 더 긴 경우를 의미한다고 보면 된다. 패킷의 흐름을 추적해 보려면 tcpdump명령어를 써서 커넥션 간 오가는 패킷을 확인해 볼 수 있다. 그렇지만 커넥션이 오래 유지되어야 하는 경우라도 커넥션 풀은 유용하다. 갑작스레 부하가 큰 작업의 막대한 시도 등의 의도치 않은 공격이나 사건을 예방할 수 있기 때문.

2.놀고있는(Idle) 커넥션은 메모리를 쓰지 않는다.

운영체제와 데이터베이스 영역에서 제각기 메모리 수준에서 사용자 연결에 대해 관리하기 때문. Aurora가 기존 MySQL보다 이런 부분을 줄이기는 했으나 없애지는 못했다. 권장하는 방법은 필요 이상의 커넥션을 만들 필요가 없다.

3.다운타임은 전적으로 데이터베이스의 안정성과 기능에 좌우

최근에는 어플리케이션 설계와 설정이 더 많은 영향을 준다. 상세사항은 아래 Best Practice 참조


Best Practice (9가지)

1.스마트 드라이버 쓰기
Aurora는 DNS로 구성되어 있기 때문에 DNS 업데이트 주기가 예상한 대로 흘러가지 않습니다. 거기다가 종종 이벤트의 발생과 실제 처리 사이에 지연을 발생시키기도 함.

Aurora는 replica와 primary 간에 near-real time 상태를 유지하려고 하는데, 모든 인스턴스 상에서 메타데이터를 관리하는 테이블을 보면 현재 DB간의 데이터 동기화(replica) 지연 상태에 대해 쿼리를 통해 확인할 수 있음.

mysql> select server_id, if(session_id = 'MASTER_SESSION_ID', 'writer', 'reader') as role, replica_lag_in_milliseconds from information_schema.replica_host_status;

이 백서에서 다루는 스마트 드라이버는 데이터베이스 드라이버거나 커넥터로 DB의 클러스터 토폴로지를 메타데이터 테이블을 통해서 추가적으로 읽을 수 있는 녀석을 의미함.

이를 통해 새로운 커넥션이 발생하면 굳이 상위의 클러스터 엔드포인트를 타는 것이 아니라 바로 필요한 인스턴스로 연결을 할 수 있다. 스마트 드라이버는 읽기 전용의 요청이면 자연스럽게 Aurora Replica에 라운드 로빈 전략으로 로드 밸런싱을 할 수 있음.

그러한 이유로 MariaDB Connector/J가 Aurora MySQL에 추천되는 드라이버임

스마트 드라이버를 사용한다면 데이터베이스의 연결 레이어에 대해 추상적으로 접근하고 자동으로 해결해주는 것들이 많아짐.

여전히 최적의 세팅이라던가 회복 탄력성을 확보하는 것은 사람의 몫.

예를 들자면, 연결 검증과 재사용 함수의 설정이 정상적으로 되어 있는지, 과도한 DNS 캐싱이 시스템, 네트워크 계층에 존재하는지, 트랜잭션이 올바르게 관리되고 있는지 등등.

써드 파티 드라이버가 Aurora MySQL을 기능적으로 지원한다고 하더라도 AWS에서 검증한 것이 아니란 사실도 유념해야 함. 따라서 각 드라이버의 릴리즈 노트 등을 세밀히 보시고 가급적이면 최신의 드라이버를 사용해야 한다.

2.DNS Caching

Aurora의 DNS 구성은 TTL(Time To Live) 시간을 5초로 잡고 보고 있다.

그렇기 때문에 네트워크나 클라이언트 상의 설정에서 TTL 시간을 그 이상으로 설정해서는 안된다.

DNS 캐싱은 네트워크 레이어 어디서든 발생함을 명심해야 합니다. OS에서도 Application 컨테이너에서도요. JVM은 심지어 따로 설정하지 않으면 DNS 정보를 무한정으로 캐싱하는 거로 유명하다.

이러한 사항을 따르지 않으면 다음과 같은 일들이 벌어진다.

패일오버가 발생해 새로운 Primary Instnace가 생겨나도 어플리케이션에서는 문제가 생긴 과거의 Primary Instance에게 데이터를 변경하는 요청을 보낼 것이고 이러한 유형의 요청이 실패하게 된다.
데이터베이스 인스턴스의 스케일업이나 스케일다운이 발생하면 어플리케이션에서 연결할 수 없다. 이 또한 DNS 캐싱 때문(구 IP로 어플리케이션이 접근하기 때문)
레플리카들의 부하 분산이 고르게 이뤄지지 않게 된다. 특정 인스턴스에게 트래픽이 몰리는 현상을 목격하게 된다.

3.커넥션 관리와 풀링

어플리케이션의 데이터베이스 커넥션의 종결은 명시적으로 하는게 아니라 언어나 프레임워크 차원에서 종결 시 수행 하도록 한다.

컨테이너 기반이나 서버리스 어플리케이션의 시나리오로 보자면, 코드가 종결되는 순간 바로 닫아지지 않는다. 이러한 경우에는 커넥션의 누수가 발생한다고 보시면 된다. (메모리나 락 같은)

만약 클라이언트 어플리케이션이나 상호작용하는 클라이언트에서 유휴 커넥션 종결 처리에 대해 만족할 수없다면 데이터베이스 서버에서는 wait_timeout이나 interactive_timeout을 설정하시어 유휴 커넥션을 탈락시키는 것도 방법.

기본적으로는 8시간으로 되어 있다.

커넥션 풀이 데이터베이스에 과도한 연결 요청을 방어하는 요소로 쓰일 수 있다는 점을 유념해야 한다.

또한 다수의 사용자가 짧은 요청을 해야하는 환경에서 커넥션을 셋업하고 제거하는 시간과 전체 커넥션의 수명주기에 대해서도 이해해야 한다. 만약에 언어나 프레임워크 차원에서 커넥션 풀을 지원하지 않는다면 커넥션 프록시를 사용하는 것을 고려해야 한다. ProxySQL, MaxScale 등..

다음과 같은 방법으로 커넥션 풀과 프록시를 설정

1.어플리케이션 커넥션 풀에서 커넥션을 획득해 올 때(borrow) 유효성(validation) 체크를 수행

단순하게는 SELECT 1 경우에 따라서는 @@innodb_read_only(반환값이 TRUE이면 replica) 같은 변수를 이용한 쿼리를 통해서 Primay instance나 Replica instance 에 따라 다른 결과를 반환하는 유효성 검사를 통해 어떤 인스턴스인지를 확인 가능

2.현재 사용하지 않는 커넥션이어도 주기적으로 유효성 체크를 수행

어플리케이션의 스레드가 문제가 있는 커넥션을 사용하기 전에 포착하고 제거할 수 있다.

3.커넥션이 풀에 무한정으로 대기하게 하지 말 것. 예를 들면 15분 간격으로 커넥션을 닫고 새로 열도록 전체적인 최대 수명을 설정해두도록. 이를 통해서 커넥션과 관련되어 묶여있던 리소스들이 구속된 상태에서 자유롭게 풀려나 반환된다. 클라이언트인 어플리케이션 영역에서 방치해버리고 마는 런어웨이 쿼리나 좀비 커넥션들로 인해 발생하는 위험한 상황들이 예방 됨. 모든 커넥션임. 유휴(Idle)가 아니라.

4.커넥션 스케일링

웹 서비스에서 가장 흔하게 가용성을 늘리는 기술은 어플리케이션 서버(인스턴스)를 늘이거나 줄임으로써 사용자 트래픽의 변화를 꾀하는 것에 있다. 각 어플리케이션 서버는 데이터베이스 커넥션 풀을 사용할 수 있음.

이러한 접근 방식은 전체 데이터베이스 커넥션의 사이즈가 어플리케이션 인스턴스에 비례하여 커지는 현상을 유발한다. 예를 들면, 20개의 어플리케이션 서버가 200개의 데이터 커넥션을 설정해 관리한다면 결국 4,000개의 데이터베이스 커넥션이 만들어진다는 의미. 만약 어플리케이션의 데이터베이스 커넥션 풀 사이즈가 200개의 인스턴스가 달라 붙게 되면 커넥션이 40,000개로 뛰어 오르게 된다. 일반적인 웹 어플리케이션의 부하로 따져 본다면, 이런 커넥션의 대부분은 유휴(idle)한 경우가 많다. 아주 극단적인 경우를 예로 들자면, 이런 상황이 데이터베이스의 확장성을 가로막게 될 수도 있다. 유휴한 커넥션들이 서버의 자원을 잡아먹으며, 필요 이상으로 막대한 커넥션을 만들게 된다. 또한 다수의 어플리케이션에서 별도로 관리하는 커넥션들이기 때문에 데이터베이스 차원에서 전체 커넥션의 총 갯수 등을 제어하기도 힘들게 된다. 이러한 상황은 어플리케이션의 수에 따라 양상이 크게 달라진다. 이럴 경우 두가지 대안이 등장하게 된다.

어플리케이션 인스턴스의 커넥션 풀을 튜닝한다. 기본적으로 풀에서 생성할 수 있는 커넥션의 갯수를 성능적으로 가용한 수준에서 최소치(가장 효율적인)로 만든다. 이를 통해 stop-gap 현상을 해결할 수 있다. 그렇지만 어플리케이션의 숫자가 계속 증가하게 될 경우 이는 일시적인 해결책에 불과하다.
데이터베이스와 어플리케이션 사이에 커넥션 프록시를 배치한다. 이를 통해 얻는 이점으로 프록시는 고정된 숫자의 연결만을 허용하게 될 것이며, 커넥션 프록시의 다양한 기능인 쿼리 캐싱, 커넥션 버퍼링, 쿼리 rewrite/routing, 로드 밸런싱 등의 혜택을 볼 수 있다. 관련 제품으로는 ProxySQL, MaxScale 등이 있다. 이를 통해 보다 나은 가용성과 확장성을 얻을 수 있다. 원하는 경우 하나의 DNS 엔드포인트에 여러개의 프록시 인스턴스를 배치할 수도 있다.

5.트랜잭션 관리(Transaction Management)와 오토커밋(Autocommit)
오토커밋이 활성화 된 상태에서 SQL구문들은 저마다 별도의 트랜잭션으로 취급된다. 그렇기에 하나의 구문이 끝나는 순간 하나의 트랜잭션이 정상적으로 종료된다. 이 트랜잭션의 시작과 종료 선언 사이에 클라이언트의 커넥션은 트랜잭션 상태에 있지 않다. 만약에 하나의 구문 처리로 끝나는 상황이 아니라면 임의로 트랜잭션임을 지정하고, 여러 구문들을 실행하고 난 뒤에 커밋하거나 롤백 처리를 해서 트랜잭션을 마무리 지어야 한다.

반대로 오토커밋을 비활성화 한 상태에서는, 언제나 커넥션은 트랜잭션 상태로 움직인다. 개발자는 커밋하거나 롤백을 현재 트랜잭션 단위로 생각할 수 있으며, 커밋하건 롤백하건 서버는 즉시 새로운 트랜잭션을 생성해 대령하게 된다.

✱ 보다 상세한 내용은 MySQL 레퍼런스 참고.

기본적으로 오토커밋을 비활성화 하는 것을 권장하지 않는다.(오토커밋을 활성화 하도록.) 대부분 오래 도는 트랜잭션이 필요하지 않기 때문. 일단 트랜잭션을 생성하는 행위는 서버의 GC 메커니즘을 차단한다. 이는 정말 중요한 서버의 성능 최적화 요소. 극단적인 경우를 예로 들자면 GC가 제대로 이뤄지지 않을 경우 무절제한 스토리지 사용과 CPU 사용률이 치솟아 쿼리 처리 자체가 느려진다.

이에 적합한 대응은 아래와 같다.

오토커밋을 활성화. 또한 어플리케이션 영역에서도 오토커밋을 활성화.(디폴트가 아닌 경우)
오토커밋 세팅에 대해 어플리케이션 영역에서 더블 체크. 라이브러리나 드라이버에 따라 종종 오토커밋이 기본이 아닌 경우가 있기 때문.
트랜잭션은 명시적으로 선언해서 처리. 쿼리의 경우 BEGIN/START TRANSACTION COMMIT/ROLLBACK 활용. 즉 필요할 때만 트랜잭션을 사용하도록.
위의 추천은 Aurora MySQL에만 국한되는 추천사항이 아님. 위의 접근 방식은 일반적인 MySQL과 InnoDB storage engine을 사용하는 다른 데이터베이스에도 해당하는 사항임.

오래도는 트랜잭션과 GC백로그 이슈는 쉽게 모니터링할 수 있음.

INFORMATION_SCHEMA.INNODB_TRX 테이블을 보면 트랜잭션이 시작된 시간을 볼 수 있다.

INFORMATION_SCHEMA.INNODB_METRICS 테이블을 보면 trx_rseg_history_len 수치를 통해 GC 사이즈를 알 수 있다.

✱ 보다 상세한 내용은 MySQL 레퍼런스 참고.

중요: Aurora에서는 모든 데이터베이스 인스턴스가 같은 스토리지 볼륨을 이용한다. 이는 GC가 전체 클러스터에서 같이 이뤄지는 것이지 개별적으로 벌어지는 현상이 아니라는 의미. 결과적으로, runaway transaction이 어떤 인스턴스에선 벌어지건 그 영향이 전체 인스턴스에 퍼져나간다는 뜻. 따라서, 오래 도는 트랜잭션은 모든 디비 인스턴스에서 면밀하게 관찰해야 한다.

6.커넥션 핸드쉐이크(Connection Handshakes)
아주 많은 일들이 어플리케이션 커넥터와 GUI 툴이 데이터베이스 세션에서 새로운 연결을 생성하는 사이에 벌어진다. 드라이버들과 클라이언트 도구들은 일반적으로 여러가지 구문(statment)를 수행하여 세션을 설정한다. (예를 들면 세션의 타임존 설정 등) 이 때문에 새로운 커넥션을 생성하고 쿼리를 수행하는데 있어 실제로 쿼리를 요청하는데 까지 지연이 발생하게 된다. 커넥션 핸드쉐이크라 칭해지는 상황에서 발생하는 응답성이 매우 민감하게 취급되는 서비스의 경우에는 매우 중요한 문제로 취급된다. OLTP나 Key-Value 형태의 워크로드에서는 한자리수의 밀리세컨드 단위에서 발생하는 지연들이 서비스에 영향을 줄 수도 있다. 예를 들면 커넥션을 생성하는데 1밀리 세컨드를 소요하는데 맺어지기까지 여섯단계의 통신이 필요한 경우에는, 최초 쿼리를 처리하는데까지 최소 6밀리 세컨드의 지연이 발생하게 되는 식.

이에 적합한 대응은 다음과 같다.

Aurora MySQL의 Advanced Audit을 활용하거나 일반적인 쿼리로그, 네트워크 레벨 패킷 트레이스 등 커넥션 핸드쉐이크 단계에 발생하는 로그를 수집해 둬야 한다. 커넥션 응답성(latency) 이슈를 접하기 이전에 이미 데이터베이스 드라이버의 동작원리가 익숙한 상황이어야 하기 때문.
각 핸드쉐이크 단계별로, 단계 별로 갖는 의미와 이것들이 쿼리들에게 미치는 영향에 대해서 인지하고 있어야 한다.
각 핸드쉐이크 구문은 최소 하나의 네트워크 왕복이 발생하며, 이는 전체 세션 지연시간의 증가를 불러옵니다. 이 과정에서 작업을 실제로 수행하는 구문의 수를 식별해보고 이 중에서 줄일 수 있는 핸드 쉐이크 단계가 있다면 줄여보는 것을 고려해보는 것도 좋다. 커넥션 핸드 쉐이크 과정을 줄이기 위해 커넥션 풀을 사용하는 것을 고려해야 함.

7.Reader Endpoint 기준의 로드 밸런싱

읽기(Reader) 엔드포인트는 Aurora의 모든 Replica를 포함하고 있다. 이는 DNS 기반의 라운드 로빈 정책으로 새로운 커넥션을 생성함. 매 번 읽기 엔드포인트에서 인스턴스의 IP를 연결을 할 때 마다 라운드 로빈 방식으로 획득하는 식.

DNS 로드 밸런싱은 커넥션 레벨에서 이뤄진다(개별 쿼리 레벨이 아님). 이 때문에 DNS 정보를 절대로 캐싱해서는 안 된다. 만약에 DNS 정보를 캐싱하는 경우 실제로 대상이 변경되었음에도 동일한 IP를 호출하는 일이 벌어지게 된다.

위의 가이드를 따르지 않을 경우 아래와 같은 이슈가 발생할 수 있다.

불균등한 레플리카 호출. 특정 레플리카 인스턴스에 부하가 집중된다.
Aurora 레플리카를 더하거나 스케일 할 경우 트래픽을 받을 수 없거나 오랜 지연 끝에 받을 수 있게 된다.
Aurora 레플리카를 제거할 경우에 제거된 인스턴스에 여전히 트래픽 전달 시도.
✱기타 자세한 내용은DNS Endpoints, DNS Caching 참고

8.결함 허용(Fault Tolerance)과 빠른 복구(Quick Recovery) 디자인
대규모의 데이터베이스 운용에 있어서, 커넥션 인터럽션과 하드웨어 문제는 통계적으로 드문 일이 아니다. 또한 수시로 운영상의 이유로 데이터베이스 인스턴스를 더하거나 빼거나 스케일링하거나 소프트웨어 업그레이드를 수행해야 한다.

이런 의도되거나 의도되자 않은 변화나 이슈는 계속해서 발생하기에 어플리케이션 디자인 영역에서 꾸준하고 알맞게 고려해야 하는 부분이다.

예시

Aurora MySQL에서 Primary Instance의 문제르 ㄹ식별하면 새로운 Instance가 Primary로 승격. 이는 보통 30초 사이에 벌어짐. 따라서 어플리케이션은 이 변화를 인지하는 시간을 수동으로 알릴 필요 없이 자동으로 눈치 챌 수 있어야 한다.
만약 새로운 레플리카를 Aurora DB 클러스터 상에 새로 만들게 된다면, 이를 어플리케이션이 스스로 알고 요청할 수 있어야 한다.
만약 인스턴스를 DB 클러스터에서 제거하면 어플리케이션이 제거된 인스턴스와 통신을 시도해 선 안된다.
어플리케이션을 광범위하게 테스트하여 어플리케이션이 데이터베이스의 변화에 어떻게 대응하는지 가정이 아니라 관측된 결과로 목록화 하여 관리해야한다.

만약 베스트 프랙티스를 따르지 않을 경우, 데이터베이스에서 발생하는 변화(failover 등)로 인해 예상 보다 훨씬 큰 다운타임을 겪을 수 있다. 가령, 위에 언급한 failover가 데이터베이스 클러스터 영역에서 30초라지만 어플리케이션 영역까지 고려하면 더 오래 걸리는 것을 알 수 있다.

9.서버 설정
서버 설정 변수 중에 매우 중요한 것 max_connections 와 max_connect_error

max_connection 변수 다루기

이 변수는 Aurora DB 인스턴스 별로 다룰 수 있는 최대 연결의 수를 의미한다. 베스트 프랙티스는 하나의 인스턴스가 처리하길 기대하는 최대값보다 살짝 높게 해주는 것을 권하고 있다. 또한 performacne_schema를 활성화 시킨 상태에서는 이 변수를 조정 할 때 세심한 주의가 필요하다. 이 성능 스키마(perormance schema)의 메모리 구조는 자동으로 서버의 환경 변수에 의해 결정지어지는데 그 중에 하나가 max_connection. 이 변수가 크게 잡힐 수록 성능 스키마가 사용하는 메모리 역시 커지는 구조이다. 그렇기에 극단적인 경우를 예로 들면 작은 인스턴스 구조에 무리하게 최대 연결을 크게 줄 경우는 메모리 부족이 발생한다.

T2, T3 인스턴스 유형에서의 주의사항

T2, T3 인스턴스에서 8GB 이하의 메모리를 사용하는 경우에는 performance schema 사용을 권하지 않는다. 메모리 부족 이슈를 회피하기 위해서 T2, T3 인스턴스에서는 아래 가이드를 따라야 함.

성능 스키마(performance schema)를 쓰지 말 것.
반드시 써야 한다면 max_connection을 기본 값으로 둘 것
만약 max_connection을 증가시켜야 하면 그 전에 성능 스키마를 비활성화 할 것

max_connect_errors 다루기

max_connect_errors는 특정 클라이언트의 호스트가 데이터베이스로 요청하는 횟수가 성공보다 실패가 많을 경우 차단을 하게 끔 할 수 있다. 이럴 경우 아래와 같은 메시지가 클라이언트 쪽으로 전달 된다.

Host 'host_name' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'

일반적으로 이 이슈를 회피하는 가장 쉽지만(틀린) 방법은 해당 값을 매우 크게 줘서 발생하지 않게 하는 식.

그렇지만 이 방법은 아래와 같은 이유로 추천하지 않는다.

커넥션 이슈는 어플리케이션의 상태에 지대한 영향을 미친다. 이런 중대한 문제는 무시되는게 아니라 관리하고 해결되어야 한다.
정말 위험한 침해 시도를 놓칠 수 있다. 예: 반복적인 서버 침해 시도
만약 서버에서 host is blocked 같은 메시지를 받는다면, 값을 늘리는 것은 올바른 대응이 아니다. 대신에 aborted_connects 상태와 host_cache 테이블을 참조해야 한다. 이 정보를 이용하여 클라이언트의 문제를 식별하고 커넥션 이슈를 조치할 수 있게 해야 한다. 또한 skip_name_resolve 값이 기본값인 1로 되어 있다면 max_connect_errors라는 값이 무시된다는 사실도 주의깊게 이해하고 있어야 한다.