Spring Boot 통합 Druid 에 이상 신고 가 발생 한 원인 및 해결

Spring Boot 통합 Druid 이상
Spring Boot 통합 Druid 프로젝트 에서 오류 로그 에서 다음 과 같은 오류 정보 가 자주 발생 합 니 다.

discard long time none received connection. , jdbcUrl : jdbc:mysql://******?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8, version : 1.2.3, lastPacketReceivedIdleMillis : 172675
조사 결과 Druid 버 전 으로 인 한 이상 이 발 견 됐 으 며 1.2.2 및 이전 버 전에 서 는 이러한 이상 이 나타 나 지 않 았 다.상기 버 전에 서 모두 이 문제 가 존재 하 므 로 이상 원인 과 해결 방안 을 분석 하 겠 습 니 다.
이상 분석
우선 위의 이상 은 프로그램의 정상 적 인 운행 에 영향 을 주지 않 지만 프로그래머 로 서 프로그램 에서 끊임없이 이상 이 발생 하 는 것 을 보면 참 기 어렵다.그 러 니까 꼬치 꼬치 캐 서 해결 해 야 지.
스 택 정 보 를 추적 하면 해당 하 는 이상 이 com.alibaba.druid.pool.druidAbstractDataSource\#testconnection Internal 방법 에서 나 온 것 을 발견 할 수 있 습 니 다.해당 하 는 코드 는 다음 과 같 습 니 다.

if (valid && isMySql) { // unexcepted branch
    long lastPacketReceivedTimeMs = MySqlUtils.getLastPacketReceivedTimeMs(conn);
    if (lastPacketReceivedTimeMs > 0) {
        long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs;
        if (lastPacketReceivedTimeMs > 0 //
                && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) {
            discardConnection(holder);
            String errorMsg = "discard long time none received connection. "
                    + ", jdbcUrl : " + jdbcUrl
                    + ", jdbcUrl : " + jdbcUrl
                    + ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis;
            LOG.error(errorMsg);
            return false;
        }
    }
}
상기 코드 에서 MySqlUtils.getLastPacket ReceivedTimeMs(conn)는 지난번 에 사 용 된 시간 을 얻 는 것 이 고,mysql IdleMillis 는 남 은 시간 을 계산 하 는 것 이 며,timeBetweenEvictionRunsMillis 는 상수 60 초 입 니 다.연결 이 60 초 이상 비어 있 으 면 discardConnection(holder)은 이 오래된 연결 을 버 리 고 로그 LOG.warn(errorMsg)을 인쇄 합 니 다.
원리 추적
상기 코드 에서 우 리 는 이 업무 논리 에 들 어 가 는 것 이 전제조건 이 있 는 것 을 보 았 다.즉,valid 와 isMySql 변 수 는 동시에 true 이다.isMySql 은 true 가 필요 합 니 다.우리 가 사용 하 는 것 자체 가 Mysql 데이터베이스 입 니 다.그럼 valid 를 false 로 할 수 있 을까요?이렇게 하면 이 업무 처리 에 들 어가 지 않 을 것 입 니까?
valid 의 출처 를 보 시 겠 습 니까?아니면 이 방법 위 에 있 습 니까?

boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);

validConnectionChecker 의 Mysql 구현 하위 클래스 MySqlValidConnectionChecker 를 찾 았 습 니 다.이 클래스 에서 isValidConnection 에 대한 실현 은 다음 과 같 습 니 다.

