클라이언트 사이드 커넥션 풀
GitLab v19.4요약
ActiveRecord를 통해 데이터베이스에 접근하는 Ruby 프로세스는 동시성에 기반해 해당 프로세스의 커넥션 풀 크기를 자동으로 계산합니다. Ruby on Rails가 데이터베이스 커넥션을 관리하는 방식 때문에 스레드 수만큼은 커넥션을 확보해 두어야 합니다.
ActiveRecord를 통해 데이터베이스에 접근하는 Ruby 프로세스는 동시성에 기반해 해당 프로세스의 커넥션 풀 크기를 자동으로 계산합니다.
Ruby on Rails가 데이터베이스 커넥션을 관리하는 방식 때문에
스레드 수만큼은 커넥션을 확보해 두어야 합니다.
database.yml에
'pool' 설정이 있기는 하지만, 애플리케이션 스레드 수와
함께 관리해야 하므로 실용적이지 않습니다. 이러한 이유로
GitLab은 구성된 애플리케이션 스레드 수를 기준으로 데이터베이스
커넥션 풀에서 허용하는 커넥션 수를 재정의합니다.
Gitlab::Runtime.max_threads는 해당 프로세스에 구성된 사용자 대면
애플리케이션 스레드 수입니다. 이 외에도 데이터베이스 커넥션을 사용하는
보조 스레드가 있습니다. 애플리케이션이 변화하는 동안 보조 스레드
수를 정확하게 유지하기는 쉽지 않으므로, 사용자 대면 스레드
수에 고정된 여유분을 더합니다. 커넥션은 지연 생성되므로
이 값이 다소 크더라도
문제가 되지 않습니다.
커넥션 풀 문제 해결#
커넥션 풀 사용량은 환경별로 커넥션 풀 포화 대시보드에서 확인할 수 있습니다.
커넥션 풀이 너무 작으면 애플리케이션에서
ActiveRecord::ConnectionTimeoutError가 발생합니다. 거의 모든 커넥션이
사용되면 알림이 발생하므로 타임아웃이 발생하기 전에 상황을 파악할 수
있습니다. 이 경우 DB_POOL_HEADROOM 환경 변수를 하드코딩된
값(10)보다 크게 설정해 문제를 완화할 수
있습니다.
이 시점에는 예상보다 많은 커넥션을 사용하는 대상이 무엇인지
조사해야 합니다. 이를 위해
gitlab_ruby_threads_running_threads 메트릭을 사용할 수 있습니다. 예를 들어
이 그래프는
데이터베이스에 연결하는 실행 중인 모든 스레드를 이름별로
보여 줍니다. puma worker 또는 sidekiq_worker_thread로 표시된 스레드는
Gitlab::Runtime.max_threads를 정의하는 스레드이므로 이미
반영되어 있습니다. 그 외 스레드가 10개를 넘게 실행 중이라면
기본 여유분을 늘리는 방안을 검토할 수 있습니다.
커넥션 라이프사이클#
웹 요청에서는 데이터베이스 쿼리가 처음 수행될 때 풀에서 커넥션을 가져옵니다. 커넥션은 요청이 완료된 뒤 풀로 반환됩니다.
백그라운드 job도 동작이 매우 비슷합니다. 스레드가 첫 쿼리를 수행할 때 커넥션을 가져오고, job 이 끝나면 반환합니다.
이 과정은 Rails가 내부적으로 관리합니다.