[트러블슈팅 - DB] 발생할 수 있는 에러를 정리해보자

Hocaron·2023년 4월 30일
0

트러블슈팅

목록 보기
4/12
post-custom-banner

wait_timeout(활동하지 않는 커넥션을 끊을때까지 서버가 대기하는 시간) 관련

hikariPool - Failed to validate connection org.mariadb.jdbc.MariaDbConnection@7aa2f8a6 ((conn=463456) Connection.setNetworkTimeout cannot be called on a closed connection). Possibly consider using a shorter maxLifetime value.
  1. DB는 idle 상태의 커넥션을 wait_timeout이 지나면 연결을 종료한다.
  2. 스프링 서버는 idle 상태의 커넥션을 max-lifetime이 지나면 연결을 끊고 새로운 커넥션을 생성한다.
  • max-lifetime이 wait_timeout보다 짧아야 RDS가 커넥션을 끊기 전에 스프링 서버 스스로 연결을 끊고 새로운 커넥션을 맺기 때문에 문제가 발생하지 않는다.

어디서 나는 에러일까?

package com.zaxxer.hikari.pool;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.SQLExceptionOverride;
import com.zaxxer.hikari.metrics.IMetricsTracker;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
import com.zaxxer.hikari.util.DriverDataSource;
import com.zaxxer.hikari.util.PropertyElf;
import com.zaxxer.hikari.util.UtilityElf;
import com.zaxxer.hikari.util.UtilityElf.DefaultThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

abstract class PoolBase {
   boolean isConnectionDead(final Connection connection)
   {
      try {
         try {
            setNetworkTimeout(connection, validationTimeout);

            final var validationSeconds = (int) Math.max(1000L, validationTimeout) / 1000;

            if (isUseJdbc4Validation) {
               return !connection.isValid(validationSeconds);
            }

            try (var statement = connection.createStatement()) {
               if (isNetworkTimeoutSupported != TRUE) {
                  setQueryTimeout(statement, validationSeconds);
               }

               statement.execute(config.getConnectionTestQuery());
            }
         }
         finally {
            setNetworkTimeout(connection, networkTimeout);

            if (isIsolateInternalQueries && !isAutoCommit) {
               connection.rollback();
            }
         }

         return false;
      }
      catch (Exception e) {
         lastConnectionFailure.set(e);
         logger.warn("{} - Failed to validate connection {} ({}). Possibly consider using a shorter maxLifetime value.",
                     poolName, connection, e.getMessage());
         return true;
      }
   }
...

해결방법

스프링에서 다음과 설정을 추가하면 경고 로그는 없어진다.

spring:
  datasource:
    hikari:
      max-lifetime: 177000 # 177초, hikari는 RDS wait_timeout 보다 2 ~ 3초 정도 짧게 줄 것을 권장

hikari CP는 네트워크 지연을 고려하여 max-lifetime을 wait_timeout보다 2~3초 정도 짧게 줄 것을 권고한다.

또는 DB의 wait_timeout 설정을 max-lifetime 보다 길게 설정해줄 수도 있다.

DB의 wait_timeout을 어떻게 확인할 수 있을까?

  • MySQL
mysql> SHOW GLOBAL VARIABLES LIKE 'wait_timeout';
Variable_nameValue
wait_timeout1830
  • Oracle
SQL>
select PROFILE
     , RESOURCE_NAME
     , RESOURCE_TYPE
     , LIMIT
     , COMMON
from dba_profiles
where profile = 'DEFAULT'
order by 1,2;
PROFILERESOURCE_NAMERESOURCELIMIT
DEFAULTIDLE_TIMEKERNEL15
profile
기록을 통한 성장을
post-custom-banner

0개의 댓글