Merge pull request 'ci: Gitea Actions CI/CD 파이프라인 + systemd 서비스 구성' (#8) from feature/multilevel-track-cache into develop
This commit is contained in:
커밋
fb1a9f21f2
82
.gitea/workflows/deploy.yml
Normal file
82
.gitea/workflows/deploy.yml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
name: Build & Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install JDK 17 + Maven
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y -qq openjdk-17-jdk-headless maven openssh-client > /dev/null 2>&1
|
||||||
|
java -version
|
||||||
|
mvn --version
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: |
|
||||||
|
mvn -B clean package -DskipTests \
|
||||||
|
-Dmaven.compiler.release=17
|
||||||
|
ls -lh target/vessel-batch-aggregation.jar
|
||||||
|
|
||||||
|
- name: Deploy to production server
|
||||||
|
env:
|
||||||
|
DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||||
|
run: |
|
||||||
|
# SSH 키 설정
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "$DEPLOY_KEY" > ~/.ssh/id_deploy
|
||||||
|
chmod 600 ~/.ssh/id_deploy
|
||||||
|
ssh-keyscan -p 32023 192.168.1.18 >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||||
|
|
||||||
|
SSH_CMD="ssh -p 32023 -i ~/.ssh/id_deploy -o StrictHostKeyChecking=no root@192.168.1.18"
|
||||||
|
SCP_CMD="scp -P 32023 -i ~/.ssh/id_deploy -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
# JAR 전송
|
||||||
|
echo "=== Uploading JAR ==="
|
||||||
|
$SCP_CMD target/vessel-batch-aggregation.jar root@192.168.1.18:/home/apps/signal-batch/vessel-batch-aggregation.jar.new
|
||||||
|
|
||||||
|
# 원자적 교체 + 서비스 재시작
|
||||||
|
echo "=== Deploying ==="
|
||||||
|
$SSH_CMD bash -s << 'DEPLOY'
|
||||||
|
set -e
|
||||||
|
APP_DIR=/home/apps/signal-batch
|
||||||
|
|
||||||
|
# 기존 JAR 백업
|
||||||
|
if [ -f $APP_DIR/vessel-batch-aggregation.jar ]; then
|
||||||
|
cp $APP_DIR/vessel-batch-aggregation.jar $APP_DIR/backup/vessel-batch-aggregation.jar.$(date +%Y%m%d-%H%M%S)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 원자적 교체
|
||||||
|
mv $APP_DIR/vessel-batch-aggregation.jar.new $APP_DIR/vessel-batch-aggregation.jar
|
||||||
|
|
||||||
|
# 백업 정리 (최근 5개만 유지)
|
||||||
|
ls -t $APP_DIR/backup/vessel-batch-aggregation.jar.* 2>/dev/null | tail -n +6 | xargs rm -f 2>/dev/null || true
|
||||||
|
|
||||||
|
# 서비스 재시작
|
||||||
|
systemctl restart signal-batch
|
||||||
|
echo "Service restarted, waiting for startup..."
|
||||||
|
|
||||||
|
# 시작 확인 (최대 90초 — 48GB 힙 AlwaysPreTouch)
|
||||||
|
for i in $(seq 1 90); do
|
||||||
|
if curl -sf http://localhost:18090/actuator/health > /dev/null 2>&1; then
|
||||||
|
echo "Service started successfully (${i}s)"
|
||||||
|
curl -s http://localhost:18090/actuator/health
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "WARNING: Startup timeout. Recent logs:"
|
||||||
|
journalctl -u signal-batch --no-pager -n 50
|
||||||
|
exit 1
|
||||||
|
DEPLOY
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: rm -f ~/.ssh/id_deploy
|
||||||
66
deploy/signal-batch.service
Normal file
66
deploy/signal-batch.service
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Signal Batch Aggregation Service
|
||||||
|
After=network.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/home/apps/signal-batch
|
||||||
|
|
||||||
|
# JDK 경로 (프로세스별 독립 JDK)
|
||||||
|
Environment=JAVA_HOME=/home/apps/jdk/jdk-17.0.14+7
|
||||||
|
|
||||||
|
# Spring Profile
|
||||||
|
Environment=SPRING_PROFILES_ACTIVE=prod
|
||||||
|
|
||||||
|
# JVM 옵션 — 64코어 Xeon Gold 6430, 250GB RAM
|
||||||
|
# Heap: 64GB (RAM의 ~26%, 인메모리 캐시 대량 활용)
|
||||||
|
Environment=JAVA_OPTS="\
|
||||||
|
-Xms64g -Xmx64g \
|
||||||
|
-XX:+UseG1GC \
|
||||||
|
-XX:G1HeapRegionSize=32m \
|
||||||
|
-XX:MaxGCPauseMillis=200 \
|
||||||
|
-XX:InitiatingHeapOccupancyPercent=35 \
|
||||||
|
-XX:G1ReservePercent=15 \
|
||||||
|
-XX:G1MixedGCCountTarget=8 \
|
||||||
|
-XX:ParallelGCThreads=24 \
|
||||||
|
-XX:ConcGCThreads=8 \
|
||||||
|
-XX:+UseStringDeduplication \
|
||||||
|
-XX:+ParallelRefProcEnabled \
|
||||||
|
-XX:+AlwaysPreTouch \
|
||||||
|
-XX:MaxMetaspaceSize=512m \
|
||||||
|
-XX:+HeapDumpOnOutOfMemoryError \
|
||||||
|
-XX:HeapDumpPath=/home/apps/signal-batch/logs/heapdump.hprof \
|
||||||
|
-XX:+ExitOnOutOfMemoryError \
|
||||||
|
-Xlog:gc*,gc+ref=debug,gc+heap=debug,gc+age=trace:file=/home/apps/signal-batch/logs/gc.log:time,uptime,level,tags:filecount=5,filesize=100m \
|
||||||
|
-Dfile.encoding=UTF-8 \
|
||||||
|
-Duser.timezone=Asia/Seoul \
|
||||||
|
-Djava.security.egd=file:/dev/./urandom"
|
||||||
|
|
||||||
|
ExecStart=/home/apps/jdk/jdk-17.0.14+7/bin/java \
|
||||||
|
${JAVA_OPTS} \
|
||||||
|
-jar /home/apps/signal-batch/vessel-batch-aggregation.jar \
|
||||||
|
--spring.profiles.active=${SPRING_PROFILES_ACTIVE}
|
||||||
|
|
||||||
|
# Graceful shutdown (SIGTERM → Spring Boot shutdown hook)
|
||||||
|
ExecStop=/bin/kill -TERM $MAINPID
|
||||||
|
TimeoutStopSec=60
|
||||||
|
KillMode=mixed
|
||||||
|
KillSignal=SIGTERM
|
||||||
|
|
||||||
|
# 자동 재시작 (OOM 등 비정상 종료 시)
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=15
|
||||||
|
|
||||||
|
# 로그 → journald + 파일 (Spring Boot logback)
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
SyslogIdentifier=signal-batch
|
||||||
|
|
||||||
|
# 리소스 제한
|
||||||
|
LimitNOFILE=65536
|
||||||
|
LimitNPROC=4096
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@ -1,265 +0,0 @@
|
|||||||
server:
|
|
||||||
port: 8090
|
|
||||||
tomcat:
|
|
||||||
threads:
|
|
||||||
max: 200
|
|
||||||
min-spare: 10
|
|
||||||
connection-timeout: 60000 # 60초로 증가
|
|
||||||
max-http-form-post-size: 50MB # 50MB로 증가
|
|
||||||
max-swallow-size: 50MB # 50MB로 증가
|
|
||||||
max-connections: 10000 # 최대 연결 수
|
|
||||||
accept-count: 100 # 대기열 크기
|
|
||||||
|
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
# 원격 수집 DB
|
|
||||||
collect:
|
|
||||||
jdbc-url: jdbc:postgresql://10.188.171.182:5432/mdadb?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mda
|
|
||||||
password: mda#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: CollectHikariPool
|
|
||||||
connection-timeout: 30000 # 원격 연결이므로 타임아웃 증가
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
maximum-pool-size: 20 # 10 -> 20 증가
|
|
||||||
minimum-idle: 5 # 2 -> 5 증가
|
|
||||||
# 원격 연결 안정성을 위한 추가 설정
|
|
||||||
connection-test-query: SELECT 1
|
|
||||||
validation-timeout: 5000
|
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
|
||||||
|
|
||||||
# 원격 조회 DB (수집 DB와 동일하게 설정)
|
|
||||||
query:
|
|
||||||
jdbc-url: jdbc:postgresql://10.188.141.124:5432/mdadb?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mda
|
|
||||||
password: mda#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: QueryHikariPool
|
|
||||||
connection-timeout: 5000
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
maximum-pool-size: 60 # 20 -> 40 증가
|
|
||||||
minimum-idle: 10 # 5 -> 10 증가
|
|
||||||
connection-test-query: SELECT 1
|
|
||||||
validation-timeout: 5000
|
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
|
||||||
statement-cache-size: 250
|
|
||||||
data-source-properties:
|
|
||||||
prepareThreshold: 3
|
|
||||||
preparedStatementCacheQueries: 250
|
|
||||||
|
|
||||||
# 로컬 배치 메타 DB
|
|
||||||
batch:
|
|
||||||
jdbc-url: jdbc:postgresql://10.188.141.124:5432/mdadb?currentSchema=public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mda
|
|
||||||
password: mda#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: BatchHikariPool
|
|
||||||
maximum-pool-size: 20 # 10 → 30 증가
|
|
||||||
minimum-idle: 10 # 2 → 10 증가
|
|
||||||
connection-timeout: 30000 # 30초 타임아웃
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO public, signal;"
|
|
||||||
|
|
||||||
# Request 크기 설정
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
max-file-size: 50MB
|
|
||||||
max-request-size: 50MB
|
|
||||||
|
|
||||||
# Spring Batch 설정
|
|
||||||
batch:
|
|
||||||
job:
|
|
||||||
enabled: false
|
|
||||||
jdbc:
|
|
||||||
initialize-schema: never # always에서 never로 변경 (이미 수동으로 생성했으므로)
|
|
||||||
table-prefix: BATCH_
|
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
root: INFO
|
|
||||||
gc.mda.signal_batch: DEBUG
|
|
||||||
gc.mda.signal_batch.global.util: INFO
|
|
||||||
gc.mda.signal_batch.global.websocket.service: INFO
|
|
||||||
gc.mda.signal_batch.batch.writer: INFO
|
|
||||||
gc.mda.signal_batch.batch.reader: INFO
|
|
||||||
gc.mda.signal_batch.batch.processor: INFO
|
|
||||||
gc.mda.signal_batch.domain: INFO
|
|
||||||
gc.mda.signal_batch.monitoring: DEBUG
|
|
||||||
gc.mda.signal_batch.monitoring.controller: INFO
|
|
||||||
org.springframework.batch: INFO
|
|
||||||
org.springframework.jdbc: WARN
|
|
||||||
org.postgresql: WARN
|
|
||||||
com.zaxxer.hikari: INFO
|
|
||||||
|
|
||||||
# 개발 환경 배치 설정 (성능 최적화)
|
|
||||||
vessel: # spring 하위가 아닌 최상위 레벨
|
|
||||||
# 통합선박 설정
|
|
||||||
integration:
|
|
||||||
enabled: true # queryDB signal.t_ship_integration_sub 사용 (기본값)
|
|
||||||
batch:
|
|
||||||
# Area Statistics 처리를 위한 별도 설정
|
|
||||||
area-statistics:
|
|
||||||
chunk-size: 1000 # 5000 → 1000
|
|
||||||
batch-size: 500 # 새로 추가
|
|
||||||
|
|
||||||
chunk-size: 10000
|
|
||||||
page-size: 5000
|
|
||||||
partition-size: 12
|
|
||||||
|
|
||||||
# 성능 최적화 설정
|
|
||||||
optimization:
|
|
||||||
enabled: true
|
|
||||||
dynamic-chunk-sizing: true
|
|
||||||
memory-optimization: true
|
|
||||||
cache-optimization: true
|
|
||||||
thread-pool-optimization: true
|
|
||||||
# 동적 청크 크기 조정
|
|
||||||
chunk:
|
|
||||||
min-size: 1000
|
|
||||||
max-size: 20000
|
|
||||||
adjustment-factor: 0.2
|
|
||||||
# 메모리 임계값
|
|
||||||
memory:
|
|
||||||
warning-threshold: 70
|
|
||||||
critical-threshold: 85
|
|
||||||
optimization-threshold: 80
|
|
||||||
# 캐시 설정
|
|
||||||
cache:
|
|
||||||
min-hit-rate: 70
|
|
||||||
area-boundary-size: 5000
|
|
||||||
|
|
||||||
# Reader 최적화
|
|
||||||
fetch-size: 200000
|
|
||||||
use-cursor-reader: true
|
|
||||||
|
|
||||||
# Bulk Insert 최적화
|
|
||||||
bulk-insert:
|
|
||||||
batch-size: 10000
|
|
||||||
parallel-threads: 8
|
|
||||||
use-binary-copy: false
|
|
||||||
|
|
||||||
# Writer 설정
|
|
||||||
writer:
|
|
||||||
use-advisory-lock: false
|
|
||||||
parallel-threads: 4
|
|
||||||
|
|
||||||
# 재시도 설정
|
|
||||||
retry:
|
|
||||||
max-attempts: 3
|
|
||||||
initial-interval: 1000
|
|
||||||
max-interval: 10000
|
|
||||||
multiplier: 2
|
|
||||||
|
|
||||||
# 스케줄러 설정
|
|
||||||
scheduler:
|
|
||||||
enabled: true
|
|
||||||
incremental:
|
|
||||||
delay-minutes: 3 # 데이터 수집 지연 고려
|
|
||||||
|
|
||||||
# Batch 메타데이터 정리 설정
|
|
||||||
metadata:
|
|
||||||
cleanup:
|
|
||||||
enabled: true # 자동 정리 활성화
|
|
||||||
retention-days: 30 # 보존 기간 (30일)
|
|
||||||
dry-run: false # false: 실제 삭제, true: 테스트만
|
|
||||||
|
|
||||||
# 궤적 비정상 검출 설정
|
|
||||||
track:
|
|
||||||
abnormal-detection:
|
|
||||||
large-gap-threshold-hours: 6 # 이 시간 이상 gap은 연결 안함
|
|
||||||
extreme-speed-threshold: 1000 # 이 속도 이상은 무조건 비정상 (knots)
|
|
||||||
enable-merger-filtering: false # VesselTrackMerger 필터링 활성화 (기본: false)
|
|
||||||
|
|
||||||
# 타임아웃 설정
|
|
||||||
query-timeout: 1800 # 30분
|
|
||||||
lock:
|
|
||||||
timeout: 30
|
|
||||||
max-retry: 5
|
|
||||||
|
|
||||||
# Health Check 설정
|
|
||||||
health:
|
|
||||||
job-timeout-hours: 2
|
|
||||||
min-partition-count: 1
|
|
||||||
|
|
||||||
# 그리드 설정
|
|
||||||
grid:
|
|
||||||
mode: haegu
|
|
||||||
haegu:
|
|
||||||
cache-enabled: true
|
|
||||||
cache-size: 2000
|
|
||||||
|
|
||||||
cache:
|
|
||||||
latest-position:
|
|
||||||
enabled: true # 운영 환경: 활성화
|
|
||||||
ttl-minutes: 60 # 60분 TTL
|
|
||||||
max-size: 80000 # 최대 50,000척
|
|
||||||
refresh-interval-minutes: 2 # 2분치 데이터 조회 (수집 지연 고려)
|
|
||||||
|
|
||||||
# 비정상 궤적 검출 설정 (개선됨)
|
|
||||||
abnormal-detection:
|
|
||||||
enabled: true
|
|
||||||
5min-speed-threshold: 500 # 5분 집계 비정상 속도 임계값 (200 knots로 완화)
|
|
||||||
# 비정상 판정 기준 (명백한 비정상만 검출하도록 완화)
|
|
||||||
thresholds:
|
|
||||||
# 정박/저속 판단 기준
|
|
||||||
min-movement-nm: 0.05 # 최소 이동거리 (정박 판단)
|
|
||||||
stationary-speed-knots: 0.5 # 정박 속도 기준
|
|
||||||
|
|
||||||
# 선박 관련 임계값
|
|
||||||
vessel-physical-limit-knots: 100.0 # 선박 물리적 한계
|
|
||||||
vessel-abnormal-speed-knots: 200.0 # 선박 명백한 비정상 속도
|
|
||||||
|
|
||||||
# 항공기 관련 임계값
|
|
||||||
aircraft-physical-limit-knots: 600.0 # 항공기 물리적 한계
|
|
||||||
aircraft-abnormal-speed-knots: 800.0 # 항공기 명백한 비정상 속도
|
|
||||||
|
|
||||||
# 거리 관련 임계값
|
|
||||||
base-distance-5min-nm: 20.0 # 5분 기준 거리 (20nm로 완화)
|
|
||||||
extreme-distance-5min-nm: 100.0 # 5분간 극단적 이동거리
|
|
||||||
|
|
||||||
# Hourly/Daily 전용 임계값
|
|
||||||
hourly-daily-speed-limit: 500.0 # 시간/일 집계시 극단적 속도만 검출
|
|
||||||
|
|
||||||
# 기타 설정
|
|
||||||
distance-tolerance: 3.0 # 거리 허용 배수 (3.0으로 완화)
|
|
||||||
time-scaling-method: "sqrt" # 시간 스케일링 방법 (sqrt)
|
|
||||||
# 캐시 설정
|
|
||||||
cache:
|
|
||||||
previous-track-size: 10000 # 이전 궤적 캐시 크기
|
|
||||||
ttl-hours: 24 # 캐시 TTL
|
|
||||||
# 처리 옵션
|
|
||||||
processing:
|
|
||||||
remove-abnormal-segments: false # 비정상 구간 제거 여부
|
|
||||||
save-corrected-tracks: true # 보정된 궤적 저장 여부
|
|
||||||
exclude-stationary-vessels: true # 정박 선박 제외 여부
|
|
||||||
lenient-mode: true # 관대한 모드 활성화
|
|
||||||
|
|
||||||
# S&P AIS API 캐시 TTL (개발: 60분)
|
|
||||||
app:
|
|
||||||
cache:
|
|
||||||
ais-target:
|
|
||||||
ttl-minutes: 60
|
|
||||||
|
|
||||||
# 액추에이터 설정
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
exposure:
|
|
||||||
include: health,info,metrics,prometheus,env,loggers,threaddump,heapdump,scheduledtasks
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
show-details: always
|
|
||||||
show-components: always
|
|
||||||
metrics:
|
|
||||||
tags:
|
|
||||||
application: vessel-batch-aggregation
|
|
||||||
environment: dev
|
|
||||||
@ -1,319 +0,0 @@
|
|||||||
server:
|
|
||||||
port: 8090
|
|
||||||
tomcat:
|
|
||||||
threads:
|
|
||||||
max: 200
|
|
||||||
min-spare: 10
|
|
||||||
connection-timeout: 60000 # 60초로 증가
|
|
||||||
max-http-form-post-size: 50MB # 50MB로 증가
|
|
||||||
max-swallow-size: 50MB # 50MB로 증가
|
|
||||||
max-connections: 10000 # 최대 연결 수
|
|
||||||
accept-count: 100 # 대기열 크기
|
|
||||||
|
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
# 원격 수집 DB
|
|
||||||
collect:
|
|
||||||
jdbc-url: jdbc:postgresql://10.26.252.39:5432/mdadb?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mda
|
|
||||||
password: mda#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: CollectHikariPool
|
|
||||||
connection-timeout: 30000 # 원격 연결이므로 타임아웃 증가
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
maximum-pool-size: 30 # 10 -> 30 증가
|
|
||||||
minimum-idle: 10 # 2 -> 10 증가
|
|
||||||
# 원격 연결 안정성을 위한 추가 설정
|
|
||||||
connection-test-query: SELECT 1
|
|
||||||
validation-timeout: 5000
|
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
|
||||||
|
|
||||||
# 원격 조회 DB
|
|
||||||
query:
|
|
||||||
jdbc-url: jdbc:postgresql://10.29.17.90:5432/mpcdb2?currentSchema=signal&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mpc
|
|
||||||
password: mpc#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: QueryHikariPool
|
|
||||||
connection-timeout: 5000
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
maximum-pool-size: 90 # 20 -> 90 증가
|
|
||||||
minimum-idle: 15 # 5 -> 15 증가
|
|
||||||
connection-test-query: SELECT 1
|
|
||||||
validation-timeout: 5000
|
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
|
||||||
# PostGIS 함수를 위해 public 스키마를 search_path에 명시적으로 추가
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public, pg_catalog;"
|
|
||||||
statement-cache-size: 250
|
|
||||||
data-source-properties:
|
|
||||||
prepareThreshold: 3
|
|
||||||
preparedStatementCacheQueries: 250
|
|
||||||
|
|
||||||
# 로컬 배치 메타 DB
|
|
||||||
batch:
|
|
||||||
jdbc-url: jdbc:postgresql://10.26.252.51:5432/mdadb?currentSchema=public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mda
|
|
||||||
password: mda#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: BatchHikariPool
|
|
||||||
maximum-pool-size: 20 # 10 → 30 증가
|
|
||||||
minimum-idle: 10 # 2 → 10 증가
|
|
||||||
connection-timeout: 30000 # 30초 타임아웃
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO public, signal;"
|
|
||||||
|
|
||||||
# Request 크기 설정
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
max-file-size: 50MB
|
|
||||||
max-request-size: 50MB
|
|
||||||
|
|
||||||
# Spring Batch 설정
|
|
||||||
batch:
|
|
||||||
job:
|
|
||||||
enabled: false
|
|
||||||
jdbc:
|
|
||||||
initialize-schema: never # always에서 never로 변경 (이미 수동으로 생성했으므로)
|
|
||||||
table-prefix: BATCH_
|
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
root: INFO
|
|
||||||
gc.mda.signal_batch: DEBUG
|
|
||||||
gc.mda.signal_batch.global.util: INFO
|
|
||||||
gc.mda.signal_batch.global.websocket.service: INFO
|
|
||||||
gc.mda.signal_batch.batch.writer: INFO
|
|
||||||
gc.mda.signal_batch.batch.reader: INFO
|
|
||||||
gc.mda.signal_batch.batch.processor: INFO
|
|
||||||
gc.mda.signal_batch.domain: INFO
|
|
||||||
gc.mda.signal_batch.monitoring: DEBUG
|
|
||||||
gc.mda.signal_batch.monitoring.controller: INFO
|
|
||||||
org.springframework.batch: INFO
|
|
||||||
org.springframework.jdbc: WARN
|
|
||||||
org.postgresql: WARN
|
|
||||||
com.zaxxer.hikari: INFO
|
|
||||||
|
|
||||||
# 개발 환경 배치 설정 (성능 최적화)
|
|
||||||
vessel: # spring 하위가 아닌 최상위 레벨
|
|
||||||
# 통합선박 설정
|
|
||||||
integration:
|
|
||||||
enabled: true # 통합선박 기능 활성화 여부
|
|
||||||
batch:
|
|
||||||
# Area Statistics 처리를 위한 별도 설정
|
|
||||||
area-statistics:
|
|
||||||
chunk-size: 1000 # 5000 → 1000
|
|
||||||
batch-size: 500 # 새로 추가
|
|
||||||
|
|
||||||
chunk-size: 10000
|
|
||||||
page-size: 5000
|
|
||||||
partition-size: 12
|
|
||||||
|
|
||||||
# 성능 최적화 설정
|
|
||||||
optimization:
|
|
||||||
enabled: true
|
|
||||||
dynamic-chunk-sizing: true
|
|
||||||
memory-optimization: true
|
|
||||||
cache-optimization: true
|
|
||||||
thread-pool-optimization: true
|
|
||||||
# 동적 청크 크기 조정
|
|
||||||
chunk:
|
|
||||||
min-size: 1000
|
|
||||||
max-size: 20000
|
|
||||||
adjustment-factor: 0.2
|
|
||||||
# 메모리 임계값
|
|
||||||
memory:
|
|
||||||
warning-threshold: 70
|
|
||||||
critical-threshold: 85
|
|
||||||
optimization-threshold: 80
|
|
||||||
# 캐시 설정
|
|
||||||
cache:
|
|
||||||
min-hit-rate: 70
|
|
||||||
area-boundary-size: 5000
|
|
||||||
|
|
||||||
# Reader 최적화
|
|
||||||
fetch-size: 200000
|
|
||||||
use-cursor-reader: true
|
|
||||||
|
|
||||||
# Bulk Insert 최적화
|
|
||||||
bulk-insert:
|
|
||||||
batch-size: 10000
|
|
||||||
parallel-threads: 8
|
|
||||||
use-binary-copy: false
|
|
||||||
|
|
||||||
# Writer 설정
|
|
||||||
writer:
|
|
||||||
use-advisory-lock: false
|
|
||||||
parallel-threads: 4
|
|
||||||
|
|
||||||
# 재시도 설정
|
|
||||||
retry:
|
|
||||||
max-attempts: 3
|
|
||||||
initial-interval: 1000
|
|
||||||
max-interval: 10000
|
|
||||||
multiplier: 2
|
|
||||||
|
|
||||||
# 스케줄러 설정
|
|
||||||
scheduler:
|
|
||||||
enabled: true
|
|
||||||
incremental:
|
|
||||||
delay-minutes: 3 # 데이터 수집 지연 고려
|
|
||||||
|
|
||||||
# Batch 메타데이터 정리 설정
|
|
||||||
metadata:
|
|
||||||
cleanup:
|
|
||||||
enabled: true # 자동 정리 활성화
|
|
||||||
retention-days: 30 # 보존 기간 (30일)
|
|
||||||
dry-run: false # false: 실제 삭제, true: 테스트만
|
|
||||||
|
|
||||||
# 궤적 비정상 검출 설정
|
|
||||||
track:
|
|
||||||
abnormal-detection:
|
|
||||||
large-gap-threshold-hours: 6 # 이 시간 이상 gap은 연결 안함
|
|
||||||
extreme-speed-threshold: 1000 # 이 속도 이상은 무조건 비정상 (knots)
|
|
||||||
enable-merger-filtering: false # VesselTrackMerger 필터링 활성화 (기본: false)
|
|
||||||
|
|
||||||
# 타임아웃 설정
|
|
||||||
query-timeout: 1800 # 30분
|
|
||||||
lock:
|
|
||||||
timeout: 30
|
|
||||||
max-retry: 5
|
|
||||||
|
|
||||||
# Health Check 설정
|
|
||||||
health:
|
|
||||||
job-timeout-hours: 2
|
|
||||||
min-partition-count: 1
|
|
||||||
|
|
||||||
# 그리드 설정
|
|
||||||
grid:
|
|
||||||
mode: haegu
|
|
||||||
haegu:
|
|
||||||
cache-enabled: true
|
|
||||||
cache-size: 2000
|
|
||||||
|
|
||||||
# 선박 최신 위치 캐시 설정 (운영 환경 활성화)
|
|
||||||
cache:
|
|
||||||
latest-position:
|
|
||||||
enabled: true # 운영 환경: 활성화
|
|
||||||
ttl-minutes: 60 # 60분 TTL
|
|
||||||
max-size: 50000 # 최대 50,000척
|
|
||||||
refresh-interval-minutes: 2 # 2분치 데이터 조회 (수집 지연 고려)
|
|
||||||
|
|
||||||
|
|
||||||
# 비정상 궤적 검출 설정 (개선됨)
|
|
||||||
abnormal-detection:
|
|
||||||
enabled: true
|
|
||||||
5min-speed-threshold: 500 # 5분 집계 비정상 속도 임계값 (200 knots로 완화)
|
|
||||||
# 비정상 판정 기준 (명백한 비정상만 검출하도록 완화)
|
|
||||||
thresholds:
|
|
||||||
# 정박/저속 판단 기준
|
|
||||||
min-movement-nm: 0.05 # 최소 이동거리 (정박 판단)
|
|
||||||
stationary-speed-knots: 0.5 # 정박 속도 기준
|
|
||||||
|
|
||||||
# 선박 관련 임계값
|
|
||||||
vessel-physical-limit-knots: 100.0 # 선박 물리적 한계
|
|
||||||
vessel-abnormal-speed-knots: 200.0 # 선박 명백한 비정상 속도
|
|
||||||
|
|
||||||
# 항공기 관련 임계값
|
|
||||||
aircraft-physical-limit-knots: 600.0 # 항공기 물리적 한계
|
|
||||||
aircraft-abnormal-speed-knots: 800.0 # 항공기 명백한 비정상 속도
|
|
||||||
|
|
||||||
# 거리 관련 임계값
|
|
||||||
base-distance-5min-nm: 20.0 # 5분 기준 거리 (20nm로 완화)
|
|
||||||
extreme-distance-5min-nm: 100.0 # 5분간 극단적 이동거리
|
|
||||||
|
|
||||||
# Hourly/Daily 전용 임계값
|
|
||||||
hourly-daily-speed-limit: 500.0 # 시간/일 집계시 극단적 속도만 검출
|
|
||||||
|
|
||||||
# 기타 설정
|
|
||||||
distance-tolerance: 3.0 # 거리 허용 배수 (3.0으로 완화)
|
|
||||||
time-scaling-method: "sqrt" # 시간 스케일링 방법 (sqrt)
|
|
||||||
# 캐시 설정
|
|
||||||
cache:
|
|
||||||
previous-track-size: 10000 # 이전 궤적 캐시 크기
|
|
||||||
ttl-hours: 24 # 캐시 TTL
|
|
||||||
# 처리 옵션
|
|
||||||
processing:
|
|
||||||
remove-abnormal-segments: false # 비정상 구간 제거 여부
|
|
||||||
save-corrected-tracks: true # 보정된 궤적 저장 여부
|
|
||||||
exclude-stationary-vessels: true # 정박 선박 제외 여부
|
|
||||||
lenient-mode: true # 관대한 모드 활성화
|
|
||||||
|
|
||||||
# 파티션 관리 설정 (운영 환경 - application.yml 설정 오버라이드)
|
|
||||||
partition:
|
|
||||||
# 운영 환경에서는 더 긴 보관 기간 설정 가능
|
|
||||||
default-retention:
|
|
||||||
daily-partitions-retention-days: 7 # 일별 파티션 7일 보관
|
|
||||||
monthly-partitions-retention-months: 3 # 월별 파티션 3개월 보관
|
|
||||||
|
|
||||||
tables:
|
|
||||||
# 중요 데이터는 더 오래 보관
|
|
||||||
t_area_vessel_tracks:
|
|
||||||
retention-days: 60 # 구역별 선박 항적: 60일
|
|
||||||
t_grid_vessel_tracks:
|
|
||||||
retention-days: 30 # 해구별 선박 항적: 30일
|
|
||||||
t_abnormal_tracks:
|
|
||||||
retention-months: 0 # 비정상 항적: 무한 보관
|
|
||||||
|
|
||||||
# S&P AIS API 캐시 TTL (운영 MPR: 120분)
|
|
||||||
app:
|
|
||||||
cache:
|
|
||||||
ais-target:
|
|
||||||
ttl-minutes: 120
|
|
||||||
|
|
||||||
# 일일 항적 데이터 인메모리 캐시
|
|
||||||
cache:
|
|
||||||
daily-track:
|
|
||||||
enabled: true
|
|
||||||
retention-days: 7 # D-1 ~ D-7 (오늘 제외)
|
|
||||||
max-memory-gb: 6 # 최대 6GB
|
|
||||||
warmup-async: true # 비동기 워밍업 (배치 Job과 경합 방지)
|
|
||||||
|
|
||||||
# WebSocket 부하 제어 설정
|
|
||||||
websocket:
|
|
||||||
query:
|
|
||||||
max-concurrent-global: 20 # 배치 서버 동시 쿼리 제한 (메모리 보호: 40→20)
|
|
||||||
max-per-session: 10 # 세션당 동시 쿼리 상한 (15→10)
|
|
||||||
queue-timeout-seconds: 60 # 글로벌 대기 큐 타임아웃 (슬롯 감소 보완: 30→60)
|
|
||||||
transport:
|
|
||||||
message-size-limit-mb: 2 # 단일 STOMP 메시지 상한 (50→2MB, 청크 1024KB 기준)
|
|
||||||
send-buffer-size-limit-mb: 50 # 세션당 송신 버퍼 상한 (사전 할당 아님, 최악 20×50MB=1GB)
|
|
||||||
outbound-queue-capacity: 200 # 아웃바운드 메시지 큐 (5000→200)
|
|
||||||
send-time-limit-seconds: 30 # 메시지 전송 시간 제한
|
|
||||||
memory:
|
|
||||||
heap-reject-threshold: 0.85 # 힙 사용률 85% 초과 시 새 쿼리 대기열 전환 (기본 20~24GB → 정상시 50% 미만)
|
|
||||||
session:
|
|
||||||
idle-timeout-ms: 15000
|
|
||||||
server-heartbeat-ms: 5000
|
|
||||||
client-heartbeat-ms: 5000
|
|
||||||
sockjs-disconnect-delay-ms: 5000
|
|
||||||
send-time-limit-seconds: 30
|
|
||||||
|
|
||||||
# REST V2 부하 제어 설정
|
|
||||||
rest:
|
|
||||||
v2:
|
|
||||||
query:
|
|
||||||
timeout-seconds: 30 # 슬롯 대기 타임아웃 (초)
|
|
||||||
max-total-points: 500000 # 응답 총 포인트 상한
|
|
||||||
|
|
||||||
# 액추에이터 설정
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
exposure:
|
|
||||||
include: health,info,metrics,prometheus,env,loggers,threaddump,heapdump,scheduledtasks
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
show-details: always
|
|
||||||
show-components: always
|
|
||||||
metrics:
|
|
||||||
tags:
|
|
||||||
application: vessel-batch-aggregation
|
|
||||||
environment: prod
|
|
||||||
@ -1,322 +1,267 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# Production Profile — 192.168.1.18 (64코어 Xeon Gold 6430, 250GB RAM)
|
||||||
|
# DB: snpdb @ 211.208.115.83 (signal 스키마)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
server:
|
server:
|
||||||
port: 18090
|
port: 18090
|
||||||
tomcat:
|
tomcat:
|
||||||
threads:
|
threads:
|
||||||
max: 200
|
max: 200
|
||||||
min-spare: 10
|
min-spare: 10
|
||||||
connection-timeout: 60000 # 60초로 증가
|
connection-timeout: 60000
|
||||||
max-http-form-post-size: 50MB # 50MB로 증가
|
max-connections: 10000
|
||||||
max-swallow-size: 50MB # 50MB로 증가
|
accept-count: 100
|
||||||
max-connections: 10000 # 최대 연결 수
|
|
||||||
accept-count: 100 # 대기열 크기
|
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
# 원격 수집 DB
|
|
||||||
collect:
|
collect:
|
||||||
jdbc-url: jdbc:postgresql://10.188.171.182:5432/mdadb?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
jdbc-url: jdbc:postgresql://211.208.115.83:5432/snpdb?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
||||||
username: mda
|
username: snp
|
||||||
password: mda#8932
|
password: snp#8932
|
||||||
driver-class-name: org.postgresql.Driver
|
driver-class-name: org.postgresql.Driver
|
||||||
hikari:
|
hikari:
|
||||||
pool-name: CollectHikariPool
|
pool-name: CollectHikariPool
|
||||||
connection-timeout: 30000 # 원격 연결이므로 타임아웃 증가
|
maximum-pool-size: 50
|
||||||
|
minimum-idle: 10
|
||||||
|
connection-timeout: 30000
|
||||||
idle-timeout: 600000
|
idle-timeout: 600000
|
||||||
max-lifetime: 1800000
|
max-lifetime: 1800000
|
||||||
maximum-pool-size: 80 # 20 -> 80 (총 250 중 32%, 배치 Reader 주 사용)
|
|
||||||
minimum-idle: 15 # 5 -> 15
|
|
||||||
# 원격 연결 안정성을 위한 추가 설정
|
|
||||||
connection-test-query: SELECT 1
|
connection-test-query: SELECT 1
|
||||||
validation-timeout: 5000
|
validation-timeout: 5000
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
leak-detection-threshold: 60000
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
||||||
|
|
||||||
# 원격 조회 DB
|
|
||||||
query:
|
query:
|
||||||
jdbc-url: jdbc:postgresql://10.188.171.182:5432/mdadb?currentSchema=signal&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
jdbc-url: jdbc:postgresql://211.208.115.83:5432/snpdb?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
||||||
username: mda
|
username: snp
|
||||||
password: mda#8932
|
password: snp#8932
|
||||||
driver-class-name: org.postgresql.Driver
|
driver-class-name: org.postgresql.Driver
|
||||||
hikari:
|
hikari:
|
||||||
pool-name: QueryHikariPool
|
pool-name: QueryHikariPool
|
||||||
|
maximum-pool-size: 100
|
||||||
|
minimum-idle: 20
|
||||||
connection-timeout: 5000
|
connection-timeout: 5000
|
||||||
idle-timeout: 600000
|
idle-timeout: 600000
|
||||||
max-lifetime: 1800000
|
max-lifetime: 1800000
|
||||||
maximum-pool-size: 180 # 120 -> 180 (WebSocket 대기열 + REST API 주 사용)
|
|
||||||
minimum-idle: 30 # 20 -> 30
|
|
||||||
connection-test-query: SELECT 1
|
connection-test-query: SELECT 1
|
||||||
validation-timeout: 5000
|
validation-timeout: 5000
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
leak-detection-threshold: 60000
|
||||||
# PostGIS 함수를 위해 public 스키마를 search_path에 명시적으로 추가
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public, pg_catalog;"
|
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public, pg_catalog;"
|
||||||
statement-cache-size: 250
|
statement-cache-size: 250
|
||||||
data-source-properties:
|
data-source-properties:
|
||||||
prepareThreshold: 3
|
prepareThreshold: 3
|
||||||
preparedStatementCacheQueries: 250
|
preparedStatementCacheQueries: 250
|
||||||
|
|
||||||
# 로컬 배치 메타 DB (signal 스키마 사용)
|
|
||||||
batch:
|
batch:
|
||||||
jdbc-url: jdbc:postgresql://10.188.171.182:5432/mdadb?currentSchema=signal&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
jdbc-url: jdbc:postgresql://211.208.115.83:5432/snpdb?currentSchema=public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
||||||
username: mda
|
username: snp
|
||||||
password: mda#8932
|
password: snp#8932
|
||||||
driver-class-name: org.postgresql.Driver
|
driver-class-name: org.postgresql.Driver
|
||||||
hikari:
|
hikari:
|
||||||
pool-name: BatchHikariPool
|
pool-name: BatchHikariPool
|
||||||
maximum-pool-size: 30 # 20 -> 30 (총 250 중 12%, Spring Batch 메타데이터)
|
maximum-pool-size: 20
|
||||||
minimum-idle: 5 # 10 -> 5 (메타데이터 용도이므로 최소 유지)
|
minimum-idle: 5
|
||||||
connection-timeout: 30000 # 30초 타임아웃
|
connection-timeout: 30000
|
||||||
idle-timeout: 600000
|
idle-timeout: 600000
|
||||||
max-lifetime: 1800000
|
max-lifetime: 1800000
|
||||||
leak-detection-threshold: 60000 # 커넥션 누수 감지 (60초)
|
leak-detection-threshold: 60000
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO public, signal;"
|
||||||
|
|
||||||
# Request 크기 설정
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
max-file-size: 50MB
|
|
||||||
max-request-size: 50MB
|
|
||||||
|
|
||||||
# Spring Batch 설정
|
|
||||||
batch:
|
batch:
|
||||||
job:
|
job:
|
||||||
enabled: false
|
enabled: false
|
||||||
jdbc:
|
jdbc:
|
||||||
initialize-schema: never # always에서 never로 변경 (이미 수동으로 생성했으므로)
|
initialize-schema: always
|
||||||
table-prefix: signal.BATCH_
|
table-prefix: BATCH_
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
root: INFO
|
root: INFO
|
||||||
gc.mda.signal_batch: DEBUG
|
gc.mda.signal_batch: INFO
|
||||||
gc.mda.signal_batch.global.util: INFO
|
gc.mda.signal_batch.global.util: WARN
|
||||||
gc.mda.signal_batch.global.websocket.service: INFO
|
gc.mda.signal_batch.global.util.PartitionManager: WARN
|
||||||
gc.mda.signal_batch.batch.writer: INFO
|
gc.mda.signal_batch.batch: INFO
|
||||||
gc.mda.signal_batch.batch.reader: INFO
|
|
||||||
gc.mda.signal_batch.batch.processor: INFO
|
|
||||||
gc.mda.signal_batch.domain: INFO
|
gc.mda.signal_batch.domain: INFO
|
||||||
gc.mda.signal_batch.monitoring: DEBUG
|
gc.mda.signal_batch.monitoring: INFO
|
||||||
gc.mda.signal_batch.monitoring.controller: INFO
|
|
||||||
org.springframework.batch: INFO
|
org.springframework.batch: INFO
|
||||||
org.springframework.jdbc: WARN
|
org.springframework.jdbc: WARN
|
||||||
org.postgresql: WARN
|
org.postgresql: WARN
|
||||||
com.zaxxer.hikari: INFO
|
com.zaxxer.hikari: INFO
|
||||||
|
|
||||||
# 개발 환경 배치 설정 (성능 최적화)
|
# ── 배치 설정 (64코어 최적화) ──
|
||||||
vessel: # spring 하위가 아닌 최상위 레벨
|
vessel:
|
||||||
# 통합선박 설정
|
|
||||||
integration:
|
|
||||||
enabled: true
|
|
||||||
datasource:
|
|
||||||
jdbc-url: jdbc:postgresql://10.188.141.230:5432/mdadb2?currentSchema=gis&options=-csearch_path=gis,public&TimeZone=Asia/Seoul
|
|
||||||
username: mda
|
|
||||||
password: mda#8932
|
|
||||||
table-name: gis.t_ship_integration_sub # gis 스키마는 jdbc-url의 currentSchema로 지정
|
|
||||||
batch:
|
batch:
|
||||||
# Area Statistics 처리를 위한 별도 설정
|
scheduler:
|
||||||
area-statistics:
|
enabled: true
|
||||||
chunk-size: 1000 # 5000 → 1000
|
incremental:
|
||||||
batch-size: 500 # 새로 추가
|
delay-minutes: 3
|
||||||
|
|
||||||
chunk-size: 10000
|
chunk-size: 10000
|
||||||
page-size: 5000
|
page-size: 5000
|
||||||
partition-size: 12
|
partition-size: 32
|
||||||
|
fetch-size: 200000
|
||||||
|
use-cursor-reader: true
|
||||||
|
query-timeout: 1800
|
||||||
|
|
||||||
|
area-statistics:
|
||||||
|
chunk-size: 1000
|
||||||
|
batch-size: 500
|
||||||
|
|
||||||
# 성능 최적화 설정
|
|
||||||
optimization:
|
optimization:
|
||||||
enabled: true
|
enabled: true
|
||||||
dynamic-chunk-sizing: true
|
dynamic-chunk-sizing: true
|
||||||
memory-optimization: true
|
memory-optimization: true
|
||||||
cache-optimization: true
|
cache-optimization: true
|
||||||
thread-pool-optimization: true
|
thread-pool-optimization: true
|
||||||
# 동적 청크 크기 조정
|
|
||||||
chunk:
|
chunk:
|
||||||
min-size: 1000
|
min-size: 1000
|
||||||
max-size: 20000
|
max-size: 20000
|
||||||
adjustment-factor: 0.2
|
adjustment-factor: 0.2
|
||||||
# 메모리 임계값
|
|
||||||
memory:
|
memory:
|
||||||
warning-threshold: 70
|
warning-threshold: 70
|
||||||
critical-threshold: 85
|
critical-threshold: 85
|
||||||
optimization-threshold: 80
|
optimization-threshold: 80
|
||||||
# 캐시 설정
|
|
||||||
cache:
|
cache:
|
||||||
min-hit-rate: 70
|
min-hit-rate: 70
|
||||||
area-boundary-size: 5000
|
area-boundary-size: 5000
|
||||||
|
|
||||||
# Reader 최적화
|
|
||||||
fetch-size: 200000
|
|
||||||
use-cursor-reader: true
|
|
||||||
|
|
||||||
# Bulk Insert 최적화
|
|
||||||
bulk-insert:
|
bulk-insert:
|
||||||
batch-size: 10000
|
batch-size: 10000
|
||||||
parallel-threads: 8
|
parallel-threads: 16
|
||||||
use-binary-copy: false
|
use-binary-copy: false
|
||||||
|
|
||||||
# Writer 설정
|
|
||||||
writer:
|
writer:
|
||||||
use-advisory-lock: false
|
use-advisory-lock: false
|
||||||
parallel-threads: 4
|
parallel-threads: 8
|
||||||
|
|
||||||
# 재시도 설정
|
|
||||||
retry:
|
retry:
|
||||||
max-attempts: 3
|
max-attempts: 3
|
||||||
initial-interval: 1000
|
initial-interval: 1000
|
||||||
max-interval: 10000
|
max-interval: 10000
|
||||||
multiplier: 2
|
multiplier: 2
|
||||||
|
|
||||||
# 스케줄러 설정
|
|
||||||
scheduler:
|
|
||||||
enabled: true
|
|
||||||
incremental:
|
|
||||||
delay-minutes: 3 # 데이터 수집 지연 고려
|
|
||||||
|
|
||||||
# Batch 메타데이터 정리 설정
|
|
||||||
metadata:
|
metadata:
|
||||||
cleanup:
|
cleanup:
|
||||||
enabled: true # 자동 정리 활성화
|
enabled: true
|
||||||
retention-days: 21 # 보존 기간 (30일)
|
retention-days: 21
|
||||||
dry-run: false # false: 실제 삭제, true: 테스트만
|
dry-run: false
|
||||||
|
|
||||||
# 궤적 비정상 검출 설정
|
|
||||||
track:
|
track:
|
||||||
abnormal-detection:
|
abnormal-detection:
|
||||||
large-gap-threshold-hours: 4 # 이 시간 이상 gap은 연결 안함
|
large-gap-threshold-hours: 4
|
||||||
extreme-speed-threshold: 1000 # 이 속도 이상은 무조건 비정상 (knots)
|
extreme-speed-threshold: 1000
|
||||||
enable-merger-filtering: false # VesselTrackMerger 필터링 활성화 (기본: false)
|
enable-merger-filtering: false
|
||||||
|
|
||||||
# 타임아웃 설정
|
|
||||||
query-timeout: 1800 # 30분
|
|
||||||
lock:
|
lock:
|
||||||
timeout: 30
|
timeout: 30
|
||||||
max-retry: 5
|
max-retry: 5
|
||||||
|
|
||||||
# Health Check 설정
|
|
||||||
health:
|
health:
|
||||||
job-timeout-hours: 2
|
job-timeout-hours: 2
|
||||||
min-partition-count: 1
|
min-partition-count: 1
|
||||||
|
|
||||||
# 그리드 설정
|
|
||||||
grid:
|
grid:
|
||||||
mode: haegu
|
mode: haegu
|
||||||
haegu:
|
haegu:
|
||||||
cache-enabled: true
|
cache-enabled: true
|
||||||
cache-size: 2000
|
cache-size: 2000
|
||||||
|
|
||||||
# 선박 최신 위치 캐시 설정 (운영 환경 활성화)
|
|
||||||
cache:
|
cache:
|
||||||
latest-position:
|
latest-position:
|
||||||
enabled: true # 운영 환경: 활성화
|
enabled: true
|
||||||
ttl-minutes: 60 # 60분 TTL
|
ttl-minutes: 60
|
||||||
max-size: 60000 # 최대 60,000척
|
max-size: 60000
|
||||||
refresh-interval-minutes: 2 # 2분치 데이터 조회 (수집 지연 고려)
|
refresh-interval-minutes: 2
|
||||||
|
|
||||||
|
|
||||||
# 비정상 궤적 검출 설정 (개선됨)
|
|
||||||
abnormal-detection:
|
abnormal-detection:
|
||||||
enabled: true
|
enabled: true
|
||||||
5min-speed-threshold: 500 # 5분 집계 비정상 속도 임계값 (200 knots로 완화)
|
5min-speed-threshold: 500
|
||||||
# 비정상 판정 기준 (명백한 비정상만 검출하도록 완화)
|
|
||||||
thresholds:
|
thresholds:
|
||||||
# 정박/저속 판단 기준
|
min-movement-nm: 0.05
|
||||||
min-movement-nm: 0.05 # 최소 이동거리 (정박 판단)
|
stationary-speed-knots: 0.5
|
||||||
stationary-speed-knots: 0.5 # 정박 속도 기준
|
vessel-physical-limit-knots: 100.0
|
||||||
|
vessel-abnormal-speed-knots: 200.0
|
||||||
# 선박 관련 임계값
|
aircraft-physical-limit-knots: 600.0
|
||||||
vessel-physical-limit-knots: 100.0 # 선박 물리적 한계
|
aircraft-abnormal-speed-knots: 800.0
|
||||||
vessel-abnormal-speed-knots: 200.0 # 선박 명백한 비정상 속도
|
base-distance-5min-nm: 20.0
|
||||||
|
extreme-distance-5min-nm: 100.0
|
||||||
# 항공기 관련 임계값
|
hourly-daily-speed-limit: 500.0
|
||||||
aircraft-physical-limit-knots: 600.0 # 항공기 물리적 한계
|
distance-tolerance: 3.0
|
||||||
aircraft-abnormal-speed-knots: 800.0 # 항공기 명백한 비정상 속도
|
time-scaling-method: "sqrt"
|
||||||
|
|
||||||
# 거리 관련 임계값
|
|
||||||
base-distance-5min-nm: 20.0 # 5분 기준 거리 (20nm로 완화)
|
|
||||||
extreme-distance-5min-nm: 100.0 # 5분간 극단적 이동거리
|
|
||||||
|
|
||||||
# Hourly/Daily 전용 임계값
|
|
||||||
hourly-daily-speed-limit: 500.0 # 시간/일 집계시 극단적 속도만 검출
|
|
||||||
|
|
||||||
# 기타 설정
|
|
||||||
distance-tolerance: 3.0 # 거리 허용 배수 (3.0으로 완화)
|
|
||||||
time-scaling-method: "sqrt" # 시간 스케일링 방법 (sqrt)
|
|
||||||
# 캐시 설정
|
|
||||||
cache:
|
cache:
|
||||||
previous-track-size: 10000 # 이전 궤적 캐시 크기
|
previous-track-size: 10000
|
||||||
ttl-hours: 24 # 캐시 TTL
|
ttl-hours: 24
|
||||||
# 처리 옵션
|
|
||||||
processing:
|
processing:
|
||||||
remove-abnormal-segments: true # 비정상 구간 제거 여부
|
remove-abnormal-segments: true
|
||||||
save-corrected-tracks: true # 보정된 궤적 저장 여부
|
save-corrected-tracks: true
|
||||||
exclude-stationary-vessels: false # 정박 선박 제외 여부
|
exclude-stationary-vessels: false
|
||||||
lenient-mode: true # 관대한 모드 활성화
|
lenient-mode: true
|
||||||
|
|
||||||
# 파티션 관리 설정 (운영 환경 - application.yml 설정 오버라이드)
|
|
||||||
partition:
|
partition:
|
||||||
# 운영 환경에서는 더 긴 보관 기간 설정 가능
|
|
||||||
default-retention:
|
default-retention:
|
||||||
daily-partitions-retention-days: 7 # 일별 파티션 7일 보관
|
daily-partitions-retention-days: 7
|
||||||
monthly-partitions-retention-months: 3 # 월별 파티션 3개월 보관
|
monthly-partitions-retention-months: 3
|
||||||
|
|
||||||
tables:
|
tables:
|
||||||
# 중요 데이터는 더 오래 보관
|
|
||||||
t_area_vessel_tracks:
|
t_area_vessel_tracks:
|
||||||
retention-days: 60 # 구역별 선박 항적: 60일
|
retention-days: 60
|
||||||
t_grid_vessel_tracks:
|
t_grid_vessel_tracks:
|
||||||
retention-days: 30 # 해구별 선박 항적: 30일
|
retention-days: 30
|
||||||
t_abnormal_tracks:
|
t_abnormal_tracks:
|
||||||
retention-months: 0 # 비정상 항적: 무한 보관
|
retention-months: 0
|
||||||
|
|
||||||
# S&P AIS API 캐시 TTL (운영: 120분)
|
# ── AIS API ──
|
||||||
app:
|
app:
|
||||||
|
ais-api:
|
||||||
|
username: 7cc0517d-5ed6-452e-a06f-5bbfd6ab6ade
|
||||||
|
password: 2LLzSJNqtxWVD8zC
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
ais-target:
|
ais-target:
|
||||||
ttl-minutes: 120
|
ttl-minutes: 120
|
||||||
|
|
||||||
five-min-track:
|
five-min-track:
|
||||||
ttl-minutes: 75
|
ttl-minutes: 75
|
||||||
max-size: 500000
|
max-size: 500000
|
||||||
|
|
||||||
hourly-track:
|
hourly-track:
|
||||||
ttl-hours: 26
|
ttl-hours: 26
|
||||||
max-size: 780000
|
max-size: 780000
|
||||||
|
|
||||||
# 일일 항적 데이터 인메모리 캐시
|
# ── 일일 항적 인메모리 캐시 (250GB 서버, 힙 64GB) ──
|
||||||
cache:
|
cache:
|
||||||
daily-track:
|
daily-track:
|
||||||
enabled: true
|
enabled: true
|
||||||
retention-days: 7 # D-1 ~ D-7 (오늘 제외)
|
retention-days: 7
|
||||||
max-memory-gb: 6 # 최대 6GB (일 평균 ~720MB × 7일 = ~5GB)
|
max-memory-gb: 16
|
||||||
warmup-async: true # 비동기 워밍업 (서버 시작 차단 없음)
|
warmup-async: true
|
||||||
|
|
||||||
# WebSocket 부하 제어 설정
|
# ── WebSocket 부하 제어 ──
|
||||||
websocket:
|
websocket:
|
||||||
query:
|
query:
|
||||||
max-concurrent-global: 30 # 서버 전체 동시 실행 쿼리 상한 (메모리 보호: 60→30)
|
max-concurrent-global: 30
|
||||||
max-per-session: 10 # 세션당 동시 쿼리 상한 (20→10)
|
max-per-session: 10
|
||||||
queue-timeout-seconds: 60 # 글로벌 대기 큐 타임아웃 (슬롯 감소 보완: 30→60)
|
queue-timeout-seconds: 60
|
||||||
transport:
|
transport:
|
||||||
message-size-limit-mb: 2 # 단일 STOMP 메시지 상한 (50→2MB, 청크 1024KB 기준)
|
message-size-limit-mb: 2
|
||||||
send-buffer-size-limit-mb: 50 # 세션당 송신 버퍼 상한 (사전 할당 아님, 최악 30×50MB=1.5GB)
|
send-buffer-size-limit-mb: 50
|
||||||
outbound-queue-capacity: 200 # 아웃바운드 메시지 큐 (5000→200)
|
outbound-queue-capacity: 200
|
||||||
send-time-limit-seconds: 30 # 메시지 전송 시간 제한
|
send-time-limit-seconds: 30
|
||||||
memory:
|
memory:
|
||||||
heap-reject-threshold: 0.85 # 힙 사용률 85% 초과 시 새 쿼리 대기열 전환 (기본 20~24GB → 정상시 50% 미만)
|
heap-reject-threshold: 0.85
|
||||||
session:
|
session:
|
||||||
idle-timeout-ms: 15000 # 세션 유휴 타임아웃 15초 (60s → 15s)
|
idle-timeout-ms: 15000
|
||||||
server-heartbeat-ms: 5000 # 서버 하트비트 5초 (10s → 5s)
|
server-heartbeat-ms: 5000
|
||||||
client-heartbeat-ms: 5000 # 클라이언트 하트비트 5초 (10s → 5s)
|
client-heartbeat-ms: 5000
|
||||||
sockjs-disconnect-delay-ms: 5000 # SockJS 해제 지연 5초 (30s → 5s)
|
sockjs-disconnect-delay-ms: 5000
|
||||||
send-time-limit-seconds: 30 # 메시지 전송 시간 제한 30초 (120s → 30s)
|
send-time-limit-seconds: 30
|
||||||
|
|
||||||
# REST V2 부하 제어 설정
|
# ── REST V2 부하 제어 ──
|
||||||
rest:
|
rest:
|
||||||
v2:
|
v2:
|
||||||
query:
|
query:
|
||||||
timeout-seconds: 30 # 슬롯 대기 타임아웃 (초)
|
timeout-seconds: 30
|
||||||
max-total-points: 500000 # 응답 총 포인트 상한
|
max-total-points: 500000
|
||||||
|
|
||||||
# 액추에이터 설정
|
# ── 액추에이터 ──
|
||||||
management:
|
management:
|
||||||
endpoints:
|
endpoints:
|
||||||
web:
|
web:
|
||||||
|
|||||||
@ -1,138 +0,0 @@
|
|||||||
# 조회 전용 서버 설정 (10.29.17.90)
|
|
||||||
# 배치 작업 없이 API 조회만 수행하는 프로파일
|
|
||||||
server:
|
|
||||||
port: 8090
|
|
||||||
tomcat:
|
|
||||||
threads:
|
|
||||||
max: 200
|
|
||||||
min-spare: 10
|
|
||||||
connection-timeout: 60000
|
|
||||||
max-http-form-post-size: 50MB
|
|
||||||
max-swallow-size: 50MB
|
|
||||||
max-connections: 10000
|
|
||||||
accept-count: 100
|
|
||||||
|
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
# 조회 전용 DB (10.29.17.90 로컬 DB) - 표준 Spring Boot DataSource 설정
|
|
||||||
url: jdbc:postgresql://localhost:5432/mpcdb2?currentSchema=signal&options=-csearch_path=signal,public&assumeMinServerVersion=12&reWriteBatchedInserts=true
|
|
||||||
username: mpc
|
|
||||||
password: mpc#8932
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
pool-name: QueryOnlyHikariPool
|
|
||||||
connection-timeout: 5000
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
maximum-pool-size: 60
|
|
||||||
minimum-idle: 10
|
|
||||||
connection-test-query: SELECT 1
|
|
||||||
validation-timeout: 5000
|
|
||||||
leak-detection-threshold: 60000
|
|
||||||
connection-init-sql: "SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;"
|
|
||||||
data-source-properties:
|
|
||||||
prepareThreshold: 3
|
|
||||||
preparedStatementCacheQueries: 250
|
|
||||||
|
|
||||||
# Request 크기 설정
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
max-file-size: 50MB
|
|
||||||
max-request-size: 50MB
|
|
||||||
|
|
||||||
# Spring Batch 자동 구성 완전 비활성화
|
|
||||||
autoconfigure:
|
|
||||||
exclude:
|
|
||||||
- org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration
|
|
||||||
|
|
||||||
# Spring Batch Job 비활성화
|
|
||||||
batch:
|
|
||||||
job:
|
|
||||||
enabled: false
|
|
||||||
jdbc:
|
|
||||||
initialize-schema: never
|
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
root: INFO
|
|
||||||
gc.mda.signal_batch: DEBUG
|
|
||||||
gc.mda.signal_batch.global.util: INFO
|
|
||||||
gc.mda.signal_batch.global.websocket.service: INFO
|
|
||||||
gc.mda.signal_batch.batch: WARN # 배치 관련 로그 최소화
|
|
||||||
gc.mda.signal_batch.domain: INFO
|
|
||||||
gc.mda.signal_batch.monitoring: DEBUG
|
|
||||||
gc.mda.signal_batch.monitoring.controller: INFO
|
|
||||||
org.springframework.batch: WARN # 배치 관련 로그 최소화
|
|
||||||
org.springframework.jdbc: WARN
|
|
||||||
org.postgresql: WARN
|
|
||||||
com.zaxxer.hikari: INFO
|
|
||||||
|
|
||||||
# 배치 설정 (조회 전용 서버에서는 사용 안 함)
|
|
||||||
vessel:
|
|
||||||
# 통합선박 기능 비활성화 (query DB에 통합테이블이 없을 수 있음)
|
|
||||||
integration:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
batch:
|
|
||||||
# 스케줄러 비활성화 (중요!)
|
|
||||||
scheduler:
|
|
||||||
enabled: false
|
|
||||||
incremental:
|
|
||||||
delay-minutes: 3
|
|
||||||
|
|
||||||
# 비정상 궤적 검출 비활성화
|
|
||||||
abnormal-detection:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# 기타 배치 설정은 사용되지 않지만 기본값 유지
|
|
||||||
chunk-size: 10000
|
|
||||||
page-size: 5000
|
|
||||||
partition-size: 12
|
|
||||||
|
|
||||||
# 일일 항적 데이터 인메모리 캐시 (조회 전용 서버의 핵심 성능 설정)
|
|
||||||
cache:
|
|
||||||
daily-track:
|
|
||||||
enabled: true
|
|
||||||
retention-days: 7 # D-1 ~ D-7 (오늘 제외)
|
|
||||||
max-memory-gb: 6 # 최대 6GB (조회 전용이므로 배치 없이 메모리 여유)
|
|
||||||
warmup-async: true # 비동기 워밍업 (서버 시작 차단 없음)
|
|
||||||
|
|
||||||
# WebSocket 부하 제어 설정
|
|
||||||
websocket:
|
|
||||||
query:
|
|
||||||
max-concurrent-global: 40 # 조회 전용 서버 (배치 없으므로 prod-mpr보다 여유)
|
|
||||||
max-per-session: 15 # 세션당 동시 쿼리 상한
|
|
||||||
queue-timeout-seconds: 30 # 글로벌 대기 큐 타임아웃
|
|
||||||
transport:
|
|
||||||
message-size-limit-mb: 2 # 단일 STOMP 메시지 상한 (청크 1024KB 기준)
|
|
||||||
send-buffer-size-limit-mb: 50 # 세션당 송신 버퍼 상한 (사전 할당 아님, 최악 40×50MB=2GB)
|
|
||||||
outbound-queue-capacity: 200 # 아웃바운드 메시지 큐
|
|
||||||
send-time-limit-seconds: 30 # 메시지 전송 시간 제한
|
|
||||||
session:
|
|
||||||
idle-timeout-ms: 15000
|
|
||||||
server-heartbeat-ms: 5000
|
|
||||||
client-heartbeat-ms: 5000
|
|
||||||
sockjs-disconnect-delay-ms: 5000
|
|
||||||
send-time-limit-seconds: 30
|
|
||||||
|
|
||||||
# REST V2 부하 제어 설정
|
|
||||||
rest:
|
|
||||||
v2:
|
|
||||||
query:
|
|
||||||
timeout-seconds: 30 # 슬롯 대기 타임아웃 (초)
|
|
||||||
max-total-points: 500000 # 응답 총 포인트 상한
|
|
||||||
|
|
||||||
# 액추에이터 설정
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
exposure:
|
|
||||||
include: health,info,metrics,prometheus,env,loggers,threaddump,heapdump
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
show-details: always
|
|
||||||
show-components: always
|
|
||||||
metrics:
|
|
||||||
tags:
|
|
||||||
application: vessel-query-server
|
|
||||||
environment: query
|
|
||||||
불러오는 중...
Reference in New Issue
Block a user