[yoonnsshop] Database Connection Pool

yoonn·2024년 7월 9일

yoonnsshop

목록 보기
6/7
post-thumbnail

Intro

대규모 애플리케이션에서 데이터베이스 연결 관리는 성능과 안정성에 크리티컬한 영향을 미칩니다. 이번 포스팅에서는 yoonnsshop의 대량의 상품 데이터에서의 조회 트래픽 급증 상황에서 발생한 데이터베이스 성능 문제를 다룹니다. 특히 HikariCP 라이브러리를 사용한 Database Connection Pool의 최적화가 어떻게 이러한 문제를 해결할 수 있는지 탐구합니다. 이 과정에서 Connection Pool 크기 설정과 MySQL 서버 설정을 조정하며 성능 변화를 측정하고 분석했습니다. 이를 통해 Connection Pool 최적화의 복잡성과 중요성을 이해하고, 실제 운영 환경에서의 효과적인 대처 방법을 모색하고자 합니다.

Database Connection Pool?

Database Connection Pool은 데이터베이스 연결을 효율적으로 관리하기 위한 기술입니다. 이는 미리 일정 수의 데이터베이스 연결을 생성하고 유지하며, 애플리케이션의 요청에 따라 이를 재사용합니다.
이를 통해 연결 생성 및 해제에 따른 오버헤드를 줄이고, 리소스 사용을 최적화하며, 애플리케이션의 성능과 확장성을 향상시킵니다.


Scenario

*Contents
TitleDatabse Connection Pool 최적화
Trigger상품 데이터 대량 삽입 후 조회 트래픽 급증
Problem데이터베이스 처리 시간 증가로 인한 성능 저하
ActionDatabase Connection Pool 관련 설정 조정
Benefit커넥션 재사용을 통해 커넥션 생성/해제 오버헤드 감소 및 처리량 향상

Validation

HikariCP Monitoring Setup

HikariCP?

  • HikariCP는 실제 운영 환경에서 zero-overhead를 지원하는 JDBC Connectino Pool
  • HikariCP는 Spring Boot 2.0부터 기본 Connection Pool로 채택되었음.

HikariCP 주요 설정

  • 본 실험에서는 HikariCP의 여러 설정 중 주로 maximum-pool-size에 초점을 맞추었습니다. 이 설정은 커넥션 풀의 최대 크기를 결정하는 파라미터입니다.
  • 어플리케이션에서 사용하는 maximum-pool-size 기본값은 10입니다.

HikariCP는 이 외에도 다양한 설정 옵션을 제공하여 커넥션 풀의 동작을 세밀하게 제어할 수 있습니다. 예를 들어, 최소 유휴 커넥션 수, 유휴 커넥션의 최대 생존 시간, 커넥션 타임아웃 등을 설정할 수 있습니다. 실제로 운영 환경에서는 이들을 종합적으로 고려하여 최적의 성능을 달성할 수 있습니다.
(자세한 설정 관련 내용은 HikariCP의 공식 문서에서 확인하실 수 있습니다.)

Setup

⌈code⌋ build.gradle

implementation 'org.springframework.boot:spring-boot-starter-actuator'

⌈code⌋ application.properties

management.endpoints.web.exposure.include=metrics # actuator 엔드포인트 노출 설정

management.metrics.enable.hikaricp=true # HikariCP 메트릭스 활성화 설정. 커넥션 풀의 상태, 사용량 등의 정보를 모니터링할

Curl Test

> curl -s "http://localhost:8080/actuator/metrics/hikaricp.connections.active"
{"name":"hikaricp.connections.active","description":"Active connections","measurements":[{"statistic":"VALUE","value":0.0}],"availableTags":[{"tag":"pool","values":["HikariPool-1"]}]}%

Monitoring

Connection Pool의 상태를 모니터링하기 위해 다음과 같은 스크립트들을 작성했습니다:

⌈code⌋ monitor_network_connections.sh

#!/bin/bash

while true
do
    count=$(lsof -i | wc -l)
    echo "$(date): $count active connections"
    sleep 1  # 1초마다 실행
done

⌈code⌋ hikari_monitoring.sh

#!/bin/bash

while true
do
    # HikariCP 커넥션 풀 상태 정보 가져오기
    active_connections=$(curl -s "http://localhost:8080/actuator/metrics/hikaricp.connections.active" | jq '.measurements[0].value')
    idle_connections=$(curl -s "http://localhost:8080/actuator/metrics/hikaricp.connections.idle" | jq '.measurements[0].value')
    total_connections=$(curl -s "http://localhost:8080/actuator/metrics/hikaricp.connections" | jq '.measurements[0].value')
    
    # 현재 시간과 커넥션 풀 상태 출력
    echo "$(date): Active Connections: $active_connections, Idle Connections: $idle_connections, Total Connections: $total_connections"
    
    sleep 1  # 1초마다 실행
