signal-batch/docs/cache-benchmark-report.md
htlee 2e9361ee58 refactor: SNP API 전환 및 레거시 코드 전면 정리
- CollectDB 다중 신호 수집 → S&P Global AIS API 단일 수집으로 전환
- sig_src_cd + target_id 이중 식별자 → mmsi(VARCHAR) 단일 식별자
- t_vessel_latest_position → t_ais_position 테이블 전환
- 레거시 배치/유틸 ~30개 클래스 삭제 (VesselAggregationJobConfig, ShipKindCodeConverter 등)
- AisTargetCacheManager 기반 캐시 이중 구조 (최신위치 + 트랙 버퍼)
- CacheBasedVesselTrackDataReader + CacheBasedTrackJobListener 신규 추가
- VesselStaticStepConfig: 정적정보 CDC 변경 검출 + hourly job 편승
- SignalKindCode enum: vesselType/extraInfo 기반 선종 자동 분류
- WebSocket/STOMP 전체 mmsi 전환 (StompTrackStreamingService ~40곳)
- 모니터링/성능 최적화 코드 mmsi 기반 전환
- DataSource 설정 통합 (snpdb 단일 DB)
- AreaBoundaryCache Polygon→Geometry 캐스트 수정 (MULTIPOLYGON 지원)
- ConcurrentHashMap 적용 (VesselTrackStepConfig 동시성 버그 수정)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:59:49 +09:00

