본문으로 건너뛰기

벤치마크

벤치마크 하네스는 안정적인 JSON와 사람이 읽기 쉬운 보고서를 작성합니다. 이 도구는 bench/에 있으며, storh 저장소에 포함되어 있습니다. Composer 패키지에는 0.5.2 이후 포함되지 않았으므로, 아래 composer bench* 명령은 복제본에서 composer install한 후에만 실행됩니다:

셸
composer bench
composer bench -- --dataset=100000 --engine=doc
composer bench -- --dataset=100000 --engine=log
composer bench -- --dataset=100000 --engine=queue
composer bench -- --dataset=100000 --engine=cache --cache-validation=trust
composer bench -- --dataset=100000 --engine=filter
composer bench -- --dataset=1000000 --engine=uuid
composer bench:jit -- --dataset=1000000 --engine=uuid
composer bench:repeat -- --dataset=100000 --engine=doc --repeat=5
composer bench:repeat -- --dataset=1000000 --engine=filter --repeat=5 --memory-limit=512M
composer bench:range -- --datasets=1000,10000,50000,100000
composer bench:range -- --datasets=100000 --engines=cache --memory-limit=512M
composer bench:compare build/bench-main.json build/bench-current.json
composer bench:gate -- build/bench-main.json build/bench-current.json --threshold=10 --metric=doc.put --metric=log.stream
composer bench:ci

기준 결과

50,000개의 레코드를 엔진별로 처리한 하네스 전체 실행 3회의 중앙값입니다. Apple M1 Pro(16 GB, macOS 26.5, APFS)에서 PHP 8.5 CLI를 사용했으며 opcache와 JIT는 껐습니다.

셸
composer bench:repeat -- --dataset=50000 --engine=all --repeat=3 --memory-limit=512M

storh에서 저장됐다고 보고하기 전에 모든 쓰기를 flush 및 fsync하므로 쓰기 속도는 파일 시스템에 좌우됩니다. 읽기는 OS 페이지 캐시에서 실행됩니다. 속도는 중앙값에서 산출했습니다. 사용자의 하드웨어에서 측정하려면 리포지토리를 클론해 composer bench을 실행하세요.

DocStore, 레코드 50k개 중앙값
put(), 레코드당 내구성 파일 1개 3.3k 레코드/s
putStream() 대량 수집 3.7k 레코드/s
importJsonl() 3.6k 레코드/s
get() 지점 읽기, STAT 검증 5.6 µs
기존 store 다시 열기 0.26 ms
인덱스 동등성 쿼리, limit(100) 1.1 ms
컬렉션 전체 인덱스 count() 41 µs
인덱스 빌드, 동등성 필드 2개 + 범위 필드 1개 52k 레코드/s
STAT 재검증을 포함한 전체 stream() 103k 레코드/s
exportJsonl() 104k 레코드/s
SegmentedLog, 레코드 50k개, 세그먼트 16 KB 중앙값
put(), 추가마다 fsync 초당 16k회 추가
appendStream() 대량 수집 56k 레코드/s
커서 읽기, 중간 지점부터 레코드 100개 2.1 ms
시간 범위 읽기 1.1 ms
동등성 count() 11 µs
봉인된 모든 세그먼트 compact() 69k 레코드/s
잘린 꼬리 복구를 포함해 다시 열기 218k 레코드/s

벤치마크에서는 세그먼트 롤오버를 확인하기 위해 16 KB마다 세그먼트를 봉인합니다. 기본 세그먼트 크기는 1 MiB입니다.

큐, 작업 50k개 중앙값
enqueue(), 이벤트마다 fsync 22k 작업/s
claim() 23k 작업/s
complete() 23k 작업/s
enqueueMany() 209k 작업/s
claimMany() 467k 작업/s
completeMany() 512k 작업/s
SQL Mirror, SQLite, 레코드 50k개 중앙값
초기 push() 61k 행/s
변경 사항이 없을 때 push() 86k 레코드/s
flush(), 100 ID 7.1 ms
미러 전체 인덱스 SQL COUNT 6.9 ms
rebuild() 65k 행/s
pull() 복구, 레코드당 내구성 파일 1개 3.2k 레코드/s
마이크로 중앙값
캐시된 get(), 콜드 후 웜(MemoryCache, STAT) 83 µs / 6.3 µs
UUIDv7 생성 1.3 µs
UUIDv7 검증 0.30 µs
메모리 내 조건자 필터링 4.4M 행/s

대상 범위:

  • DocStore put, 스트리밍 put, JSONL 내보내기/가져오기, get, delete, stream 및 인덱스 빌드
  • 동등성 인덱스, 복합 인덱스, 범위 인덱스, 오름차순 및 내림차순 정렬 범위, 인덱스 기반 카운트, ID 조회 및 비인덱스 DocStore 쿼리
  • SegmentedLog append, 스트리밍 append, 커서 읽기, 시간 범위 읽기, 압축된 시간 범위 읽기, QueryBuilder 커서 및 ID 조회, 카운트, 일괄 append 카운트, 통계, 압축
  • Queue enqueue, 일괄 enqueue, claim, 일괄 claim, complete, 일괄 complete, requeue
  • 메모리 내 행에 대한 RecordQuery 및 QueryCondition 조건자 필터링
  • UUIDv7 단조 증가 생성, 타임스탬프 분산 생성, 검증 및 타임스탬프 추출
  • 끝부분이 잘린 줄 복구
  • 해시, stat 또는 신뢰 기반 검증을 사용하는 콜드 및 웜 캐시 읽기

기본 출력 경로:

Text
build/bench-current.json

범위 실행은 데이터 세트와 엔진별로 JSON 파일 하나를 build/bench-ranges/에 씁니다.

bench:gate은 벤치마크 JSON 파일 두 개를 비교하고, 추적하는 지표 중 하나라도 설정된 임계값보다 느리면 0이 아닌 상태 코드로 종료합니다. --metric 값이 전달되지 않으면 기준 파일에 있는 모든 지표를 검사합니다.

bench:ci은 GitHub Actions 스모크 회귀 검사 게이트입니다. 모든 엔진에서 1k 벤치마크를 실행하고, 선택한 쓰기/읽기/캐시/UUID 지표를 추적 중인 bench/baselines/ci-1k-all.json 기준과 비교합니다. 일반적인 실행 환경의 변동에도 실패하지 않도록 기본 임계값을 넉넉하게 설정하면서도 큰 성능 회귀는 감지합니다.

bench:jit은 같은 하네스를 CLI opcache와 추적 JIT를 활성화한 상태로 실행하며, 벤치마크 프로세스에서 Xdebug를 비활성화해 PHP이 실제로 JIT를 켤 수 있게 합니다. 생성된 JSON에는 해당 실행에서 opcache와 JIT가 활성 상태였는지 보여 주는 런타임 플래그가 포함됩니다.