SO_REUSEPORT와 피어링을 활용한 PgBouncer 처리량 4배 확대
SO_REUSEPORT와 피어링을 활용한 PgBouncer 처리량 4배 확대
ClickHouse가 PgBouncer 처리량을 4배 늘림
ClickHouse는 단일 머신에서 여러 PgBouncer 프로세스를 실행하여 PgBouncer 처리량을 4배로 확장했습니다. 이 접근 방식은 일반적으로 성능이 단일 CPU 코어에 제한되는 PgBouncer의 단일 스레드 특성을 극복하고, SO_REUSEPORT 소켓 옵션을 사용해 연결 부하를 여러 프로세스로 분산시킵니다.
부하 분산을 위한 SO_REUSEPORT 사용
고처리량을 달성하기 위해 ClickHouse는 SO_REUSEPORT를 활용합니다. 이 소켓 옵션을 사용하면 여러 프로세스가 동일한 IP 주소와 포트에 바인딩할 수 있습니다. Linux 커널은 들어오는 TCP 연결을 라운드‑로빈 또는 해시 방식으로 프로세스에 분배합니다. 이를 통해 단일 PgBouncer 인스턴스를 다중 프로세스 아키텍처로 전환시켜, 프로세스 풀에 할당된 CPU 코어 수에 비례해 선형적으로 확장할 수 있습니다.
피어링으로 쿼리 취소 문제 해결
SO_REUSEPORT가 연결을 분산시키지만, 쿼리 취소 요청이 해당 세션을 소유하지 않은 PgBouncer 프로세스로 전달되는 문제를 야기합니다. 표준 PgBouncer 아키텍처는 격리되어 있기 때문에, 세션을 인식하지 못하는 프로세스가 취소 요청을 받으면 이를 무시하게 되어 쿼리 취소가 실패합니다.
이를 해결하기 위해 ClickHouse는 피어링 메커니즘을 구현했습니다. 피어링을 통해 PgBouncer 프로세스들이 서로 통신할 수 있게 됩니다. 프로세스가 자신이 소유하지 않은 세션에 대한 취소 요청을 받으면, 실제 해당 세션을 관리하고 있는 피어 프로세스로 요청을 전달합니다. 이렇게 하면 분산된 프로세스 풀에서도 쿼리 취소가 정상적으로 동작합니다.
구현 및 설정
커뮤니티 논의를 바탕으로, 이 설정을 사용하려면 so_reuseport를 활성화하고 피어 ID와 해당 소켓을 정의해야 합니다. 예시 설정 구조는 다음과 같습니다:
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
so_reuseport = 1
peer_id = 1
unix_socket_dir = /tmp/pgbouncer1
[peers]
1 = host=/tmp/pgbouncer1
2 = host=/tmp/pgbouncer2
3 = host=/tmp/pgbouncer3
4 = host=/tmp/pgbouncer4
커뮤니티 인사이트와 대안
이 구현에 대한 기술 토론에서는 PostgreSQL 연결 풀링을 확장하기 위한 여러 대안과 고려 사항이 강조되었습니다:
- 대체 풀러: 일부 사용자는 PgBouncer의 확장 가능한 대안으로 Odyssey 또는 pgdog 사용을 제안했습니다.
- 인프라 수준 확장: Kubernetes를 통해 다수의 PgBouncer 인스턴스를 실행하는 것이 여러 머신에 걸쳐 유사한 결과를 얻는 간단한 방법으로 언급되었으며, 이는 클라우드 제공업체 VM 유지보수와 관련된 위험을 완화합니다.
- 아키텍처 질문: 일부 엔지니어는 다수의 PgBouncer 인스턴스에 트래픽을 분산시키는 전통적인 HAProxy 설정 대비 이 접근 방식의 장점에 대해 의문을 제기했습니다.
"취소 요청이 해당 쿼리를 전혀 모르는 프로세스로 전달되면 아무 일도 일어나지 않습니다. 피어링이 이를 해결합니다. 프로세스들이 서로를 인식하고 있기 때문에, 잘못된 프로세스로 전달된 취소는 실제 세션을 소유한 프로세스로 전달됩니다."
이 피어링 메커니즘은 다중 프로세스 PgBouncer 환경에서 PostgreSQL 연결 관리 기능을 유지하는 데 핵심적인 역할을 합니다.
요약:
ClickHouse는 단일 머신에 다중 프로세스를 배치하고 SO_REUSEPORT와 세션‑특정 요청(예: 쿼리 취소)을 처리하기 위한 피어링 메커니즘을 활용함으로써 PgBouncer 처리량을 4배 향상시켰습니다.
제목: SO_REUSEPORT와 피어링을 활용한 PgBouncer 처리량 4배 확대