벤치마크 설정 및 방법
본 벤치마크는 sysbench 도구의 oltp_read_only 워크로드를 사용하여 PostgreSQL 17 및 18의 성능을 비교했습니다. 데이터 크기는 약 300GB(100개 테이블에 각각 1,300만 행)로 설정되었으며, RAM(64GB)을 초과하여 상당한 디스크 I/O가 발생하도록 유도했습니다.
테스트는 다음 네 가지 AWS EC2 인스턴스 구성에서 진행되었습니다:
-
r7i.2xlarge (gp3 3,000 IOPS / 125 MB/s): 네트워크 연결 스토리지
-
r7i.2xlarge (gp3 10,000 IOPS / 500 MB/s): 네트워크 연결 스토리지 (향상된 성능)
-
r7i.2xlarge (io2 16,000 IOPS): 네트워크 연결 스토리지 (고가, 고성능)
-
i7i.2xlarge (로컬 NVMe 300,000 IOPS): 고속 로컬 NVMe 드라이브
각 인스턴스에서 PostgreSQL 17, 그리고 io_method가 sync, worker, io_uring으로 설정된 PostgreSQL 18 버전에 대해 다음 6가지 시나리오를 5분씩 4회 반복하여 총 96가지 조합을 벤치마크했습니다:
-
단일 연결 및
--range_size = 100 -
10개 연결 및
--range_size = 100 -
50개 연결 및
--range_size = 100 -
단일 연결 및
--range_size = 10,000 -
10개 연결 및
--range_size = 10,000 -
50개 연결 및
--range_size = 10,000
벤치마크 결과 분석
- 단일 연결 워크로드 (
--range_size=100)- 네트워크 연결 스토리지(gp3, io2)에서는 Postgres 18의
sync및worker모드가 Postgres 17 및 18의io_uring모드보다 현저히 우수한 성능을 보였습니다. 이는io_uring에 대한 초기 기대와는 다른 결과였습니다. - 로컬 NVMe 드라이브에서는 모든 옵션 간 성능 차이가 훨씬 적었습니다.
- Postgres 18은 짧은 쿼리에 대한 직선 성능(straight-line performance)에서 크게 개선된 모습을 보였습니다.
- 네트워크 연결 스토리지(gp3, io2)에서는 Postgres 18의
- 단일 연결 워크로드 (
--range_size=10000)--range_size가 커지면서 더 많은 순차 I/O와 CPU 작업(집계)이 발생하여, 옵션 간의 성능 차이가 줄어들었습니다.- 로컬 디스크는 여전히 우위를 점했지만, Postgres 17과 18의 성능 격차는 작아졌습니다.
- 다중 연결 워크로드 (
50개 연결, --range_size=100)- 높은 병렬성과 I/O 요구 사항이 증가함에 따라, EBS 기반 인스턴스에서는 I/OPS와 처리량이 명확한 병목 현상이었습니다. 이 경우 버전이나 I/O 설정의 차이는 크지 않았습니다.
- 로컬 NVMe 인스턴스는 모든 EBS 기반 인스턴스를 압도적으로 능가했습니다.
- Postgres 18의
sync및worker모드가 모든 EBS 기반 인스턴스에서 약간 더 나은 성능을 보였습니다.
- 다중 연결 워크로드 (
50개 연결, --range_size=10000)- 이 시나리오에서는 벤치마크가 I/O 바운드에서 CPU 바운드로 전환되면서 로컬 디스크의 저지연 이점이 줄어들었습니다.
- 주목할 점은 NVMe 인스턴스에서
io_uring이 다른 옵션들을 약간 능가하는 유일한 시나리오였다는 것입니다. 이는io_uring이 특정 고병렬/고성능 I/O 환경에서 잠재력을 가질 수 있음을 시사합니다.
io_uring의 성능 특성- 10개 연결 시나리오에서
io_uring은 낮은 동시성에서 다른 설정보다 훨씬 낮은 성능을 보였으나, 50개 연결에서는 그 차이가 줄어들었습니다. 이는io_uring이 높은 I/O 동시성에서 더 효과적일 수 있음을 나타냅니다.
- 10개 연결 시나리오에서
비용 효율성
- 로컬 NVMe 디스크를 사용하는 i7i 인스턴스는 gp3 또는 io2 EBS 기반 인스턴스보다 훨씬 저렴한 비용으로 월등한 성능을 제공하여, 가격 대비 성능에서 명확한 승자로 나타났습니다.
io_uring이 기대에 못 미친 이유
Tomas Vondra의 분석에 따르면, io_uring이 항상 최적의 성능을 보이지 않는 몇 가지 이유가 있습니다:
-
현재 인덱스 스캔은 비동기 I/O(AIO)를 사용하지 않습니다.
-
I/O가 백그라운드에서 발생하더라도 체크섬 및 메모리 복사 작업이 병목이 될 수 있습니다.
-
worker방식은 단일 프로세스 관점에서 I/O에 더 나은 병렬성을 제공할 수 있습니다.