[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