Skip to content

[Perf] 전체 인덱싱 Queue 적체 및 DB Pool Backpressure Benchmark 추가 - #142

Merged
Gimini-3 merged 7 commits into
developfrom
feature/141
Aug 10, 2026
Merged

[Perf] 전체 인덱싱 Queue 적체 및 DB Pool Backpressure Benchmark 추가#142
Gimini-3 merged 7 commits into
developfrom
feature/141

Conversation

@Gimini-3

@Gimini-3 Gimini-3 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

🔍️ 작업 내용

✨ 상세 설명

  • 16×4, 32×8, 64×16, 128×32 문서·업로더 Profile
  • Hikari active/idle/total/awaiting connection 25ms 표본화
  • Queue depth, oldest pending age, Queue AUC·평균 depth 측정
  • 전용 workerQueueBackpressureTest Gradle task 추가
  • 실제 PostgreSQL 17·MinIO·BAAI/bge-m3 전체 파이프라인 실행
  • 리뷰 후 Queue 평균 적분 구간과 기본 실행 Timeout 예산 보정

실측 결과

Profile 상태 처리량 Queue wait p95 max waiting
16문서·4업로더 POOL_BACKPRESSURED 163.000 docs/min 3.07s 6
32문서·8업로더 POOL_BACKPRESSURED 149.266 docs/min 9.96s 10
64문서·16업로더 POOL_BACKPRESSURED 142.791 docs/min 23.78s 18
128문서·32업로더 POOL_BACKPRESSURED 142.054 docs/min 49.20s 33
  • Hikari Pool 4개는 첫 Profile부터 포화되고 connection waiting이 발생했습니다.
  • 고부하 처리량은 약 142문서/분에서 정체되고 Queue 대기만 증가했습니다.
  • 재측정 8회·480문서 모두 INDEXED됐으며 업로드 실패, FAILED Job, 미완료 Job은 0입니다.
  • 붕괴는 128문서·32업로더 범위에서 관측되지 않았으며 임계값을 추정하지 않았습니다.

✅ 검증

  • ./gradlew test --tests com.opensource.docgrid.e2e.WorkerQueueBackpressureStatisticsTest
  • DB_SSLMODE=disable ./gradlew workerQueueBackpressureTestBUILD SUCCESSFUL in 3m 29s
  • DB_SSLMODE=disable JWT_SECRET=<test-only-value> ./gradlew testBUILD SUCCESSFUL in 25s
  • git diff --check

로컬 Docker PostgreSQL은 SSL을 제공하지 않아 성공 실행에만 DB_SSLMODE=disable을 명시했으며 저장소 설정과 시크릿은 변경하지 않았습니다.

🛠️ 추후 리팩토링 및 고도화 계획

  • 실제 배포 장비와 운영형 문서 크기 분포에서 붕괴점 재측정
  • 운영 SLO가 확정된 뒤 Queue 경보·Admission Control 임계값 검토

💬 리뷰 요구사항

  • Pool 압력 상태 판정과 Queue AUC 계산 계약
  • Benchmark가 일반 테스트에서 분리되어 있는지
  • 붕괴 미관측 결과와 추론의 경계

Summary by CodeRabbit

  • 테스트
    • Worker Queue와 데이터베이스 연결 풀의 부하 및 백프레셔를 측정하는 전용 검증 작업을 추가했습니다.
    • 다양한 문서 규모와 동시성 조건에서 처리량, 대기 시간, 큐 적체, 연결 풀 상태를 확인합니다.
    • 업로드·작업 처리 결과와 데이터 정합성을 자동 검증하고 JSON 및 Markdown 결과를 생성합니다.
    • 큐 통계 계산, 부하 프로파일 검증, 압력 상태 판정에 대한 단위 테스트를 추가했습니다.
  • 문서
    • 벤치마크 실행 방법, 측정 기준, 결과 해석 및 운영 판단 기준을 문서화했습니다.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Worker Queue와 Hikari Connection Pool backpressure 벤치마크를 추가했습니다. 실제 인프라에서 단계별 부하를 실행하고, Queue·Pool·처리량·정합성 지표를 수집합니다. 전용 Gradle 작업과 JSON·Markdown 결과 문서도 추가했습니다.

