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
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@
"title": "CB 호출 결과 (성공/실패/차단)",
"description": "failed 비율 50% + 5초 지속 시 OPEN 임박. not_permitted 증가 = CB가 OPEN 상태에서 차단 중.",
"type": "timeseries",
"targets": [ { "expr": "sum by (name, kind) (rate(resilience4j_circuitbreaker_calls_total[5m]))", "legendFormat": "{{name}} {{kind}}", "refId": "A", "datasource": { "type": "prometheus", "uid": "DS_PROMETHEUS" } } ]
"targets": [ { "expr": "sum by (name, kind) (rate(resilience4j_circuitbreaker_calls_seconds_count[5m])) or label_replace(sum by (name) (rate(resilience4j_circuitbreaker_not_permitted_calls_total[5m])), \"kind\", \"not_permitted\", \"\", \"\")", "legendFormat": "{{name}} {{kind}}", "refId": "A", "datasource": { "type": "prometheus", "uid": "DS_PROMETHEUS" } } ]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

PromQL에서 label_replace를 사용하여 고정된 값의 라벨을 추가할 때, src_labelregex를 빈 문자열("")로 지정하는 방식은 일부 Prometheus 호환 TSDB(예: VictoriaMetrics, Thanos 등)나 구버전 Prometheus에서 파싱 에러를 유발하거나 의도치 않게 동작할 수 있습니다.\n\n안전하고 표준적인 방법은 이미 존재하는 라벨(여기서는 sum by (name)을 통해 보존된 name 라벨)을 src_label로 지정하고, 정규식 ".*"을 매칭시켜 라벨을 추가하는 것입니다.

Suggested change
"targets": [ { "expr": "sum by (name, kind) (rate(resilience4j_circuitbreaker_calls_seconds_count[5m])) or label_replace(sum by (name) (rate(resilience4j_circuitbreaker_not_permitted_calls_total[5m])), \"kind\", \"not_permitted\", \"\", \"\")", "legendFormat": "{{name}} {{kind}}", "refId": "A", "datasource": { "type": "prometheus", "uid": "DS_PROMETHEUS" } } ]
"targets": [ { "expr": "sum by (name, kind) (rate(resilience4j_circuitbreaker_calls_seconds_count[5m])) or label_replace(sum by (name) (rate(resilience4j_circuitbreaker_not_permitted_calls_total[5m])), \"kind\", \"not_permitted\", \"name\", \".*\")", "legendFormat": "{{name}} {{kind}}", "refId": "A", "datasource": { "type": "prometheus", "uid": "DS_PROMETHEUS" } } ]

},

{ "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 68 }, "id": 900, "title": "Row 9 — 시스템 자원", "type": "row" },
Expand Down
12 changes: 5 additions & 7 deletions k6/01-store-browse.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
* - GET /stores/{id} (상세)
* - GET /remains (시간대별 좌석)
*
* 전체 소요 시간: 약 9분
* 전체 소요 시간: 약 5분
* [0s ~ ~2m50s] event_spike — 워밍업 후 50명 즉시 점프
* [3m20s ~ ~9m] ramp_up — 0→50명 단계적 증가
* [3m ~ ~5m] ramp_up — 0→50명 단축 단계 (10→30→50, 임계점 1차 탐색)
*
* [두 시나리오 비교 포인트]
* - nearby / in-bounds: PostGIS 쿼리는 GIST 인덱스가 없으면 spike 구간에서 타임아웃
Expand Down Expand Up @@ -74,16 +74,14 @@ export const options = {
// ── SCENARIO B: 점진적 증가 ────────────────────────────────────────────
// 목적: 몇 명부터 응답시간이 꺾이는지 임계점 탐색
// event_spike와 달리 서버가 단계적으로 적응하면서 50명에 도달
// 체크: 10→20→35→50 각 단계에서 nearby p95 변화량 확인
// 체크: 10→30→50 각 단계에서 nearby p95 변화량 확인
ramp_up: {
executor: 'ramping-vus',
startVUs: 0,
startTime: '3m20s',
startTime: '3m',
stages: [
{ duration: '30s', target: 10 },
{ duration: '30s', target: 20 },
{ duration: '30s', target: 35 },
{ duration: '1m', target: 50 },
{ duration: '30s', target: 30 },
{ duration: '30s', target: 50 },
{ duration: '30s', target: 0 },
],
Expand Down
32 changes: 7 additions & 25 deletions k6/03-full-flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*
* 시나리오: 홈 진입 → 매장 검색 → 상세 조회 → 메뉴/리뷰 확인 → 좌석 확인
*
* 전체 소요 시간: 약 9분
* 전체 소요 시간: 약 5분
* [0s ~ ~2m50s] event_spike — 워밍업 후 50명 즉시 점프
* [3m20s ~ ~9m] ramp_up — 0→50명 단계적 증가
* [3m ~ ~5m] ramp_up — 0→50명 단축 단계 (10→30→50, 임계점 1차 탐색)
*/
import http from 'k6/http';
import { sleep, check, group } from 'k6';
Expand Down Expand Up @@ -35,23 +35,8 @@ const errorRate = new Rate('flow_error_rate');
export const options = {
scenarios: {

// ── SCENARIO A: 이벤트 스파이크 ────────────────────────────────────────
// 실제 상황: 오전 10시 이벤트 오픈, 좌석 공개처럼 특정 시각에 트래픽이 몰리는 상황
//
// [워밍업을 추가한 이유]
// 실제 서비스에서 이벤트가 오픈되는 시점의 서버는 이미 운영 중인 상태.
// JVM JIT 컴파일과 DB 커넥션풀이 확보된 상태에서 갑자기 50명이 몰리는 것이 현실적.
// 워밍업 없이 바로 50명을 붙이면 JVM 콜드 스타트 비용이 포함되어
// 실제 이벤트 상황의 성능과 다른 결과가 나옴.
//
// [ramping-vus를 쓴 이유]
// warmup(10명) + constant(50명)을 별도 시나리오로 돌리면 동시 실행되어
// 실제로는 10 + 50 = 60명이 되는 문제가 생김.
// ramping-vus 하나로 합쳐야 정확히 50명으로 제어 가능.
//
// [체크포인트]
// 점프 직후(30~35s) Step별 p95 중 어느 step이 먼저 터지는지 확인
// → 가장 먼저 급등하는 step = 이벤트 상황에서의 첫 번째 병목
// SCENARIO A: 이벤트 스파이크 — 50명 즉시 점프로 이벤트 오픈 순간 재현 (패턴 근거는 01-store-browse.js 헤더)
// 체크: 점프 직후 Step별 p95 — 가장 먼저 급등하는 step = 첫 번째 병목
event_spike: {
executor: 'ramping-vus',
startVUs: 0,
Expand All @@ -64,17 +49,14 @@ export const options = {
tags: { scenario: 'event_spike' },
},

// ── SCENARIO B: 점진적 증가 ────────────────────────────────────────────
// 목적: 몇 명부터 어느 step이 먼저 나빠지는지 임계점 탐색
// SCENARIO B: 점진적 증가 — 임계점 1차 탐색 (몇 명부터 어느 step이 먼저 나빠지는가)
ramp_up: {
executor: 'ramping-vus',
startVUs: 0,
startTime: '3m20s',
startTime: '3m',
stages: [
{ duration: '30s', target: 10 },
{ duration: '30s', target: 20 },
{ duration: '30s', target: 35 },
{ duration: '1m', target: 50 },
{ duration: '30s', target: 30 },
{ duration: '30s', target: 50 },
{ duration: '30s', target: 0 },
],
Expand Down
Loading
Loading