MySQL Connection.isValid() 최적화

2026. 3. 30. 22:44·IT 지식
728x90
반응형

HikariCP에서 Connection.isValid() 이 실행되는 시점

커넥션 풀에서 커넥션을 꺼낼 때
정확히는 두 가지 시점이 있습니다:

시점 조건 설명
커넥션 획득 시 항상 getConnection() 호출 시 풀에서 꺼낸 커넥션이 유효한지 검증
유휴 커넥션 검사 keepaliveTime 설정 시 풀에 놀고 있는 커넥션을 주기적으로 검증 (기본값: 0 = 비활성)

즉, 애플리케이션에서 DB 요청할 때마다 SELECT 1 → 실제 쿼리 이렇게 매번 2개의 쿼리가 나가고 있었던 상황.
COM_PING으로 전환하면 이 검증이 SQL 파서를 거치지 않는 프로토콜 명령으로 대체된다.

참고로 HikariCP 설정 중 관련된 것들:

설정 기본값 역할
connectionTestQuery 없음 (JDBC4 isValid 사용) 커넥션 유효성 검증 쿼리
validationTimeout 5000ms 검증 타임아웃
keepaliveTime 0 (비활성) 유휴 커넥션 주기적 검증 간격

connectionTestQuery가 실행되는 시점

상황 connectionTestQuery 설정됨 connectionTestQuery 미설정
getConnection() 호출 시 SELECT 1 실행 isValid() → COM_PING
유휴 커넥션 주기 검사 (keepaliveTime > 0) SELECT 1 실행 isValid() → COM_PING
유휴 커넥션 주기 검사 (keepaliveTime = 0) 검사 안 함 검사 안 함

keepaliveTime이 0이든 아니든, getConnection() 할 때마다 커넥션 유효성 검증은 항상 실행됩니다.
connectionTestQuery가 설정되어 있으면 매번 SELECT 1이 나가고, 미설정이면 COM_PING이 나가는 구조입니다.


HikariCP 헬스체크 전환: SELECT 1 → COM_PING

배경

기존에 HikariCP의 connectionTestQuery("SELECT 1")을 사용하여 커넥션 유효성을 검증하고 있었다.
이 방식은 커넥션 풀에서 커넥션을 꺼낼 때마다 SELECT 1 쿼리를 DB에 실행하므로, 불필요한 DB 조회 부하가 발생한다.

조사 결과, HikariCP는 JDBC4 드라이버 사용 시 connectionTestQuery를 설정하지 않으면
Connection.isValid()를 호출하고, MySQL Connector/J는 이를 내부적으로 COM_PING 프로토콜 명령으로 처리한다.
COM_PING은 SQL 쿼리가 아닌 MySQL 프로토콜 레벨의 경량 명령(1바이트)으로, SELECT 1 대비 오버헤드가 적다.

변경 내용

변경 사항

connectionTestQuery("SELECT 1") 설정을 제거(주석 처리)하여
HikariCP 기본 동작인 JDBC4 Connection.isValid() → COM_PING 방식으로 전환했다.

// Before
hikariConfig.setConnectionTestQuery("SELECT 1");

// After (제거)
// hikariConfig.setConnectionTestQuery("SELECT 1");

동작 원리

항목 SELECT 1 방식 COM_PING 방식
설정 connectionTestQuery("SELECT 1") 설정 없음 (기본값)
동작 SQL 쿼리 실행 MySQL 프로토콜 명령 (0x0e)
패킷 크기 수십 바이트 (SQL 문자열) 5바이트 (헤더 4 + 명령 1)
DB 파서 SQL 파서 경유 프로토콜 레벨 처리
HikariCP 조건 JDBC4 미지원 드라이버용 JDBC4 드라이버 사용 시 기본값

환경 정보

  • HikariCP: Spring Boot 내장
  • MySQL Connector/J: 8.0.33 (JDBC4 지원)
  • MySQL: 8.0.42 (AWS RDS)

