Client-side connection-pool

루비 프로세스는 ActiveRecord를 통해 데이터베이스에 액세스하며, 동시성에 기반하여 프로세스별로 연결 풀 크기를 자동으로 계산합니다.

Ruby on Rails가 데이터베이스 연결을 관리하는 방식 때문에, 스레드 수만큼 연결이 있어야 합니다. database.yml에는 ‘pool’ 설정이 있지만, 응용프로그램 스레드 수와 함께 유지해야 하기 때문에 실용적이지 않습니다. 이에 따라, 설정된 응용프로그램 스레드 수에 기반하여 데이터베이스 연결 풀에서 허용된 연결 수를 재정의합니다.

Gitlab::Runtime.max_threads는 프로세스에 구성된 사용자를 대상으로 하는 응용프로그램 스레드 수입니다. 또한 데이터베이스 연결을 사용하는 보조 스레드도 있습니다. 시간이 지남에 따라 응용프로그램이 진화하기 때문에 보조 스레드 수를 정확하게 계산하는 것은 단순하지 않기 때문에, 우리는 사용자를 대상으로 하는 스레드 수에 고정된 여유를 더합니다. 이 숫자가 너무 크더라도 문제 없습니다. 연결은 게으르게 생성되기 때문입니다.

연결 풀 문제 해결

연결 풀 사용량은 연결 풀 포화 대시보드에서 환경별로 볼 수 있습니다.

연결 풀이 너무 작으면, 응용프로그램에서 ActiveRecord::ConnectionTimeoutError가 발생합니다. 거의 모든 연결이 사용될 때 경고가 발생하기 때문에, 시간이 지나기 전에 알아차릴 수 있어야 합니다. 이렇게 되면 DB_POOL_HEADROOM 환경 변수를 hardcoded된 값(10)보다 큰 값으로 설정하여 문제를 해결할 수 있습니다.

이 시점에서, 예상보다 더 많은 연결을 사용하는 것을 조사해야 합니다. 이를 위해 gitlab_ruby_threads_running_threads 메트릭을 사용할 수 있습니다. 예를 들어, 이 그래프는 이름에 따라 데이터베이스에 연결하는 모든 실행 중인 스레드를 보여줍니다. puma worker 또는 sidekiq_worker_thread로 표시된 스레드는 Gitlab::Runtime.max_threads를 정의하는 스레드이므로 고려됩니다. 10개 이상의 다른 스레드가 실행 중이면, 기본 여유를 높이는 것을 고려할 수 있습니다.

연결 라이프사이클

웹 요청의 경우, 데이터베이스 쿼리를 처음으로 만들때 연결이 연결 풀에서 얻어집니다. 요청이 완료되면 연결이 연결 풀로 반환됩니다.

백그라운드 작업의 경우, 동작 방식은 매우 유사합니다. 스레드는 첫 번째 쿼리에 대해 연결을 얻고, 작업이 완료되면 반환합니다.

이는 Rails에서 내부적으로 관리됩니다.