Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions docs/test-results/evidence/issue-374/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# WebSocket 대시보드 권한 검증 부하 시험 원본 목록

관련 이슈: [#374](https://github.com/DocGrid/docgrid/issues/374) · [해석 보고서](../../gimin-374-stomp-dashboard-outbound-load-20261001.md)

2026-10-01 GCP 내부 시험에서 수집한 클라이언트 결과 JSON 12개와 앱 메트릭 JSONL 10개를 **시험 목적·버전·구독자 수·회차별 별도 파일**로 보존한다. [핵심 근거 로그](key-evidence-logs-20261001.md)에서 전후 수치, 앱 journal 선별 행, JVM 스택을 함께 읽을 수 있다. `base`는 보안 수정 전 커밋 `f6213bbdb6f487af00727be156da0710d619cc6a`, `fix`는 #373의 커밋 `b425c3535194be6719b75ef79cf5100d9a86be97`이다. 접미사 없는 50개 파일이 1회차이며 `r2`, `r3`가 2·3회차다.

| 목적·회차 | 수신 결과 | 앱 메트릭 | 관측 창 | 수신 건수 | p95 |
| --- | --- | --- | ---: | ---: | ---: |
| 기존 1명, 스모크 | [`base-n1.json`](runs/base-n1.json) | 없음 | 12초 | 40 | 2.874 ms |
| 수정 1명, 스모크 | [`fix-n1.json`](runs/fix-n1.json) | 없음 | 12초 | 40 | 55.995 ms |
| 기존 5명 | [`base-n5.json`](runs/base-n5.json) | [`base-n5-metrics.jsonl`](metrics/base-n5-metrics.jsonl) | 30초 | 500 | 3.637 ms |
| 수정 5명 | [`fix-n5.json`](runs/fix-n5.json) | [`fix-n5-metrics.jsonl`](metrics/fix-n5-metrics.jsonl) | 30초 | 500 | 217.529 ms |
| 기존 20명 | [`base-n20.json`](runs/base-n20.json) | [`base-n20-metrics.jsonl`](metrics/base-n20-metrics.jsonl) | 30초 | 2,000 | 5.180 ms |
| 수정 20명 | [`fix-n20.json`](runs/fix-n20.json) | [`fix-n20-metrics.jsonl`](metrics/fix-n20-metrics.jsonl) | 30초 | 599 | 969.252 ms |
| 기존 50명, 1회 | [`base-n50.json`](runs/base-n50.json) | [`base-n50-metrics.jsonl`](metrics/base-n50-metrics.jsonl) | 30초 | 5,000 | 9.117 ms |
| 기존 50명, 2회 | [`base-n50-r2.json`](runs/base-n50-r2.json) | [`base-n50-r2-metrics.jsonl`](metrics/base-n50-r2-metrics.jsonl) | 30초 | 5,000 | 8.475 ms |
| 기존 50명, 3회 | [`base-n50-r3.json`](runs/base-n50-r3.json) | [`base-n50-r3-metrics.jsonl`](metrics/base-n50-r3-metrics.jsonl) | 30초 | 5,000 | 8.011 ms |
| 수정 50명, 1회 | [`fix-n50.json`](runs/fix-n50.json) | [`fix-n50-metrics.jsonl`](metrics/fix-n50-metrics.jsonl) | 30초 | 603 | 2,386.041 ms |
| 수정 50명, 2회 | [`fix-n50-r2.json`](runs/fix-n50-r2.json) | [`fix-n50-r2-metrics.jsonl`](metrics/fix-n50-r2-metrics.jsonl) | 30초 | 588 | 2,451.737 ms |
| 수정 50명, 3회 | [`fix-n50-r3.json`](runs/fix-n50-r3.json) | [`fix-n50-r3-metrics.jsonl`](metrics/fix-n50-r3-metrics.jsonl) | 30초 | 588 | 2,443.748 ms |

## 읽는 방법과 한계

- 결과 JSON의 `frames_received`는 관측 창에서 **전체 수신자가 받은 프레임 합계**다. `interior_sequence_gaps=0`은 받은 첫·마지막 sequence 사이에 구멍이 없다는 뜻일 뿐, 예정된 주기의 push가 모두 생성됐다는 뜻이 아니다.
- `latency_ms`는 임시 publisher의 `sentEpochMillis`와 부하 VM 수신 시각의 차이다. 두 VM을 같은 NTP 기준으로 동기화한 후의 결과만 이 디렉터리에 넣었다. 앞선 시간 동기화 전 음수 지연 2회는 제외했다.
- 메트릭 JSONL의 `at`은 UTC다. 보고서의 사람이 읽는 로그 시각은 KST다. 앱 지표 채집 창은 클라이언트 관측 창보다 길어 백그라운드 작업도 포함한다. 메트릭에서 메시지당 SQL 수를 직접 계산하지 않는다.
- 클라이언트 결과 JSON에는 절대 실행 시각이나 UUID run ID가 없다. **파일명과 이 목록**으로 회차를 매핑한다. 1명 스모크에는 앱 메트릭 파일이 없고, 1·5·20명은 반복 실행이 없어 신뢰구간을 주장하지 않는다.
- DB snapshot 원본에는 내부 주소가 있어 `server_ip`를 제거한 [전후 4개 파일](db/)만 공개한다. JVM 덤프는 PID·tid·nid·16진 주소를 가리고 끝의 빈 줄·공백을 정리한 [1116줄 전체 내용](jvm-thread-dump-fix-n50-redacted.txt)과 [핵심 발췌](stack-excerpt-fix-n50.txt)를 공개한다. 두 증거 모두 개인정보·내부 주소를 뺀 변형본이므로 원래 바이트와 같지는 않다.
- [`websocket_dashboard_load.py`](../../../../scripts/opensql/websocket_dashboard_load.py)와 [`websocket_dashboard_metrics.py`](../../../../scripts/opensql/websocket_dashboard_metrics.py)는 실행 당시 스크립트의 측정 로직을 보존하되, 추후 실패 시 예외 문자열에 내부 URL이 기록되지 않도록 **예외 클래스명만 저장하는 비식별 수정**을 했다. 임시 Java `wsbench` publisher·시험용 ADMIN fixture는 저장소에 포함하지 않으므로 이 두 스크립트만으로 당시 합성 부하를 끝까지 재현할 수는 없다.

## 공개 범위

원본 JSON/JSONL에는 토큰·암호·계정·내부 IP·프로젝트 ID를 넣지 않았다. DB·JVM 파일은 위 필드를 제거한 뒤에만 공개본으로 기록했다. 별도 journal에서 필요한 기동·경고·종료 항목은 보고서에 기록 전에 비식별화된 한국어 표로만 옮겼다. 공개 GitHub에 보관하는 것은 이 선별 결과이며, 원래 VM의 **전체 앱 journal**을 보존했다는 뜻은 아니다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 공개 측정 증거 검증 로그 — 2026-10-01

목적: 이슈 #374의 PR #375에 담을 WebSocket 부하 측정 파일이 회차별로 분리돼 있고, 공개본의 숫자가 원본과 일치하며, 알려진 민감정보 패턴이 없는지 확인한다. 실행 위치는 `test/374` 브랜치의 저장소 루트다. 이는 **기존 클라우드 부하 시험의 증거 검증**이지 새 GCP 부하 시험이 아니다.

최종 공개 전 별도 재검증은 [22:46 KST 실행 로그](publication-check-20261001-2246.md)에 기록했다.

| 실행 시각(KST) | 명령·절차 | 수치·결과 | 해석 |
| --- | --- | --- | --- |
| 2026-10-01 22:23 | `python3 -m unittest -v scripts.opensql.test_websocket_dashboard_evidence` | 3개 테스트, 실패 0건, 약 0.006초 | 12개 회차 파일, 10개 앱 지표 파일, 50명 3회 중앙값 대조 통과 |
| 2026-10-01 22:23 | `python3 -m py_compile scripts/opensql/websocket_dashboard_load.py scripts/opensql/websocket_dashboard_metrics.py` | 두 파일 구문 검사 성공 | 클라이언트 코드는 구문상 유효함. `websockets` 패키지가 현재 로컬 환경에 없어 실제 연결 실행은 하지 않음 |
| 2026-10-01 22:23 | `jq -e . runs/*.json metrics/*.jsonl >/dev/null` (실제로는 `evidence/issue-374/` 경로 지정) | JSON 12개·JSONL 10개 파싱 성공 | 공개 원본에 JSON 문법 오류 없음 |
| 2026-10-01 22:23 | 임시 보관 원본과 공개본 22개 파일을 파일명별 `cmp -s` | 불일치 0건 | 공개 JSON/JSONL은 수치 편집 없이 그대로 복사됨 |
| 2026-10-01 22:23 | 공개 보고서·코드·원본에 대해 프로젝트 ID, 내부 IP, JWT 형태, 개인 홈 경로, PEM 키 패턴을 `rg -l`로 검사 | 일치 파일 0개 | 이 패턴의 민감값은 찾지 못함. 모든 비밀 유형을 증명하는 검사는 아니므로 PR 직전 변경 파일을 재검토함 |
| 2026-10-01 22:24 | `git diff --cached --check`와 변경 파일 목록 확인 | 28개 파일, 공백 오류 0건 | 의도한 측정 자료·스크립트만 스테이징됨 |
| 2026-10-01 22:28 | 50명 수정 버전 JVM 덤프의 핵심 프레임을 대조하고 JVM 주소·스레드 ID를 제외한 발췌 생성 | `MessageBroker → SimpleBroker fan-out → outbound 인가 → primary 역할 조회 → PostgreSQL 응답 대기` 순서 확인 | 전체 덤프 대신 분석에 필요한 호출 경로만 공개. 발췌는 원본 전체가 아님 |
| 2026-10-01 22:42 | 원본 JVM 덤프를 PID·tid·nid·16진 주소 치환 후 최초 공개 후보와 `cmp -` 대조 | **원본 1117줄**, 치환 후 불일치 0건, 원래 주소 잔여 0건 | 이후 끝의 빈 줄·공백을 정리해 최종 공개본은 1116줄. 호출 프레임은 보존 |
| 2026-10-01 22:42 | DB 전후 스냅샷 4개에 `jq 'map(del(.server_ip))'` 적용 후 공개본과 `cmp -` 대조 | **4개 일치**, 각 파일 primary 1·standby 2 | 내부 IP만 제외하고 전후 거래 지표를 보존 |
| 2026-10-01 22:42 | `python3 -m unittest -v scripts.opensql.test_websocket_dashboard_evidence` 재실행 | **5개 테스트 통과, 실패 0건** | 기존 3개 검사에 JVM 덤프·DB 스냅샷 무결성 2개를 추가 |
| 2026-10-01 22:42 | 공개 증거·문서에 내부 IP·프로젝트 ID·JWT·이메일·개인 홈 경로 패턴 `rg -l` 검사 | 일치 파일 0개 | 패턴 기반 비식별 검사이며 알려지지 않은 모든 민감값을 배제한다는 보장은 아님 |

## 한계

- 앱 journal 선별 로그는 과거 시험 중 실시간으로 수집해 [보고서](../../gimin-374-stomp-dashboard-outbound-load-20261001.md)에 기록했다. 이번에는 남아 있던 JVM 전체 덤프의 [비식별본](jvm-thread-dump-fix-n50-redacted.txt)과 DB 전후 스냅샷의 [비식별본](db/)도 추가했다. [핵심 근거 로그](key-evidence-logs-20261001.md)는 원본과 계산값을 구분해 인용한다. 삭제된 임시 VM에 다시 접속하거나 새로운 부하를 발생시키지는 않았다.
- 임시 Java publisher·시험용 계정 fixture는 공개하지 않았으므로, 이번에 보관한 Python 클라이언트만으로 당시 합성 시험을 곧바로 다시 실행할 수 없다.
- 외부 접속·부하 재시험, 2백엔드 분산, 관리자 역할 회수 중 부하의 동시 재현은 이 검증 로그의 범위가 아니다.
44 changes: 44 additions & 0 deletions docs/test-results/evidence/issue-374/db/db-after-base-n50.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"sampled_at": "2026-10-01T12:40:38.239142+00:00",
"standby": false,
"numbackends": 6,
"xact_commit": 48272,
"xact_rollback": 46,
"tup_returned": 17082949,
"tup_fetched": 359967,
"tup_inserted": 5073,
"tup_updated": 1058,
"tup_deleted": 163,
"blks_hit": 1383921,
"blks_read": 102
},
{
"sampled_at": "2026-10-01T12:40:38.273828+00:00",
"standby": true,
"numbackends": 3,
"xact_commit": 2699,
"xact_rollback": 6,
"tup_returned": 144548,
"tup_fetched": 61151,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 102951,
"blks_read": 0
},
{
"sampled_at": "2026-10-01T12:40:38.30512+00:00",
"standby": true,
"numbackends": 4,
"xact_commit": 2784,
"xact_rollback": 13,
"tup_returned": 156159,
"tup_fetched": 63725,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 105962,
"blks_read": 0
}
]
44 changes: 44 additions & 0 deletions docs/test-results/evidence/issue-374/db/db-after-n50.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"sampled_at": "2026-10-01T12:31:08.226692+00:00",
"standby": false,
"numbackends": 6,
"xact_commit": 46828,
"xact_rollback": 46,
"tup_returned": 17068138,
"tup_fetched": 359471,
"tup_inserted": 5071,
"tup_updated": 1058,
"tup_deleted": 163,
"blks_hit": 1381276,
"blks_read": 102
},
{
"sampled_at": "2026-10-01T12:31:08.262484+00:00",
"standby": true,
"numbackends": 3,
"xact_commit": 2163,
"xact_rollback": 6,
"tup_returned": 141955,
"tup_fetched": 60126,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 99831,
"blks_read": 0
},
{
"sampled_at": "2026-10-01T12:31:08.292662+00:00",
"standby": true,
"numbackends": 4,
"xact_commit": 2273,
"xact_rollback": 13,
"tup_returned": 147397,
"tup_fetched": 61041,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 101333,
"blks_read": 0
}
]
44 changes: 44 additions & 0 deletions docs/test-results/evidence/issue-374/db/db-before-base-n50.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"sampled_at": "2026-10-01T12:39:23.933737+00:00",
"standby": false,
"numbackends": 6,
"xact_commit": 48062,
"xact_rollback": 46,
"tup_returned": 17079923,
"tup_fetched": 359804,
"tup_inserted": 5073,
"tup_updated": 1058,
"tup_deleted": 163,
"blks_hit": 1383319,
"blks_read": 102
},
{
"sampled_at": "2026-10-01T12:39:24.000597+00:00",
"standby": true,
"numbackends": 3,
"xact_commit": 2586,
"xact_rollback": 6,
"tup_returned": 144406,
"tup_fetched": 61015,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 102491,
"blks_read": 0
},
{
"sampled_at": "2026-10-01T12:39:24.075189+00:00",
"standby": true,
"numbackends": 4,
"xact_commit": 2737,
"xact_rollback": 13,
"tup_returned": 156016,
"tup_fetched": 63589,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 105394,
"blks_read": 0
}
]
44 changes: 44 additions & 0 deletions docs/test-results/evidence/issue-374/db/db-before-n50.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"sampled_at": "2026-10-01T12:29:28.751072+00:00",
"standby": false,
"numbackends": 6,
"xact_commit": 44778,
"xact_rollback": 46,
"tup_returned": 17061806,
"tup_fetched": 357764,
"tup_inserted": 5071,
"tup_updated": 1058,
"tup_deleted": 163,
"blks_hit": 1376919,
"blks_read": 102
},
{
"sampled_at": "2026-10-01T12:29:28.813629+00:00",
"standby": true,
"numbackends": 3,
"xact_commit": 2103,
"xact_rollback": 6,
"tup_returned": 141812,
"tup_fetched": 59989,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 99508,
"blks_read": 0
},
{
"sampled_at": "2026-10-01T12:29:28.848265+00:00",
"standby": true,
"numbackends": 4,
"xact_commit": 2185,
"xact_rollback": 13,
"tup_returned": 147076,
"tup_fetched": 60739,
"tup_inserted": 0,
"tup_updated": 0,
"tup_deleted": 0,
"blks_hit": 100435,
"blks_read": 0
}
]
Loading
Loading