Skip to content
Merged
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
id 'io.spring.dependency-management' version '1.1.7'
}

group = 'io.EJangs'
group = 'io.ejangs'
version = '1.0.0'

java {
Expand Down Expand Up @@ -60,6 +60,12 @@ dependencies {
testImplementation 'com.h2database:h2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.awaitility:awaitility:4.2.0'

implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.12.1'

implementation platform('software.amazon.awssdk:bom:2.42.35')
implementation 'software.amazon.awssdk:s3'

}

tasks.named('test') {
Expand Down
2 changes: 1 addition & 1 deletion perf/cleanup_perf_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ MODE="${MODE:-all}" # single | multi | all
USER_PASSWORD="${USER_PASSWORD:-Testtest1}"
TEST_EMAIL="${TEST_EMAIL:-test@test.com}"

USER_PREFIX="${USER_PREFIX:-perfdel}"
USER_PREFIX="${USER_PREFIX:-perfuser}"
USER_DOMAIN="${USER_DOMAIN:-test.com}"
USER_COUNT="${USER_COUNT:-100}"
SEARCH_PAGE_SIZE="${SEARCH_PAGE_SIZE:-100}"
Expand Down
30 changes: 22 additions & 8 deletions perf/delete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,31 @@ MONGO_URI='...' MYSQL_USERNAME='devbae' MYSQL_PASSWORD='' SPRING_PROFILES_ACTIVE
MAIL_USERNAME='...' MAIL_PASSWORD='...'
```

## 1) Prepare users (no script)
## 1) Prepare users

유저 생성은 애플리케이션의 `TestUserInitializer`를 사용합니다.
유저 생성은 애플리케이션의 `PerfDataInitializer`를 사용합니다.
삭제 벤치용으로 유저만 만들 때는 `DOCS_PER_USER`를 0으로 둡니다.

```bash
PERF_SEED_USER_COUNT=100
PERF_SEED_DOCS_PER_USER=0
```

`PerfDataInitializer`로 문서까지 직접 주입할 때는 아래 옵션도 같이 사용합니다.
이 경우 문서, 브랜치, 커밋, 간선, save, Mongo block/commitBlockSequence/saveContent가 생성됩니다.

```bash
PERF_SEED_RUN_ID=run01
PERF_SEED_DOCS_PER_USER=3
PERF_SEED_BRANCHES_PER_DOC=2
PERF_SEED_COMMITS_PER_BRANCH=6
PERF_SEED_BLOCKS_PER_SAVE=20
PERF_SEED_BLOCKS_PER_COMMIT=20
```

유저 패턴:

- `perfdel_u001@test.com` ~ `perfdel_u100@test.com`
- `perfuser_u001@test.com` ~ `perfuser_u100@test.com`
- 비밀번호: `Testtest1`

## 2) Seed realistic dataset
Expand All @@ -51,7 +65,7 @@ PERF_SEED_USER_COUNT=100
```bash
RUN_ID=run01 \
BASE_URL=http://localhost:8080 \
USER_PREFIX=perfdel USER_DOMAIN=test.com USER_PASSWORD=Testtest1 \
USER_PREFIX=perfuser USER_DOMAIN=test.com USER_PASSWORD=Testtest1 \
USER_COUNT=100 DOCS_PER_USER=3 \
MAIN_COMMITS=6 FEATURE_COMMITS=4 BLOCKS_PER_COMMIT=20 \
SEED_VUS=20 \
Expand All @@ -69,7 +83,7 @@ k6 run perf/delete/seed_dataset.js
```bash
RUN_ID=run01 \
BASE_URL=http://localhost:8080 \
USER_PREFIX=perfdel USER_DOMAIN=test.com USER_PASSWORD=Testtest1 \
USER_PREFIX=perfuser USER_DOMAIN=test.com USER_PASSWORD=Testtest1 \
USER_COUNT=100 DOCS_PER_USER=3 \
DELETE_VUS=30 \
k6 run perf/delete/delete_only_benchmark.js \
Expand All @@ -88,7 +102,7 @@ k6 run perf/delete/delete_only_benchmark.js \

1. 브랜치 checkout
2. 서버 실행
3. 유저 준비(`PERF_SEED_USER_COUNT` 적용된 상태)
3. 유저 준비(`PERF_SEED_USER_COUNT`, `PERF_SEED_DOCS_PER_USER=0` 적용된 상태)
4. 데이터 생성 (`seed_dataset.js`)
5. 삭제 벤치 실행 (`delete_only_benchmark.js`)
6. 결과 파일 저장
Expand Down Expand Up @@ -120,7 +134,7 @@ node perf/delete/compare_delete_summary.mjs \
```bash
BASE_URL=http://localhost:8080 \
MODE=multi \
USER_PREFIX=perfdel USER_DOMAIN=test.com USER_COUNT=100 \
USER_PREFIX=perfuser USER_DOMAIN=test.com USER_COUNT=100 \
USER_PASSWORD=Testtest1 \
bash perf/cleanup_perf_docs.sh
```
Expand All @@ -131,7 +145,7 @@ staging HTTPS(자체 서명 인증서)면:
BASE_URL=https://<stg-domain-or-ip>:8443 \
INSECURE_TLS=1 \
MODE=multi \
USER_PREFIX=perfdel USER_DOMAIN=test.com USER_COUNT=100 \
USER_PREFIX=perfuser USER_DOMAIN=test.com USER_COUNT=100 \
USER_PASSWORD=Testtest1 \
bash perf/cleanup_perf_docs.sh
```
2 changes: 1 addition & 1 deletion perf/delete/delete_only_benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { check } from 'k6';
import { Rate, Trend } from 'k6/metrics';

const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
const USER_PREFIX = __ENV.USER_PREFIX || 'perfdel';
const USER_PREFIX = __ENV.USER_PREFIX || 'perfuser';
const USER_DOMAIN = __ENV.USER_DOMAIN || 'test.com';
const USER_PASSWORD = __ENV.USER_PASSWORD || 'Testtest1';
const USER_COUNT = Number(__ENV.USER_COUNT || 50);
Expand Down
10 changes: 4 additions & 6 deletions perf/delete/seed_dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { check } from 'k6';
import { Rate, Trend } from 'k6/metrics';

const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
const USER_PREFIX = __ENV.USER_PREFIX || 'perfdel';
const USER_PREFIX = __ENV.USER_PREFIX || 'perfuser';
const USER_DOMAIN = __ENV.USER_DOMAIN || 'test.com';
const USER_PASSWORD = __ENV.USER_PASSWORD || 'Testtest1';
const USER_COUNT = Number(__ENV.USER_COUNT || 50);
Expand Down Expand Up @@ -132,12 +132,10 @@ function buildCommitBody(title, branchId) {
for (let i = 0; i < BLOCKS_PER_COMMIT; i += 1) {
const blockId = `${title}-b${i}-${Math.floor(Math.random() * 1e6)}`;
blocks.push({
id: blockId,
type: 'paragraph',
data: {
id: blockId,
type: 'paragraph',
data: {
text: `${title}-text-${i}`,
},
text: `${title}-text-${i}`,
},
});
blockOrders.push(blockId);
Expand Down
112 changes: 112 additions & 0 deletions perf/read/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Document List Performance Benchmark

목표:

- 문서 목록 조회 경로의 읽기 성능을 별도로 측정
- `sidebar`(최근 활동만)와 `full list`(preview 포함), `search`(preview 포함)를 분리 비교
- 문서 수, branch 수, preview 조립 비용이 응답 시간에 미치는 영향을 확인

## Files

- `perf/delete/seed_dataset.js`
- 목록 테스트에 사용할 문서/브랜치/커밋 데이터를 생성
- `perf/read/doc_list_benchmark.js`
- `sidebar`, `full list`, `search` 읽기 성능 측정

## Why this benchmark

현재 목록 조회는 `Doc` 페이지 조회 후, 각 문서마다 최근 branch를 찾고 preview를 조립합니다.
즉 `sidebar`는 JPA 연관 로딩 비용, `full list`와 `search`는 여기에 Mongo preview 조립 비용까지 추가로 확인할 수 있습니다.

## 1) Prepare users

유저 생성은 애플리케이션의 `PerfDataInitializer`를 사용합니다.
API seed 스크립트로 문서를 만들 때는 여기서는 유저만 준비합니다.

```bash
PERF_SEED_USER_COUNT=50
PERF_SEED_DOCS_PER_USER=0
```

유저 패턴:

- `perfuser_u001@test.com` ~ `perfuser_u050@test.com`
- 비밀번호: `Testtest1`

## 2) Seed dataset

삭제 벤치에서 쓰던 seed 스크립트를 그대로 재사용합니다.
중요한 건 목록 조회 시 문서별 branch/commit이 충분히 많아지도록 데이터를 만드는 것입니다.

```bash
RUN_ID=read01 \
BASE_URL=http://localhost:8080 \
USER_PREFIX=perfuser USER_DOMAIN=test.com USER_PASSWORD=Testtest1 \
USER_COUNT=50 DOCS_PER_USER=5 \
MAIN_COMMITS=8 FEATURE_COMMITS=5 BLOCKS_PER_COMMIT=100 \
SEED_VUS=20 \
k6 run perf/delete/seed_dataset.js
```

애플리케이션 initializer로 DB에 직접 주입할 수도 있습니다. 이 방식은 API 호출 비용 없이
문서, 브랜치, 커밋, 간선, save, Mongo block/commitBlockSequence/saveContent를 생성합니다.

```bash
PERF_SEED_RUN_ID=read01 \
PERF_SEED_USER_COUNT=50 \
PERF_SEED_DOCS_PER_USER=5 \
PERF_SEED_BRANCHES_PER_DOC=2 \
PERF_SEED_COMMITS_PER_BRANCH=8 \
PERF_SEED_BLOCKS_PER_SAVE=100 \
PERF_SEED_BLOCKS_PER_COMMIT=100
```

권장 기준:

- `DOCS_PER_USER`: 5 이상
- `MAIN_COMMITS`: 8 이상
- `FEATURE_COMMITS`: 5 이상
- `BLOCKS_PER_COMMIT`: 100 이상

## 3) Run list benchmark

```bash
RUN_ID=read01 \
BASE_URL=http://localhost:8080 \
USER_PREFIX=perfuser USER_DOMAIN=test.com USER_PASSWORD=Testtest1 \
USER_COUNT=50 DOCS_PER_USER=5 PAGE_SIZE=10 \
SEARCH_PREFIX=PDEL \
SIDEBAR_VUS=10 FULL_LIST_VUS=10 SEARCH_VUS=10 \
k6 run perf/read/doc_list_benchmark.js
```

`PerfDataInitializer`로 직접 주입한 데이터는 문서 제목 prefix가 `PERF`이므로 검색 벤치에서
아래처럼 맞춥니다.

```bash
SEARCH_PREFIX=PERF
```

결과 파일:

- `perf/read/results/doc_list_benchmark_<RUN_ID>.json`

핵심 지표:

- `op_doc_sidebar_ms`
- `op_doc_list_ms`
- `op_doc_search_ms`
- `http_req_duration`
- `http_req_failed`

## 4) Recommended comparison order

1. `sidebar` vs `full list`
2. `full list` vs `search`
3. 같은 조건에서 `PAGE_SIZE=10`, `20`, `50` 비교

해석 기준:

- `sidebar`보다 `full list`가 크게 느리면 preview 조립 비용 영향이 큼
- `search`까지 더 느리면 목록 조립 비용 + 검색 쿼리 비용이 함께 작동
- `PAGE_SIZE` 증가에 따라 p95가 급격히 오르면 per-doc 조립 비용이 병목일 가능성이 큼
Loading
Loading