- t_chnprmship_positions 월별 파티션 테이블 (PartitionManager 관리)
- ChnPrmShipPositionSyncStep: 5분 Job 편승 캐시→DB 이중 적재
- ChnPrmShip 캐시 TTL 2→7일, 워밍업 소스 전용 DB + t_ais_position 이중화
- tracks/vessels API: includeChnPrmShip=true 시 ChnPrmShipInfo enrichment
- ShipImageControllerV2: /api/v2/shipimg/{imo} 추가
- SwaggerConfig: V2 경로 분리 + shipimg V2 그룹 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
316 lines
10 KiB
YAML
316 lines
10 KiB
YAML
server:
|
|
shutdown: graceful
|
|
servlet:
|
|
context-path: /signal-batch
|
|
|
|
spring:
|
|
application:
|
|
name: vessel-batch-aggregation
|
|
|
|
lifecycle:
|
|
timeout-per-shutdown-phase: 3m # graceful shutdown 대기 (진행 중 Job 완료)
|
|
|
|
main:
|
|
allow-bean-definition-overriding: true # Bean 중복 정의 허용
|
|
|
|
profiles:
|
|
# active 프로파일은 실행 시 명시적으로 지정 권장
|
|
# 빌드 시: -DSPRING_PROFILES_ACTIVE=prod or -DSPRING_PROFILES_ACTIVE=query
|
|
# 실행 시: --spring.profiles.active=prod or --spring.profiles.active=query
|
|
# 환경변수: export SPRING_PROFILES_ACTIVE=prod
|
|
active: ${SPRING_PROFILES_ACTIVE:prod} # 기본값: prod (환경변수 없을 경우)
|
|
|
|
# Jackson 설정
|
|
jackson:
|
|
serialization:
|
|
write-dates-as-timestamps: false
|
|
deserialization:
|
|
fail-on-unknown-properties: false
|
|
time-zone: Asia/Seoul
|
|
date-format: yyyy-MM-dd'T'HH:mm:ss
|
|
|
|
batch:
|
|
job:
|
|
enabled: false # 자동 실행 방지
|
|
jdbc:
|
|
initialize-schema: always
|
|
table-prefix: BATCH_ # 배치 테이블 prefix
|
|
|
|
# 공통 데이터소스 설정
|
|
datasource:
|
|
# 수집 DB
|
|
collect:
|
|
jdbc-url: ${COLLECT_DB_URL:jdbc:postgresql://localhost:5432/wingdb?stringtype=unspecified¤tSchema=signal&TimeZone=Asia/Seoul}
|
|
username: ${COLLECT_DB_USER:collect_user}
|
|
password: ${COLLECT_DB_PASS:collect_pass}
|
|
driver-class-name: org.postgresql.Driver
|
|
pool-name: CollectHikariPool
|
|
connection-timeout: 30000
|
|
idle-timeout: 600000
|
|
max-lifetime: 1800000
|
|
maximum-pool-size: 20
|
|
minimum-idle: 5
|
|
|
|
# 조회 DB
|
|
query:
|
|
jdbc-url: ${QUERY_DB_URL:jdbc:postgresql://localhost:5432/wingdb?stringtype=unspecified¤tSchema=signal&TimeZone=Asia/Seoul}
|
|
username: ${QUERY_DB_USER:query_user}
|
|
password: ${QUERY_DB_PASS:query_pass}
|
|
driver-class-name: org.postgresql.Driver
|
|
pool-name: QueryHikariPool
|
|
connection-timeout: 30000
|
|
idle-timeout: 600000
|
|
max-lifetime: 1800000
|
|
maximum-pool-size: 30
|
|
minimum-idle: 10
|
|
|
|
# 배치 메타데이터 DB
|
|
batch:
|
|
jdbc-url: ${BATCH_DB_URL:jdbc:postgresql://localhost:5432/wingdb?stringtype=unspecified¤tSchema=signal&TimeZone=Asia/Seoul}
|
|
username: ${BATCH_DB_USER:batch_user}
|
|
password: ${BATCH_DB_PASS:batch_pass}
|
|
driver-class-name: org.postgresql.Driver
|
|
pool-name: BatchHikariPool
|
|
maximum-pool-size: 10
|
|
minimum-idle: 2
|
|
|
|
# 로깅 설정
|
|
logging:
|
|
level:
|
|
root: INFO
|
|
gc.mda.signal_batch: INFO
|
|
gc.mda.signal_batch.util: WARN
|
|
com.vessel.batch: INFO
|
|
org.springframework.batch: INFO
|
|
org.springframework.jdbc: WARN
|
|
org.postgresql: WARN
|
|
pattern:
|
|
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
|
|
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
|
|
file:
|
|
name: ${LOG_PATH:logs}/vessel-batch.log
|
|
logback:
|
|
rollingpolicy:
|
|
max-file-size: 100MB
|
|
max-history: 30
|
|
|
|
# 액추에이터 설정
|
|
management:
|
|
endpoints:
|
|
web:
|
|
exposure:
|
|
include: health,info,metrics,prometheus,env,loggers,threaddump,heapdump
|
|
base-path: /actuator
|
|
endpoint:
|
|
health:
|
|
show-details: always
|
|
show-components: always
|
|
probes:
|
|
enabled: true
|
|
metrics:
|
|
enabled: true
|
|
metrics:
|
|
export:
|
|
prometheus:
|
|
enabled: true
|
|
step: 30s
|
|
tags:
|
|
application: ${spring.application.name}
|
|
environment: ${spring.profiles.active}
|
|
distribution:
|
|
percentiles-histogram:
|
|
batch.job.duration: true
|
|
batch.step.duration: true
|
|
batch.chunk.duration: true
|
|
batch.database.operation: true
|
|
percentiles:
|
|
batch.job.duration: 0.5, 0.75, 0.95, 0.99
|
|
batch.step.duration: 0.5, 0.75, 0.95, 0.99
|
|
prometheus:
|
|
metrics:
|
|
export:
|
|
enabled: true
|
|
|
|
# 커스텀 설정
|
|
vessel:
|
|
# 데이터 필터 설정
|
|
filter:
|
|
zero-coordinates:
|
|
enabled: ${FILTER_ZERO_COORDS:false} # 0 근처 좌표 필터링 (기본: 비활성화)
|
|
# true일 경우 lat/lon이 -1 ~ 1 범위인 데이터를 제외
|
|
|
|
# 통합선박 설정
|
|
integration:
|
|
enabled: ${INTEGRATION_ENABLED:false} # 통합선박 기능 활성화 여부
|
|
cache:
|
|
refresh-cron: "0 0 6 * * ?" # 매일 06:00 갱신
|
|
datasource:
|
|
jdbc-url: "" # 빈 값: queryDataSource 폴백, 별도 DB 사용 시 프로파일에서 오버라이드
|
|
username: ""
|
|
password: ""
|
|
table-name: signal.t_ship_integration_sub # 기본: queryDB의 signal 스키마
|
|
|
|
batch:
|
|
chunk-size: ${BATCH_CHUNK_SIZE:10000}
|
|
page-size: ${BATCH_PAGE_SIZE:10000}
|
|
partition-size: ${BATCH_PARTITION_SIZE:24}
|
|
skip-limit: 100
|
|
retry-limit: 3
|
|
# Reader 설정
|
|
use-cursor-reader: true # Cursor Reader 사용 여부
|
|
fetch-size: 50000 # 한번에 가져올 row 수
|
|
|
|
|
|
# 타임아웃 설정
|
|
query-timeout: 1800 # 30분
|
|
|
|
# 파티션 관리 설정 (queryDB만 관리)
|
|
partition:
|
|
# 전역 설정
|
|
future-days: 7 # 미래 파티션 생성 기간 (일)
|
|
enable-auto-management: true # 파티션 자동 생성
|
|
enable-auto-cleanup: true # 파티션 자동 정리
|
|
|
|
# 기본 보관 기간
|
|
default-retention:
|
|
daily-partitions-retention-days: 7 # 일별 파티션 기본 보관 (일)
|
|
monthly-partitions-retention-months: 2 # 월별 파티션 기본 보관 (월)
|
|
|
|
# 테이블별 보관 기간 (기본값과 다를 경우만 설정)
|
|
tables:
|
|
t_vessel_tracks_5min:
|
|
retention-days: 7 # 7일 보관
|
|
t_area_vessel_tracks:
|
|
retention-days: 30 # 30일 보관
|
|
t_area_tracks_summary:
|
|
retention-days: 30 # 30일 보관
|
|
t_area_statistics:
|
|
retention-days: 30 # 30일 보관
|
|
t_grid_vessel_tracks:
|
|
retention-days: 14 # 14일 보관
|
|
t_grid_tracks_summary:
|
|
retention-days: 14 # 14일 보관
|
|
t_tile_summary:
|
|
retention-days: 7 # 7일 보관
|
|
|
|
# 월별 파티션 테이블 (단위: 월)
|
|
t_vessel_tracks_hourly:
|
|
retention-months: 2 # 2개월 보관
|
|
t_vessel_tracks_daily:
|
|
retention-months: 60 # 60개월 보관
|
|
t_grid_tracks_summary_hourly:
|
|
retention-months: 2 # 2개월 보관
|
|
t_grid_tracks_summary_daily:
|
|
retention-months: 3 # 3개월 보관
|
|
t_area_tracks_summary_hourly:
|
|
retention-months: 2 # 2개월 보관
|
|
t_area_tracks_summary_daily:
|
|
retention-months: 3 # 3개월 보관
|
|
t_abnormal_tracks:
|
|
retention-months: 0 # 무한 보관
|
|
t_chnprmship_positions:
|
|
retention-months: 3 # 3개월 보관
|
|
|
|
# Bulk Insert 설정
|
|
bulk-insert:
|
|
batch-size: 10000 # 한번에 처리할 레코드 수 (5분 배치에 최적화)
|
|
parallel-threads: 4 # 병렬 처리 스레드 수
|
|
use-binary-copy: false # 바이너리 COPY 사용 여부
|
|
|
|
# 데이터베이스 연결 설정
|
|
datasource:
|
|
query:
|
|
hikari:
|
|
# Bulk Insert에 맞춘 설정
|
|
connection-init-sql: |
|
|
SET work_mem = '512MB';
|
|
SET maintenance_work_mem = '1GB';
|
|
SET synchronous_commit = 'off';
|
|
SET checkpoint_completion_target = 0.9;
|
|
# 락 설정
|
|
lock:
|
|
timeout: 10 # Advisory Lock 타임아웃 (초)
|
|
max-retry: 3 # 최대 재시도 횟수
|
|
|
|
# Writer 설정
|
|
writer:
|
|
use-advisory-lock: false # Advisory Lock 사용 여부 (개별 처리 → 배치 처리)
|
|
parallel-threads: 4 # 병렬 처리 스레드 수
|
|
|
|
# 재시도 설정
|
|
retry:
|
|
max-attempts: 3
|
|
initial-interval: 100
|
|
max-interval: 5000
|
|
multiplier: 2
|
|
|
|
# 커스텀 Health Indicator 설정
|
|
health:
|
|
job-timeout-hours: 6 # Job 타임아웃 시간
|
|
min-partition-count: 5 # 최소 파티션 수
|
|
|
|
grid:
|
|
mode: haegu
|
|
haegu:
|
|
cache-enabled: true
|
|
cache-size: 2000
|
|
|
|
# 선박 최신 위치 캐시 설정
|
|
cache:
|
|
latest-position:
|
|
enabled: false # 기본값: 비활성화 (프로파일별로 활성화)
|
|
ttl-minutes: 60 # 캐시 TTL: 60분
|
|
max-size: 50000 # 최대 선박 수: 50,000척
|
|
refresh-interval-minutes: 2 # 갱신 주기 데이터 범위: 2분치 조회 (수집 지연 고려)
|
|
|
|
# 이전 버킷 위치 캐시 설정 (버킷 간 점프 검출용)
|
|
previous-bucket:
|
|
ttl-minutes: 120 # 캐시 TTL: 120분 (위성 AIS 30~60분 간격 고려)
|
|
max-size: 100000 # 최대 선박 수: 100,000척 (2시간 누적 고려)
|
|
|
|
# ==================== S&P Global AIS API 설정 ====================
|
|
app:
|
|
ais-api:
|
|
url: ${AIS_API_URL:https://aisapi.maritime.spglobal.com}
|
|
username: ${AIS_API_USERNAME:}
|
|
password: ${AIS_API_PASSWORD:}
|
|
since-seconds: 60 # API 조회 범위 (초)
|
|
chunk-size: 50000 # 배치 청크 크기 (API 1회 호출 ~33K건)
|
|
|
|
cache:
|
|
ais-target:
|
|
ttl-minutes: 120 # 기본 TTL (프로파일별 오버라이드)
|
|
max-size: 300000 # 최대 캐시 크기 (30만 건)
|
|
|
|
five-min-track:
|
|
ttl-minutes: 75 # TTL 75분 (1시간 + 15분 여유)
|
|
max-size: 1500000 # 700K→1.5M (실측 612K, 2.5배 여유)
|
|
|
|
hourly-track:
|
|
ttl-hours: 26 # TTL 26시간 (24시간 + 2시간 여유)
|
|
max-size: 3500000 # 1.4M→3.5M (실측 1.27M, 2.8배 여유)
|
|
|
|
chnprmship:
|
|
mmsi-resource-path: classpath:chnprmship-mmsi.txt
|
|
ttl-days: 7
|
|
max-size: 2000
|
|
warmup-enabled: true
|
|
warmup-days: 7
|
|
|
|
# Swagger/OpenAPI 설정
|
|
springdoc:
|
|
api-docs:
|
|
enabled: true
|
|
path: /v3/api-docs
|
|
swagger-ui:
|
|
enabled: true
|
|
path: /swagger-ui.html
|
|
display-request-duration: true
|
|
disable-swagger-default-url: true
|
|
doc-expansion: none
|
|
operations-sorter: alpha
|
|
tags-sorter: alpha
|
|
show-actuator: true
|
|
default-produces-media-type: application/json
|
|
default-consumes-media-type: application/json
|