Changes

Worker Queue Backpressure Benchmark

Layer / File(s) Summary
Benchmark 계약과 통계 모델
docs/design/..., src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatistics*
부하 프로파일, Queue·Pool 지표, 압력 상태, 정합성 조건과 통계 계산 규칙을 정의했습니다. 파싱, AUC, 평균 깊이, 샘플 비율, 상태 판정을 단위 테스트로 검증합니다.
E2E 환경과 프로파일 실행
src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java
Worker, PostgreSQL, MinIO, 임베딩 서버와 제한된 Hikari Pool을 구성합니다. 프로파일별 업로드, Queue 처리, Job 검증, 지연 측정을 수행합니다.
Pool·Queue 관측과 결과 집계
src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java
별도 모니터링 연결로 Queue와 Hikari 지표를 샘플링합니다. 프로파일 결과를 중앙값, 최악 압력 상태, 최초 임계 프로파일과 함께 JSON·Markdown으로 저장합니다.
Gradle 실행과 실측 결과
build.gradle, docs/test-results/...
기본 test 작업에서 전용 태그를 제외합니다. workerQueueBackpressureTest 작업과 실행 속성을 추가합니다. 스모크·전체 실행 결과와 정합성 검증 결과를 기록합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Benchmark as WorkerQueueBackpressureBenchmark
  participant MinIO
  participant Worker
  participant PostgreSQL
  participant EmbeddingServer
  participant Sampler as PoolQueueSampler

  Benchmark->>MinIO: 프로파일 문서 업로드
  MinIO->>Worker: Job 처리 시작
  Worker->>PostgreSQL: Job 및 문서 상태 조회·저장
  Worker->>EmbeddingServer: Embedding 생성
  EmbeddingServer-->>Worker: 벡터 반환
  Worker->>PostgreSQL: Chunk·Embedding 저장 및 INDEXED 전환
  Sampler->>PostgreSQL: Queue·Pool 지표 샘플링
  Sampler-->>Benchmark: 시계열 관측값 반환
  Benchmark->>Benchmark: 프로파일 통계·압력 상태 집계
Loading

Possibly related PRs

  • DocGrid/backend#53: Worker Queue와 Hikari Pool 동시성 측정 영역이 연결되지만, 이 변경은 별도 벤치마크와 통계 클래스를 추가합니다.
  • DocGrid/backend#62: 전용 태그 벤치마크, Worker 동시성, Hikari contention, JSON 결과 보고를 함께 다룹니다.
  • DocGrid/backend#94: Worker Queue와 실행 backpressure를 벤치마크하며, 이 변경의 Queue·Pool 측정 흐름과 연결됩니다.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 전용 Benchmark task, 실제 인프라 측정, Queue·Hikari 지표, 정합성 검증, 결과 문서화 요구를 충족합니다.
Out of Scope Changes check ✅ Passed 변경 사항은 연결된 이슈의 Benchmark 구현, 통계 검증, 실행 설정 및 결과 문서 범위에 포함됩니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed 제목은 전체 인덱싱 Queue 적체와 DB Pool Backpressure Benchmark 추가라는 주요 변경 사항을 명확하고 간결하게 요약합니다.
Description check ✅ Passed 작업 내용, 상세 설명, 실측 결과, 검증 방법, 후속 계획, 리뷰 요구사항을 포함해 템플릿의 필수 정보를 충분히 작성했습니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/141

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatisticsTest.java (1)

61-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

검증 계약의 거부 경로 테스트를 보강하세요.

summarizeQueue는 빈 목록, null sample, 시각 역전을 거부합니다. parseProfiles는 rawValue가 null이거나 공백이면 defaults를 반환합니다. 현재 테스트는 두 경로를 모두 검증하지 않습니다. 이 계약은 실측 Sampler 입력을 방어하는 지점이므로 회귀 검증이 필요합니다.

