본문 바로가기
Database/MySQL

MySQL Timeout Error: The client was disconnected by the server because of inactivity

by Dev_카페인 2024. 11. 25.
반응형

MySQL Timeout Error: The client was disconnected by the server because of inactivity

MySQL을 사용할 때 다음과 같은 에러를 본 적이 있을 것입니다:

The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.

이 에러는 클라이언트가 MySQL 서버에 연결된 후 일정 시간 동안 아무 작업도 수행하지 않을 경우 서버가 연결을 종료하면서 발생합니다. 이번 포스트에서는 이 에러의 원인, 해결 방법, 그리고 관련된 코드 최적화 방법을 소개합니다.


1. 에러 원인

MySQL 서버는 연결된 클라이언트가 일정 시간 동안 활동하지 않으면 연결을 자동으로 종료합니다. 이는 서버의 리소스를 절약하기 위한 정책입니다. 이 동작은 아래 두 가지 시스템 변수에 의해 제어됩니다:

  • wait_timeout: 비인터랙티브 클라이언트 연결에 적용되는 타임아웃(기본값: 28800초, 약 8시간)
  • interactive_timeout: MySQL 콘솔과 같은 인터랙티브 클라이언트에 적용되는 타임아웃(기본값: 28800초, 약 8시간)

문제는 MySQL 연결을 열었지만 명시적으로 닫지 않은 경우 발생할 수 있습니다. 연결이 장시간 유지되면 서버는 이를 비활성 연결로 간주하고 종료합니다.


2. 문제 상황 분석

제가 겪은 문제는 MySQL 연결을 열고 나서 명시적으로 닫지 않아서 발생했습니다. MySQL의 기본 타임아웃이 8시간으로 설정되어 있음을 확인했고, 이를 더 짧은 단위(30초)로 줄여서 재현했습니다.

다음과 같은 여러 상황에서 이 문제가 발생할 수 있습니다:

  1. MySqlCommand를 사용할 때: MySqlCommand를 생성한 후 연결을 유지한 채 닫지 않는 경우.
  2. 데이터베이스 연결 관리 미흡: 연결 풀링(Connection Pooling)을 사용하지 않거나, using 키워드를 사용해 자동으로 자원을 정리하지 않은 경우.
  3. 장시간 연결 유지: 서버와 클라이언트 간 작업이 없어서 타임아웃 초과.

3. 해결 방안

(1) 타임아웃 시간 조정

타임아웃 시간을 늘리거나 줄이는 방법으로 문제를 해결할 수 있습니다. 다음 명령어를 통해 타임아웃을 설정합니다:

SET GLOBAL wait_timeout = 60; -- 비인터랙티브 연결 타임아웃 60초로 설정
SET GLOBAL interactive_timeout = 60; -- 인터랙티브 연결 타임아웃 60초로 설정

타임아웃 설정을 변경하면 다음과 같은 사항을 고려해야 합니다:

  • 서버 자원 관리: 타임아웃을 너무 길게 설정하면 비활성 연결이 서버 리소스를 낭비할 수 있습니다.
  • 연결 사용 패턴에 맞는 설정: 클라이언트가 자주 재연결을 해야 한다면 타임아웃 시간을 적절히 늘리는 것이 유리합니다.

(2) 코드에서 연결 명시적으로 종료하기

MySQL 연결을 사용하는 코드에서는 반드시 연결을 명시적으로 종료해야 합니다. 이를 위해 using 키워드를 사용하는 것을 추천합니다. using은 객체를 사용 후 자동으로 자원을 정리해줍니다.

개선 전 코드

MySqlConnection conn = new MySqlConnection(connectionString);
conn.Open();

MySqlCommand cmd = new MySqlCommand("SELECT * FROM Users", conn);
var reader = cmd.ExecuteReader();
// 연결을 명시적으로 닫지 않음

개선 후 코드

using (MySqlConnection conn = new MySqlConnection(connectionString))
{
    conn.Open();
    using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM Users", conn))
    {
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // 데이터 처리
            }
        }
    }
} // conn.Dispose()가 호출되어 연결 자동 종료

using 블록을 사용하면 연결이 자동으로 닫히고, Dispose 메서드가 호출되어 자원이 올바르게 해제됩니다.


(3) 연결 풀링(Connection Pooling) 사용

MySQL은 기본적으로 연결 풀링(Connection Pooling)을 지원합니다. 연결을 자주 여닫는 경우 연결 풀링을 사용하면 성능이 향상되고, 타임아웃 문제를 완화할 수 있습니다.

ConnectionString에 연결 풀링 옵션을 추가합니다:

"Server=localhost;Database=test;Uid=root;Pwd=1234;Pooling=true;Min Pool Size=0;Max Pool Size=100;"


4. 테스트 및 확인

타임아웃 설정을 변경한 후 아래와 같은 단계를 통해 문제 해결 여부를 확인했습니다:

  1. 타임아웃을 30초로 설정.
  2. MySQL 연결을 유지한 채 명령 실행 없이 대기.
  3. using 블록과 연결 풀링 적용 여부를 비교 테스트.

타임아웃 문제는 연결 종료를 명확히 처리함으로써 해결되었습니다.


5. 요약

  • 에러 원인: MySQL 연결이 비활성 상태로 일정 시간이 경과되었을 때 서버가 연결을 종료.
  • 해결 방법:
    • 타임아웃 설정 조정 (wait_timeout, interactive_timeout).
    • using 키워드를 사용하여 연결을 명시적으로 종료.
    • 연결 풀링(Connection Pooling) 활용.
  • 코드에서의 교훈: 명확한 리소스 관리와 자동화된 종료 처리 방식이 중요.

이 포스트가 비슷한 문제를 겪는 분들에게 도움이 되길 바랍니다! 추가 질문은 언제든 환영입니다. 😊

 

 

 

반응형