검증

1단계: profileSQL 로그를 통한 간접 검증

JDBC URL에 profileSQL=true를 추가하면 MySQL Connector/J가 실행하는 모든 SQL을 stderr로 출력한다.

  • connectionTestQuery("SELECT 1") 설정 시 → 로그에 SELECT 1 출력됨
  • connectionTestQuery 미설정 시 → 로그에 SELECT 1 미출력 (SQL이 아닌 COM_PING 사용)

테스트 코드:
connector/src/test/java/com/eximbay/datasource/HikariConnectionHealthCheckTest.java

2단계: tcpdump + Wireshark를 통한 직접 검증

네트워크 패킷 캡처로 COM_PING (0x0e) 패킷이 실제로 전송되는 것을 확인했다.

tcpdump 캡처

# 패킷 캡처 (en0 인터페이스, RDS 포트 지정)
sudo tcpdump -i en0 port 23306 -w /tmp/mysql_comping.pcap

# 별도 터미널에서 테스트 실행
./gradlew :connector:test --tests "com.eximbay.datasource.HikariConnectionHealthCheckTest.withoutTestQuery_logDoesNotContainSelect1"

# Ctrl+C로 캡처 중지

tcpdump 분석

# 클라이언트→서버 방향, length 5 패킷의 MySQL command byte 확인
tcpdump -r /tmp/mysql_comping.pcap -nn -X 'src {클라이언트IP} and dst port 23306' | grep -B2 -A4 "length 5"

MySQL 프로토콜 패킷 구조 (5바이트):

01 00 00 00 0e
│        │  └─ command byte: 0x0e = COM_PING (14)
│        └──── sequence id: 0
└───────────── payload length: 1

캡처 결과:

⚪ COM_QUIT (0x01): 커넥션 종료
🔵 COM_PING (0x0e): isValid() → COM_PING 호출 확인
🔵 COM_PING (0x0e): isValid() → COM_PING 호출 확인
⚪ COM_QUIT (0x01): 커넥션 종료

Wireshark 확인

  1. .pcap 파일을 Wireshark에서 열기
  2. 비표준 포트이므로 Analyze → Decode As...에서 TCP port 23306을 MySQL로 설정
  3. Display Filter에 mysql.command == 14 입력
  4. COM_PING 패킷만 필터링되어 표시됨

mysql.command == 14는 Wireshark가 패킷 바이너리를 MySQL 프로토콜 규격으로 파싱한 내부 필드를 기준으로 필터링한다.
화면에 보이는 텍스트 검색이 아니라, 디코딩된 프로토콜 필드 값으로 매칭한다.

참고 필터:

필터 설명
mysql.command == 14 COM_PING
mysql.command == 1 COM_QUIT
mysql.command == 3 COM_QUERY (SELECT 등)

결론

connectionTestQuery("SELECT 1") 제거만으로 HikariCP가 자동으로 COM_PING 기반 헬스체크로 전환되며,
profileSQL 로그와 네트워크 패킷 캡처 양쪽에서 이를 검증 완료했다.


SELECT 1 검증 쿼리 확인 방법

운영 중인 MySQL에서 SELECT 1 헬스체크가 실제로 얼마나 실행되고 있는지 쿼리로 확인할 수 있다.

Com_select 카운터 확인

-- SELECT 문 실행 횟수 (서버 시작 이후 누적)
SHOW GLOBAL STATUS LIKE 'Com_select';

connectionTestQuery("SELECT 1") 제거 전후로 이 값의 증가 속도를 비교하면 효과를 확인할 수 있다.

일정 시간 동안 SELECT 1 발생량 측정

-- 1) 현재 값 기록
SELECT VARIABLE_VALUE INTO @before
FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Com_select';

-- 2) 일정 시간 대기 (예: 10초)
DO SLEEP(10);

-- 3) 차이 계산
SELECT VARIABLE_VALUE - @before AS select_count_in_10s
FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Com_select';