314 lines
14 KiB
Markdown
Raw Blame 히스토리

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 일일 캐시 성능 벤치마크 보고서
## 선박 항적 리플레이 서비스 — 캐시 vs DB 정량 비교
| 항목 | 내용 |
|------|------|
| 측정일 | 2026-02-07 |
| 대상 시스템 | Signal Batch — ChunkedTrackStreamingService (WebSocket 스트리밍) |
| 운영 환경 | prod 프로파일, Query DB 커넥션 풀 180 |
| 캐시 구성 | DailyTrackCacheManager — D-1 ~ D-7 인메모리 캐시, STRtree 공간 인덱스 |
| 측정 방식 | QueryBenchmark 내부 클래스 → `cache-benchmark.log` JSON 기록 |
| 샘플 수 | 12건 (CACHE 3, DB 2, HYBRID 5, CACHE+Today 2) |
---
## 1. 측정 경로 분류
쿼리 시간 범위에 따라 4가지 경로로 처리된다.
| 경로 | 설명 | 데이터 소스 |
|------|------|------------|
| **CACHE** | 요청 일자 전체가 인메모리 캐시에 존재 | 메모리 |
| **DB** | 캐시 미스 — Daily 테이블 직접 조회 | DB |
| **HYBRID** | 캐시 히트 일자 + 캐시 범위 밖 일자 DB 조회 | 메모리 + DB |
| **CACHE+Today** | 캐시 히트 + 오늘 데이터(Hourly/5min 테이블) | 메모리 + DB |
### 오늘 데이터 구간 구조
오늘(D-0) 데이터는 캐시 대상이 아니며, 시간 경과에 따라 두 테이블로 분할 조회된다.
```
오늘 00:00 ~ 12:00 12:00 ~ 12:35 현재(12:40)
├──── Hourly 테이블 조회 ──────┤── 5min 조회 ──┤
(12개 범위, 1시간 단위) (7개 범위, 5분 단위)
```
- **Hourly**: 자정부터 약 1시간 전까지 → 시간 단위 범위 (약 12개)
- **5min**: 최근 약 1시간 이내 → 5분 단위 범위 (약 7개)
- 각 범위마다 DB 커넥션 1회 + Viewport Pass1 1회 발생 → 오늘 구간 커넥션 = 범위 수 × 2
---
## 2. 전체 측정 데이터
### 2.1 요약 테이블
| # | 경로 | Zoom | 일수 | 캐시/DB | 선박 수 | 트랙 수 | 응답시간(ms) | DB커넥션 | DB쿼리시간(ms) |
|---|------|------|------|---------|---------|---------|-------------|----------|---------------|
| 1 | CACHE | 10 | 3 | 3/0 | 443 | 986 | **575** | 3 | 0 |
| 2 | DB | 10 | 2 | 0/2 | 352 | 587 | **7,221** | 8 | 3,475 |
| 3 | DB | 10 | 2 | 0/2 | 12,253 | 18,502 | **8,195** | 19 | 1,443 |
| 4 | CACHE | 10 | 2 | 2/0 | 10,690 | 16,942 | **1,439** | 2 | 0 |
| 5 | CACHE | 10 | 2 | 2/0 | 10,690 | 16,942 | **1,374** | 2 | 0 |
| 6 | HYBRID | 8 | 5 | 3/2 | 9,958 | 29,362 | **8,900** | 16 | 3,301 |
| 7 | HYBRID | 9 | 5 | 3/2 | 547 | 1,927 | **1,373** | 11 | 550 |
| 8 | HYBRID | 8 | 5 | 3/2 | 4,589 | 12,422 | **2,910** | 12 | 715 |
| 9 | HYBRID | 8 | 5 | 3/2 | 5,760 | 23,283 | **3,651** | 15 | 1,048 |
| 10 | CACHE+Today | 10 | 3+오늘 | 3/0 | 105 | 301 | **6,091** | 56 | 0 |
| 11 | HYBRID | 8 | 5 | 3/2 | 52,151 | 162,849 | **105,212** | 45 | 93,319 |
| 12 | CACHE+Today | 12 | 3+오늘 | 3/0 | 6,990 | 17,024 | **9,744** | 56 | 0 |
### 2.2 DB 커넥션 세분화
| # | 경로 | 합계 | Viewport Pass1 | Daily Pages | Hourly/5min | TableCheck |
|---|------|------|----------------|-------------|-------------|------------|
| 1 | CACHE | 3 | 0 | 0 | 0 | **3** |
| 2 | DB | 8 | 2 | 2 | 0 | 2 |
| 3 | DB | 19 | 2 | 2 | 0 | 2 |
| 4 | CACHE | 2 | 0 | 0 | 0 | **2** |
| 5 | CACHE | 2 | 0 | 0 | 0 | **2** |
| 6 | HYBRID | 16 | 2 | 2 | 0 | 5 |
| 7 | HYBRID | 11 | 2 | 2 | 0 | 5 |
| 8 | HYBRID | 12 | 2 | 2 | 0 | 5 |
| 9 | HYBRID | 15 | 2 | 2 | 0 | 5 |
| 10 | CACHE+Today | 56 | **21** | 0 | **21** | **14** |
| 11 | HYBRID | 45 | 2 | **6** | 0 | 5 |
| 12 | CACHE+Today | 56 | **21** | 0 | **21** | **14** |
> 합산 검증: 전 12건 모두 세분화 카운터 합 = 합계 일치 확인 (VesselInfo 카운터 포함, 표에서는 생략).
**CACHE+Today (#10, #12) 커넥션 56건 내역**:
- Hourly/5min 21건: 오늘 00:00~현재 구간 (Hourly 약 12건 + 5min 약 7건 + 폴백)
- Viewport Pass1 21건: 동일 범위에 대한 뷰포트 교차 선박 수집 (범위당 1회)
- TableCheck 14건: Daily 3건 + Hourly/5min 존재 확인 약 11건
### 2.3 캐시 경로 간소화 지표
캐시 경로에서는 원본 데이터를 메모리에 보유하므로 간소화 전/후를 측정할 수 있다.
| # | 경로 | Zoom | 원본 포인트 | 간소화 후 | 압축률 | 간소화 시간(ms) | 배치 감소 |
|---|------|------|------------|----------|--------|----------------|-----------|
| 1 | CACHE | 10 | 1,083,566 | 11,212 | 99% | 133 | 50→3 (94%) |
| 4 | CACHE | 10 | 13,502,970 | 172,066 | 99% | 1,075 | 602→10 (98%) |
| 5 | CACHE | 10 | 13,502,970 | 172,066 | 99% | 981 | 602→10 (98%) |
| 6 | HYBRID | 8 | 7,582,515 | 152,734 | 98% | 500 | 335→12 (96%) |
| 7 | HYBRID | 9 | 1,049,434 | 11,634 | 99% | 74 | 50→5 (90%) |
| 8 | HYBRID | 8 | 1,618,310 | 61,434 | 96% | 125 | 72→5 (93%) |
| 9 | HYBRID | 8 | 3,202,500 | 155,633 | 95% | 277 | 137→12 (91%) |
| 10 | CACHE+Today | 10 | 355,256 | 4,159 | 99% | 24 | 17→6 (65%) |
| 11 | HYBRID | 8 | 41,634,918 | 732,470 | 98% | 2,411 | 1,813→42 (98%) |
| 12 | CACHE+Today | 12 | 14,404,225 | 259,541 | 98% | 1,258 | 639→23 (96%) |
> DB 경로(#2, #3)는 SQL 레벨에서 `ST_Simplify` 적용 후 수신하므로 앱 레벨 압축률 산출 불가 (before = after).
---
## 3. 경로별 정량 비교
### 3.1 CACHE vs DB — 동일 규모 직접 비교
#### 대규모: #4 CACHE vs #3 DB
| 지표 | DB (#3) | CACHE (#4) | 개선 |
|------|---------|------------|------|
| 선박 수 | 12,253 | 10,690 | (유사 규모) |
| **응답시간** | 8,195 ms | 1,439 ms | **5.7배 빨라짐** |
| **DB 커넥션** | 19 | 2 | **89% 감소** |
| DB 쿼리 시간 | 1,443 ms | 0 ms | **100% 절감** |
| 배치 전송 수 | 11 | 10 | 유사 |
#### 소규모: #2 DB vs #1 CACHE
| 지표 | DB (#2) | CACHE (#1) | 개선 |
|------|---------|------------|------|
| 선박 수 | 352 | 443 | (유사 규모) |
| **응답시간** | 7,221 ms | 575 ms | **12.6배 빨라짐** |
| **DB 커넥션** | 8 | 3 | **63% 감소** |
| DB 쿼리 시간 | 3,475 ms | 0 ms | **100% 절감** |
| 배치 전송 수 | 2 | 3 | 유사 |
### 3.2 HYBRID 경로 — 규모별 성능 변화
5일 범위 쿼리 (캐시 3일 + DB 2일):
| # | 선박 수 | 응답시간 | DB커넥션 | DB쿼리시간 |
|---|---------|---------|----------|-----------|
| 7 | 547 | 1,373 ms | 11 | 550 ms |
| 8 | 4,589 | 2,910 ms | 12 | 715 ms |
| 9 | 5,760 | 3,651 ms | 15 | 1,048 ms |
| 6 | 9,958 | 8,900 ms | 16 | 3,301 ms |
| 11 | 52,151 | 105,212 ms | 45 | 93,319 ms |
- 소규모(~500척): 캐시 일자가 대부분의 처리를 흡수하여 **1.4초** 수준으로 응답.
- 중규모(5K~10K척): DB 쿼리 부담 증가하나 캐시 일자가 완충하여 **3~9초** 수준.
- 대규모(52K척): 캐시 미스 일자의 데이터량이 크면 DB 의존도가 높아져 **100초+** 수준.
- 캐시 적용 일수가 많을수록(현재 3/5일 = 60%) HYBRID 경로의 DB 부담이 경감된다.
### 3.3 CACHE+Today 경로 — 오늘 데이터 포함 쿼리
| # | Zoom | 선박 수 | 응답시간 | DB커넥션 | 오늘 구간 커넥션 |
|---|------|---------|---------|----------|----------------|
| 10 | 10 | 105 | 6,091 ms | 56 | 42 (H5m 21 + VP 21) |
| 12 | 12 | 6,990 | 9,744 ms | 56 | 42 (H5m 21 + VP 21) |
**핵심 발견**:
- 두 쿼리 모두 동일한 시간 범위(3일+오늘)이므로 커넥션 구조가 동일하며, 뷰포트 크기만 다름.
- 오늘 구간(00:00~현재)만으로 **42건의 DB 커넥션**이 발생하여, 순수 CACHE 경로(2~3건)와 큰 차이를 보인다.
- 선박 수가 적은 #10(105척)도 6초가 소요되며, 이는 오늘 구간의 범위별 개별 커넥션 오버헤드가 원인이다.
### 3.4 줌 레벨별 간소화 효과
| Zoom | 대표 # | 원본 포인트 | 간소화 후 | 압축률 | 선박당 평균 포인트 |
|------|--------|------------|----------|--------|------------------|
| 8 | #6 | 7,582,515 | 152,734 | 98% | 15.3 |
| 9 | #7 | 1,049,434 | 11,634 | 99% | 21.3 |
| 10 | #4 | 13,502,970 | 172,066 | 99% | 16.1 |
| 12 | #12 | 14,404,225 | 259,541 | 98% | 37.1 |
- 줌 8~10: 선박당 15~21 포인트로 압축 — 해역 수준 조회에 최적.
- 줌 12: 선박당 37 포인트 — 항만 수준 상세 조회에서 더 많은 포인트를 유지.
- 전 줌 레벨에서 95~99% 압축률 달성.
---
## 4. DB 커넥션 구성 분석
### 4.1 경로별 커넥션 구성 패턴
```
CACHE (순수) [==TC==] 2~3건
TableCheck만 발생
DB (순수) [VP][DA][..기타..][TC] 8~19건
각 항목 균등 분포
HYBRID [VP][DA][..기타..........][TC---] 11~45건
규모에 비례 증가
CACHE+Today [VP----------][H5m---------][TC------] 56건
오늘 구간의 Hourly/5min + Viewport가 대부분
```
### 4.2 커넥션 풀 영향 분석
Query DataSource 커넥션 풀 180 기준:
| 경로 | 쿼리당 사용 | 동시 10쿼리 시 누적 | 풀 압박 수준 |
|------|------------|-------------------|------------|
| CACHE | 2~3 | 30 | 매우 낮음 (17%) |
| HYBRID (소규모) | 11~15 | 150 | 보통 (83%) |
| DB | 8~19 | 190 | 보통~높음 |
| CACHE+Today | 56 | 560 | 높음 |
> 커넥션은 순간 점유가 아닌 순차 사용이므로 실제 동시 점유 수는 위 수치보다 작다. 캐시 적용으로 전체 쿼리 중 CACHE 경로 비율이 높아지면 풀 전체 부담이 크게 감소한다.
---
## 5. 종합 성능 비교
### 5.1 핵심 개선 지표
| 지표 | DB 경로 | CACHE 경로 | 개선율 |
|------|---------|------------|--------|
| 응답시간 (대규모, 만 척 이상) | 8,195 ms | 1,439 ms | **5.7배** |
| 응답시간 (소규모, 수백 척) | 7,221 ms | 575 ms | **12.6배** |
| DB 커넥션 수 (대규모) | 19건 | 2건 | **89% 감소** |
| DB 커넥션 수 (소규모) | 8건 | 3건 | **63% 감소** |
| DB 쿼리 시간 | 1,443~3,475 ms | 0 ms | **100% 절감** |
| 포인트 간소화 | SQL ST_Simplify | 앱 레벨 95~99% | 캐시만 측정 가능 |
### 5.2 경로별 응답시간 분포
```
응답시간 (ms, 로그 스케일 아님)
경로 0 2,000 4,000 6,000 8,000 10,000
CACHE (순수) |█| 575~1,439
HYBRID (소규모) |██| 1,373
HYBRID (중규모) |█████| 2,910~3,651
CACHE+Today |████████████| 6,091~9,744
DB (순수) |████████████████| 7,221~8,195
HYBRID (대규모) |██████████████████| 8,900
```
> HYBRID 대규모(#11, 52K척, 105초)는 스케일 초과로 표시 생략.
### 5.3 캐시 적용에 따른 운영 시나리오별 예측
D-1 ~ D-7 캐시가 적용된 상태에서:
| 사용 패턴 | 예상 경로 | 예상 응답시간 | DB 커넥션 |
|----------|----------|-------------|----------|
| 과거 1~7일만 조회 | CACHE | **0.5~1.5초** | 2~3건 |
| 과거 수일 + 오늘 | CACHE+Today | 6~10초 | ~56건 |
| 7일 이전 과거 포함 | HYBRID / DB | 1~9초 (규모 의존) | 8~45건 |
---
## 6. 캐시 범위 확장 시 권장 구성
현재 D-1 ~ D-7 캐시 구성에서 조회 기간 범위를 확장하고자 할 경우, 아래 구성을 권장한다.
### 6.1 현재 구성
```yaml
cache:
daily-track:
enabled: true
retention-days: 7 # D-1 ~ D-7 캐시
max-memory-gb: 6 # 최대 메모리 사용량
warmup-async: true # 비동기 워밍업
```
- 7일 이내 과거 조회: CACHE 경로 (0.5~1.5초)
- 7일 초과 과거 포함: HYBRID/DB 경로로 폴백
### 6.2 확장 권장안
| 시나리오 | retention-days | max-memory-gb | 예상 효과 |
|----------|---------------|---------------|----------|
| **현재** | 7 | 6 | 1주일 이내 CACHE, 이후 DB |
| **2주 확장** | 14 | 12 | 2주 리플레이까지 CACHE 커버 |
| **1개월 확장** | 30 | 25 | 월간 분석 조회까지 CACHE 커버 |
**확장 시 고려사항**:
1. **메모리 산정**: 현재 7일 캐시 ≈ 4GB 기준, 선형 증가 추정.
- 14일: ~12GB, 30일: ~25GB
- 서버 가용 메모리와 JVM 힙 설정(`-Xmx`) 여유 확인 필요.
2. **워밍업 시간**: retention-days 증가에 비례하여 초기 로드 시간 증가.
- 7일: 약 1~2분, 14일: 약 2~4분, 30일: 약 5~10분 (비동기이므로 서비스 가용성 영향 없음)
3. **HYBRID 비율 감소**: retention-days 확장 시 DB 폴백 빈도가 줄어, HYBRID 경로가 줄고 순수 CACHE 경로 비율이 증가한다. 이는 DB 커넥션 풀 부담 경감에 직접 기여한다.
4. **CACHE+Today 경로는 retention-days와 무관**: 오늘(D-0) 데이터는 항상 Hourly/5min 테이블에서 DB 조회한다. 이 구간의 커넥션 최적화는 별도 과제이다.
### 6.3 단계적 확장 전략
```
Phase 1 (현재) : retention-days=7, max-memory-gb=6 → 1주 커버
Phase 2 (권장) : retention-days=14, max-memory-gb=12 → 2주 커버, 주간 비교 분석 지원
Phase 3 (선택) : retention-days=30, max-memory-gb=25 → 월간 커버, 장기 항적 분석 지원
```
각 단계 전환 시 서버 메모리 여유와 워밍업 시간을 모니터링하며, JVM 힙 설정을 함께 조정한다.
---
## 7. 결론
### 7.1 캐시 효과 확인
1. **응답시간**: 순수 CACHE 경로에서 DB 대비 **5.7~12.6배** 빨라짐 확인.
2. **DB 커넥션**: 순수 CACHE 경로에서 DB 대비 **63~89%** 감소 확인.
3. **간소화**: 캐시 경로에서 줌 레벨에 따라 **95~99%** 포인트 압축, 배치 전송 수 **90~98%** 감소.
4. **DB 쿼리 시간**: CACHE 경로에서 **0ms** — DB 부하 완전 제거.
### 7.2 운영 권장사항
| 항목 | 현황 | 권장 방향 |
|------|------|----------|
| 캐시 보존 기간 | 7일 | 사용 패턴에 따라 14~30일로 확장 검토 |
| CACHE+Today 커넥션 | 오늘 구간 범위별 개별 DB 커넥션 (56건) | 오늘 데이터 범위 병합 또는 별도 캐시 검토 |