done

Test

pool size에 따른 처리량 비교

⌈code⌋ application.properties

spring.datasource.hikari.maximum-pool-size=10

아래와 같은 설정 값을 통해 maximum-pool-size를 조정할 수 있습니다. 조정을 통한 테스트 결과입니다.

maximum-pool-sizeRequests/sec (RPS)Transfer/sec (TPS)
102293.615.33MB
202899.106.73MB
10003975.109.23MB

그러나 실제로는 maximum-pool-size=1000 케이스의 경우, MySQL의 max_connections 설정(151)에 의해 제한되고 있는 것을 확인했습니다.

MySQL의 max_connections 값 조정

MySQL에 설정된 max_connections 갯수 제한으로 151로 설정되어있었습니다.

SHOW VARIABLES LIKE 'max_connections'; 
+-----------------+-------+
| Variable_name   | Value |
| max_connections | 151   |
+-----------------+-------+

이에 따라, max_connections 값을 1000으로 셋팅해주었습니다.

SET GLOBAL max_connections = 1000;

재수행 결과 Active Connection은 여전히 약 150개 수준에 머물러있고, 성능은 오히려 저하된 결과를 얻었습니다.
MySQL:max_connectionsmaximum-pool-sizeRequests/sec (RPS)Transfer/sec (TPS)
15110003975.109.23MB
100010001809.094.19MB

결과 분석

  1. Active Connection 수 제한
    Java 애플리케이션의 스레드 수가 실제 Active Connection 수를 제한하는 것으로 추측됩니다. 이는 Database Connection Pool 크기를 증가시켜도 실제 사용되는 연결 수는 애플리케이션의 동시 처리 능력에 의해 제한될 수 있음을 의미합니다.

  2. 성능 저하 원인에 대한 추측

  • 과도한 연결 풀 크기로 인한 리소스 낭비 : 너무 많은 연결을 유지하는 것이 서버의 메모리 사용량을 증가시키고, 연결 관리에 더 많은 오버헤드를 발생시킬 수 있습니다.
  • 데이터베이스 서버 부하 증가 : 연결 수 증가로 인해 데이터베이스 서버가 더 많은 리소스를 연결 관리에 할당해 실제 쿼리 처리 성능이 저하될 수 있습니다.
  • Connection 획득/반환에 대한 오버헤드 증가 : Connection Pool이 커지면서 적절한 연결을 선택하고 관리하는 데 더 많은 시간이 소요될 수 있습니다.

추가 고려사항 및 주의점

MySQL의 max_connections 설정을 변경할 경우, 연결된 애플리케이션의 재시작이 필요할 수 있습니다. 실제로 Mysql의 max_connections 설정을 1000에서 151로 변경해도 모니터링하는 Active Connection의 수와 사용중인 네트워크 연결 수가 유지되는 것으로 나타났습니다. 이 때, 애플리케이션을 재시작하여 자원을 정상적으로 해제하고 새로운 설정을 적용해주어야 합니다.


Conclusion

이 실험을 통해 Database Connection Pool 최적화의 중요성과 복잡성을 확인했습니다. 주요 발견사항은 다음과 같습니다:

  1. Connection Pool 크기는 성능에 직접적인 영향을 미치지만, 단순히 크기를 늘리는 것만으로는 최적의 성능을 얻을 수 없습니다. 오히려 과도한 Pool 크기는 성능 저하를 초래할 수 있습니다.
  2. 데이터베이스 서버 설정(예: MySQL의 max_connections)과 애플리케이션 설정(예: HikariCP의 maximum-pool-size)은 상호 연관되어 있으며, 둘 다 최적화에 중요한 역할을 합니다.
  3. 실제 Active Connection 수는 애플리케이션의 동시 처리 능력(스레드 수)에 의해 제한될 수 있어, Connection Pool 설정만으로는 성능 향상에 한계가 있을 수 있습니다.
  4. 설정 변경 후 애플리케이션 재시작의 중요성을 확인했으며, 이는 운영 환경에서 주의해야 할 중요한 점입니다.
  5. 지속적인 모니터링과 메트릭스 분석은 Connection Pool 최적화와 문제 진단에 필수적입니다.

결론적으로, Database Connection Pool 최적화는 단순한 설정 조정 이상의 복잡한 과정입니다. 데이터베이스 서버 설정, 애플리케이션 특성, 실제 부하 상황을 종합적으로 고려한 세심한 조정이 필요합니다. 지속적인 모니터링, 튜닝, 그리고 실제 운영 환경에서의 테스트를 통해 최적의 설정을 찾아나가는 것이 중요합니다.

Refernece

0개의 댓글