public boolean isValidConnection(Connection conn, String validateQuery, int validationQueryTimeout) throws Exception {
    if (conn.isClosed()) {
        return false;
    }

    if (usePingMethod) {
        if (conn instanceof DruidPooledConnection) {
            conn = ((DruidPooledConnection) conn).getConnection();
        }

        if (conn instanceof ConnectionProxy) {
            conn = ((ConnectionProxy) conn).getRawObject();
        }

        if (clazz.isAssignableFrom(conn.getClass())) {
            if (validationQueryTimeout <= 0) {
                validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT;
            }

            try {
                ping.invoke(conn, true, validationQueryTimeout * 1000);
            } catch (InvocationTargetException e) {
                Throwable cause = e.getCause();
                if (cause instanceof SQLException) {
                    throw (SQLException) cause;
                }
                throw e;
            }
            return true;
        }
    }

    String query = validateQuery;
    if (validateQuery == null || validateQuery.isEmpty()) {
        query = DEFAULT_VALIDATION_QUERY;
    }

    Statement stmt = null;
    ResultSet rs = null;
    try {
        stmt = conn.createStatement();
        if (validationQueryTimeout > 0) {
            stmt.setQueryTimeout(validationQueryTimeout);
        }
        rs = stmt.executeQuery(query);
        return true;
    } finally {
        JdbcUtils.close(rs);
        JdbcUtils.close(stmt);
    }

}
우 리 는 상술 한 방법 중 세 가지 가 되 돌아 오 는 곳 을 볼 수 있다.첫 번 째 연결 은 이미 닫 혔 다.두 번 째 는 ping 의 형식 으로 검 사 를 한다.셋째,select 1 방식 으로 검 사 를 한다.핑 형식 검 사 를 사용 할 때 이상 을 던 지 든 말 든 true 로 돌아 갑 니 다.여기 서 우 리 는 이 모드 를 사용 하지 않 으 면 된다.
ping 에 들 어간 업무 논 리 는 주로 변수 usePingMethod 에 의 해 판단 되 고 추적 코드 는 여기 서 진행 되 는 설정 을 발견 할 수 있 습 니 다.

public void configFromProperties(Properties properties) {
    String property = properties.getProperty("druid.mysql.usePingMethod");
    if ("true".equals(property)) {
        setUsePingMethod(true);
    } else if ("false".equals(property)) {
        setUsePingMethod(false);
    }
}
그러면 시스템 속성 druid.mysql.usePingMethod 를 false 로 설정 하면 이 기능 을 사용 하지 않 을 수 있 습 니 다.
Ping Method 사용 하지 않 기
문제 의 근원 을 찾 았 다 면 나머지 는 어떻게 사용 하지 않 느 냐 하 는 것 이다.보통 세 가지 형식 이 있다.
첫째,프로그램 을 시작 할 때 실행 매개 변수 에 추가 합 니 다:-Druid.mysql.usePingMethod=false.
둘째,Spring Boot 프로젝트 에서 시작 클래스 에 다음 과 같은 정적 코드 를 추가 할 수 있 습 니 다.

static {
    System.setProperty("druid.mysql.usePingMethod","false");
}
셋째,클래스 파일 설정.프로젝트 의 DruidConfig 클래스 에 새로 추가:

/*
*   druid     :discard long time none received connection:xxx
* */
@PostConstruct
public void setProperties(){
    System.setProperty("druid.mysql.usePingMethod","false");
}
이로써 이 기능 을 성공 적 으로 닫 을 수 있 고 이상 정 보 는 다 시 는 나타 나 지 않 을 것 이다.
왜 60 초 이상 남 은 연결 을 비 워 야 합 니까?
알 리 가 데이터베이스 에 설정 한 데이터베이스 에 남 은 대기 시간 은 60 초 이 며,my sql 데이터 베 이 스 는 남 은 대기 시간 이 되면 남 은 연결 을 닫 아 데이터베이스 서버 의 처리 능력 을 향상 시 킬 것 으로 예상 된다.
MySQL 의 기본 남 은 대기 시간 은 8 시간 입 니 다.바로"wait"입 니 다.timeout 의 설정 값 입 니 다.데이터 베 이 스 를 자발적으로 닫 으 면 연결 탱크 가 모 르 고 이 연결 을 사용 하면 이상 이 생 길 수 있 습 니 다.
이상 은 Spring Boot 통합 Druid 에 이상 보고 가 발생 한 원인 및 해결 에 대한 상세 한 내용 입 니 다.Spring Boot 통합 Druid 에 이상 이 발생 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기