General Log로 SELECT 1 직접 확인

-- General Log 활성화 (운영 환경에서는 짧은 시간만 사용)
SET GLOBAL general_log = 'ON';
SET GLOBAL log_output = 'TABLE';

-- 일정 시간 후 SELECT 1 쿼리 확인
SELECT event_time, command_type, argument
FROM mysql.general_log
WHERE argument LIKE 'SELECT 1%'
ORDER BY event_time DESC
LIMIT 20;

-- General Log 비활성화
SET GLOBAL general_log = 'OFF';

General Log는 모든 쿼리를 기록하므로 성능에 영향을 준다.
운영 환경에서는 짧은 시간만 활성화하고 반드시 끌 것.

Performance Schema로 확인

-- SELECT 1 쿼리의 실행 통계 확인
SELECT DIGEST_TEXT, COUNT_STAR, AVG_TIMER_WAIT/1000000000 AS avg_ms
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT LIKE 'SELECT ?%'
ORDER BY COUNT_STAR DESC
LIMIT 10;

SELECT ?는 MySQL이 SELECT 1을 정규화한 형태다.
COUNT_STAR가 커넥션 풀 크기 × 요청 수에 비례하면 헬스체크 쿼리일 가능성이 높다.


참고

  • HikariCP 공식 문서 — JDBC4 드라이버 사용 시 connectionTestQuery 설정하지 않을 것을 권장
    https://github.com/brettwooldridge/HikariCP#frequently-used
728x90
반응형
저작자표시 비영리 (새창열림)

'IT 지식' 카테고리의 다른 글

한글이 왜 깨질까? 캐릭터셋과 인코딩에 대해서 알아보자  (1) 2025.09.28
macOS에서 계정명(short name) 변경하기 - Sequoia 15.1 경험 정리  (0) 2025.09.21
[맥북] 한영키 변환 속도 개선  (0) 2025.06.17
[PC/문제해결] Windows 10 AMD Radeon HD 4000 모니터 화면 버그  (0) 2022.04.02
[IT 지식] 소프트웨어 아키텍트 역할군 ( AA, TA, DA, BA ??? )  (0) 2022.01.20
'IT 지식' 카테고리의 다른 글
  • 한글이 왜 깨질까? 캐릭터셋과 인코딩에 대해서 알아보자
  • macOS에서 계정명(short name) 변경하기 - Sequoia 15.1 경험 정리
  • [맥북] 한영키 변환 속도 개선
  • [PC/문제해결] Windows 10 AMD Radeon HD 4000 모니터 화면 버그
크크크크
크크크크
공뷰를 합시다.
    반응형
  • 크크크크
    Tom's Note
    크크크크
  • 전체
    오늘
    어제
    • 분류 전체보기 (131)
      • IT 지식 (7)
      • CS (66)
        • 알고리즘 & 자료구조 (19)
        • 운영체제 (41)
        • 네트워크 (1)
        • 데이터베이스 (5)
      • 보안 (6)
      • SW 공학 & 프로그래밍 언어 (5)
        • Java (28)
        • 디자인 패턴 (1)
        • 형상관리 (2)
        • 톰캣(WAS) (2)
        • SW 방법론 (3)
        • 스프링부트 (5)
      • 시스템 설계 (4)
        • Docker (2)
      • 자격증 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      su
      usermod
      문제해결
      java
      DTO
      apropos
      cifs
      DI
      알고리즘
      2차
      리눅스
      man
      which
      Chage
      단반향
      whereis
      비트연산
      스프링부트
      docker
      whatis
      1급
      암호설정
      분석기법
      passwd
      ADsP
      REST API
      chmod
      /etc/passwd
      자바
      불변
    • 최근 댓글

    • 최근 글

    • 250x250
    • hELLO· Designed By정상우.v4.10.3
    크크크크
    MySQL Connection.isValid() 최적화
    상단으로

    티스토리툴바