♻️ 제안 추가 테스트
    `@Test`
    `@DisplayName`("Profile 입력이 없으면 기본 Profile을 사용한다")
    void fallsBackToDefaultProfiles() {
        List<LoadProfile> defaults = List.of(new LoadProfile(16, 4), new LoadProfile(32, 8));

        assertThat(WorkerQueueBackpressureStatistics.parseProfiles("  ", defaults))
            .containsExactlyElementsOf(defaults);
    }

    `@Test`
    `@DisplayName`("비어 있거나 시각이 역전된 Queue Sample을 거부한다")
    void rejectsInvalidQueueSamples() {
        assertThatThrownBy(() -> WorkerQueueBackpressureStatistics.summarizeQueue(List.of()))
            .isInstanceOf(IllegalArgumentException.class);
        assertThatThrownBy(() -> WorkerQueueBackpressureStatistics.summarizeQueue(List.of(
            new QueueSample(2_000_000_000L, 1, 0, 0, 0),
            new QueueSample(1_000_000_000L, 1, 0, 0, 0)
        ))).isInstanceOf(IllegalArgumentException.class);
    }

경로 지침의 "테스트 커버리지, 스프링 테스트 어노테이션, mock 사용법, 네이밍 규칙을 확인한다"에 따른 의견입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatisticsTest.java`
around lines 61 - 85, 보호해야 할 입력 검증 계약에 대한 테스트가 누락되어 있습니다.
WorkerQueueBackpressureStatisticsTest에 parseProfiles의 null 또는 공백 rawValue가 기본
Profile 목록을 반환하는지 검증하는 테스트를 추가하고, summarizeQueue가 빈 목록과 시간이 역전된 QueueSample 목록에
IllegalArgumentException을 발생시키는지 각각 검증하세요.

Source: Path instructions

src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java (1)

436-445: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

업로드 대기 초과가 결과 보존 의도와 어긋납니다.

436행 주석은 성공과 실패를 모두 결과로 보존한다고 선언합니다. 그러나 future.get(PROFILE_TIMEOUT_SECONDS, TimeUnit.SECONDS)TimeoutException을 던지면 예외가 그대로 전파되어 해당 run은 ProfileRun으로 기록되지 않습니다. 대기 시간도 future 단위로 누적되어 총 대기가 제한 시간을 넘을 수 있습니다. 대기 초과를 업로드 실패로 변환하면 붕괴 판정(COLLAPSED) 경로로 기록됩니다.

♻️ 제안 수정
             List<UploadAttempt> attempts = new ArrayList<>(profile.documentCount());
+            long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(PROFILE_TIMEOUT_SECONDS);
             for (Future<UploadAttempt> future : futures) {
-                attempts.add(future.get(PROFILE_TIMEOUT_SECONDS, TimeUnit.SECONDS));
+                long remainingNanos = Math.max(0L, deadline - System.nanoTime());
+                try {
+                    attempts.add(future.get(remainingNanos, TimeUnit.NANOSECONDS));
+                } catch (TimeoutException exception) {
+                    future.cancel(true);
+                    attempts.add(UploadAttempt.failure(
+                        millis(remainingNanos),
+                        exception.getClass().getSimpleName()
+                    ));
+                }
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java`
around lines 436 - 445, Update the future-collection loop in the benchmark’s
upload-result flow to catch per-future TimeoutException and convert it into an
UploadAttempt failure result, preserving the run for COLLAPSED evaluation
instead of propagating the exception. Avoid applying the full profile timeout
independently to every future; enforce the intended overall wait budget while
still collecting all completed results. Keep uploader shutdown and termination
handling unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/design/gimin-`#141-worker-queue-backpressure-benchmark.md:
- Line 37: Update the server-tuning bullet in the benchmark document to replace
the nonexistent “OpenSQL” component with the actual PostgreSQL, MinIO, and
BGE-M3 components referenced elsewhere, preserving the intended exclusion scope.

In `@docs/test-results/gimin-`#141-worker-queue-backpressure-benchmark.md:
- Around line 39-64: 문서의 자동화 실행 결과에 Swagger UI 수동 검증 항목을 추가하세요. 실제로 실행하지 않았다면
결과를 추측하지 말고 상태를 “미실행”으로 기록하며 사유를 명시하세요. 또한 자동화 전용 보고서를 이 경로에 둘 수 있는지 관련 예외를
확인하고, 해당 문서 형식에 맞게 결과를 정리하세요.
- Line 5: 측정일 항목의 2026-08-11 값을 벤치마크가 실제로 실행된 날짜로 수정하세요. 실행일이 2026-08-11 이후라면
벤치마크를 실행한 뒤 문서를 갱신하고, 그렇지 않다면 실제 실행일을 기록하세요.

In
`@src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java`:
- Line 224: WorkerQueueBackpressureBenchmark 클래스의 `@Timeout` 값을 기본 부하 예산인 최대 8회 실행
× PROFILE_TIMEOUT_SECONDS 600초와 예열·정합성 질의 시간을 모두 포함하도록 3,600초보다 크게 조정하세요.

In
`@src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatistics.java`:
- Around line 79-83: Update the average queue-depth calculation in
WorkerQueueBackpressureStatistics to derive elapsedSeconds from the difference
between the final and first validated sample elapsedNanos values, matching the
integration interval used by queueDepthAucDocumentSeconds. Preserve the existing
zero-duration fallback to the first sample’s queue depth.

---

Nitpick comments:
In
`@src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java`:
- Around line 436-445: Update the future-collection loop in the benchmark’s
upload-result flow to catch per-future TimeoutException and convert it into an
UploadAttempt failure result, preserving the run for COLLAPSED evaluation
instead of propagating the exception. Avoid applying the full profile timeout
independently to every future; enforce the intended overall wait budget while
still collecting all completed results. Keep uploader shutdown and termination
handling unchanged.

In
`@src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatisticsTest.java`:
- Around line 61-85: 보호해야 할 입력 검증 계약에 대한 테스트가 누락되어 있습니다.
WorkerQueueBackpressureStatisticsTest에 parseProfiles의 null 또는 공백 rawValue가 기본
Profile 목록을 반환하는지 검증하는 테스트를 추가하고, summarizeQueue가 빈 목록과 시간이 역전된 QueueSample 목록에
IllegalArgumentException을 발생시키는지 각각 검증하세요.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0fce8449-6dab-4963-8992-bf70e7e42241

📥 Commits

Reviewing files that changed from the base of the PR and between a00368d and 860664b.

📒 Files selected for processing (6)
  • build.gradle
  • docs/design/gimin-#141-worker-queue-backpressure-benchmark.md
  • docs/test-results/gimin-#141-worker-queue-backpressure-benchmark.md
  • src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java
  • src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatistics.java
  • src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatisticsTest.java

Comment thread docs/design/gimin-#141-worker-queue-backpressure-benchmark.md Outdated

- 관련 이슈: [#141](https://github.com/DocGrid/backend/issues/141)
- 설계: [Worker Queue 적체·DB Pool Backpressure Benchmark 설계](../design/gimin-%23141-worker-queue-backpressure-benchmark.md)
- 측정일: 2026-08-11

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

측정일을 실제 실행일로 수정하세요.

현재 검토 기준일은 2026년 8월 10일입니다. Line 5는 측정일을 2026-08-11로 기록합니다. 실제 실행일이 2026년 8월 11일 이후라면 실행 후 문서를 갱신하세요. 그렇지 않다면 실제 실행일로 수정하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/test-results/gimin-`#141-worker-queue-backpressure-benchmark.md at line
5, 측정일 항목의 2026-08-11 값을 벤치마크가 실제로 실행된 날짜로 수정하세요. 실행일이 2026-08-11 이후라면 벤치마크를 실행한
뒤 문서를 갱신하고, 그렇지 않다면 실제 실행일을 기록하세요.

Comment thread docs/test-results/gimin-#141-worker-queue-backpressure-benchmark.md
Comment thread src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureBenchmark.java Outdated
Comment thread src/test/java/com/opensource/docgrid/e2e/WorkerQueueBackpressureStatistics.java Outdated
@Gimini-3
Gimini-3 merged commit 83c08df into develop Aug 10, 2026
1 check passed
@Gimini-3 Gimini-3 self-assigned this Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] 전체 인덱싱 Queue 적체 및 DB Connection Pool Backpressure Benchmark 추가

1 participant