> For the complete documentation index, see [llms.txt](https://kopens.gitbook.io/plantpulse-platform/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kopens.gitbook.io/plantpulse-platform/admin/startup-shutdown.md).

# 시스템 시작 및 종료

## 개요

PlantPulse 의 시작 / 종료 / 재시작은 **`plantpulse-startup/` 통합 스크립트** 한 곳에서 모두 관리합니다. 모듈 간 의존성 순서가 자동으로 적용되므로 운영자가 일일이 순서를 신경 쓸 필요는 없습니다.

```mermaid
flowchart LR
  CMD[./start-daemon.sh] --> CHECK[prepared.sh<br/>환경 검증]
  CHECK --> STARTUP[startup.jar<br/>의존성 순서 자동 적용]
  STARTUP --> SEQ[8단계 순차 기동]
  SEQ --> HEALTH[health 대기]
  HEALTH --> RUN[전체 RUNNING]
```

> **권장**: 가능한 한 `start-daemon.sh` / `stop.sh` / `restart.sh` 만 사용하세요. 아래 수동 / 컴포넌트별 절차는 트러블슈팅이나 검증 환경에서만 필요합니다.

## 권장 운영 명령 (요약)

```bash
cd /opt/kopens/plantpulse-platform/plantpulse-startup

./start-daemon.sh      # 백그라운드 시작 (운영)
./start.sh             # 포그라운드 시작 (검증)
./stop.sh              # 안전 종료 (역순)
./restart.sh           # stop → clean → start-daemon
./status.sh            # 전체 모듈 상태
./ops-check.sh         # 헬스 + critical log
./log-viewer.sh        # 통합 로그
./kill.sh              # 강제 종료 (응답 없을 때 / 데이터 손상 위험)
```

## 시작 순서 (자동) <a href="#startup-order" id="startup-order"></a>

`start-daemon.sh` 가 다음 8단계를 자동으로 의존성 순서에 따라 기동합니다. 각 단계 완료 후 다음 단계로 진행하므로 운영자가 개입할 필요는 없습니다.

```mermaid
flowchart TD
  S1[1 스토리지<br/>Valkey · PostgreSQL · Cassandra · MinIO]
  S2[2 분석<br/>Spark · Hadoop · Hive · Kyuubi · Gravitino]
  S3[3 시계열<br/>Time-Series Engine · UI]
  S4[4 메시징<br/>Kafka · MQTT · STOMP]
  S5[5 워크플로우<br/>Temporal · Kestra]
  S6[6 처리<br/>CEP · Data Gateway · SQL · Monitor]
  S7[7 플러그인<br/>OPC-UA · AAS]
  S8[8 애플리케이션<br/>Warehouse · Batch · Server]

  S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7 --> S8
```

| 순서 | 영역     | 주요 컴포넌트                              | 대표 포트                       |
| -- | ------ | ------------------------------------ | --------------------------- |
| 1  | 스토리지   | Cassandra, PostgreSQL, Valkey, MinIO | 9042 / 5432 / 6379 / 9000   |
| 2  | 분석     | Spark, Hive, Kyuubi, Gravitino       | 7077 / 9083 / 10000 / 19001 |
| 3  | 시계열    | TSE Engine, UI                       | 7800 / 3000                 |
| 4  | 메시징    | Kafka, MQTT, STOMP                   | 9092 / 1883 / 61000         |
| 5  | 워크플로우  | Temporal, Kestra                     | 7233 / 8233 / 8380          |
| 6  | 처리     | CEP, Data Gateway, SQL, Monitor      | 7400 / 5500 / 4000 / 4949   |
| 7  | 플러그인   | OPC-UA, AAS                          | 11004 / 8007 / 8090         |
| 8  | 애플리케이션 | Server, Batch, Warehouse             | 80 / 9500 / 9600            |

전체 부팅까지 약 **3 \~ 5분** 소요됩니다 (Cassandra 스키마 마이그레이션 + JVM warm-up).

### (트러블슈팅용) 수동 단계 시작

위 자동 순서가 실패한 경우, 단계별로 수동 시작해 가며 어느 단계에서 막혔는지 진단할 수 있습니다.

### Linux 시작 (systemd) <a href="#linux-systemd-start" id="linux-systemd-start"></a>

systemd 서비스가 등록되어 있는 경우 다음 명령어로 시작할 수 있습니다.

```bash
# 1. 스토리지 서비스 시작
sudo systemctl start plantpulse-postgresql
sudo systemctl start plantpulse-redis
sudo systemctl start plantpulse-cassandra

# Cassandra가 완전히 시작될 때까지 대기 (약 30~60초)
until cqlsh 127.0.0.1 -e "DESCRIBE KEYSPACES" > /dev/null 2>&1; do
    echo "Cassandra 시작 대기 중..."
    sleep 5
done
echo "Cassandra 시작 완료"

# 2. 메시징 서비스 시작
sudo systemctl start plantpulse-kafka
sudo systemctl start plantpulse-mqtt

# 3. 엔진 서비스 시작
sudo systemctl start plantpulse-timeseries
sudo systemctl start plantpulse-cep

# 4. 웹서버 시작
sudo systemctl start plantpulse-server

# 5. 에이전트 시작
sudo systemctl start plantpulse-agent
```

### Linux 수동 시작 <a href="#linux-manual-start" id="linux-manual-start"></a>

systemd를 사용하지 않는 경우 각 모듈의 시작 스크립트를 직접 실행할 수 있습니다.

```bash
# 스토리지
/opt/kopens/plantpulse-platform/plantpulse-storage/db/postgresql/bin/pg_ctl start -D /opt/kopens/plantpulse-platform/plantpulse-storage/db/postgresql/data
/opt/kopens/plantpulse-platform/plantpulse-storage/db/valkey/bin/valkey-server /opt/kopens/plantpulse-platform/plantpulse-storage/db/valkey/conf/valkey.conf &
/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/bin/cassandra

# 메시징
/opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/bin/kafka-server-start.sh -daemon /opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/config/server.properties
/opt/kopens/plantpulse-platform/plantpulse-messaging/mqtt/bin/startup.sh

# 엔진
/opt/kopens/plantpulse-platform/plantpulse-timeseries/bin/startup.sh
/opt/kopens/plantpulse-platform/plantpulse-cep/bin/startup.sh

# 웹서버
/opt/kopens/plantpulse-platform/plantpulse-server/bin/startup.sh

# 에이전트
/opt/kopens/plantpulse-platform/plantpulse-plugin/opc-ua/bin/startup.sh
```

### 시작 스크립트 (의존성 체크 포함) <a href="#startup-script" id="startup-script"></a>

아래는 의존성을 확인하면서 순차적으로 시작하는 스크립트 예시입니다.

```bash
#!/bin/bash
# plantpulse-start-all.sh - 전체 플랫폼 시작 스크립트

KOPENS_HOME="/home/kopens"
LOG_FILE="/var/log/plantpulse/startup.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

wait_for_port() {
    local host=$1 port=$2 timeout=${3:-60}
    local elapsed=0
    while ! nc -z "$host" "$port" 2>/dev/null; do
        if [ $elapsed -ge $timeout ]; then
            log "ERROR: $host:$port 연결 타임아웃 (${timeout}초)"
            return 1
        fi
        sleep 2
        elapsed=$((elapsed + 2))
    done
    log "OK: $host:$port 연결 확인"
    return 0
}

# 1. PostgreSQL
log "PostgreSQL 시작 중..."
sudo systemctl start plantpulse-postgresql
wait_for_port 127.0.0.1 5432 30 || exit 1

# 2. Redis
log "Redis 시작 중..."
sudo systemctl start plantpulse-redis
wait_for_port 127.0.0.1 6379 15 || exit 1

# 3. Cassandra
log "Cassandra 시작 중..."
sudo systemctl start plantpulse-cassandra
wait_for_port 127.0.0.1 9042 120 || exit 1

# 4. Kafka & MQTT
log "Kafka 시작 중..."
sudo systemctl start plantpulse-kafka
wait_for_port 127.0.0.1 9092 30 || exit 1

log "MQTT 시작 중..."
sudo systemctl start plantpulse-mqtt
wait_for_port 127.0.0.1 1883 15 || exit 1

# 5. TSE
log "시계열 엔진 시작 중..."
sudo systemctl start plantpulse-timeseries
wait_for_port 127.0.0.1 7800 30 || exit 1

# 6. CEP
log "CEP 엔진 시작 중..."
sudo systemctl start plantpulse-cep
wait_for_port 127.0.0.1 7400 30 || exit 1

# 7. 웹서버
log "PlantPulse 웹서버 시작 중..."
sudo systemctl start plantpulse-server
wait_for_port 127.0.0.1 80 60 || exit 1

# 8. OPC Agent
log "OPC Agent 시작 중..."
sudo systemctl start plantpulse-agent
wait_for_port 127.0.0.1 60000 30 || exit 1

log "전체 플랫폼 시작 완료"
```

### Windows 시작 <a href="#windows-start" id="windows-start"></a>

#### Windows 서비스

Windows 환경에서 서비스로 등록된 경우 서비스 관리자(services.msc) 또는 명령 프롬프트에서 시작할 수 있습니다.

```powershell
# 서비스 시작 (관리자 권한 PowerShell)
Start-Service PlantPulse-PostgreSQL
Start-Service PlantPulse-Redis
Start-Service PlantPulse-Cassandra
Start-Service PlantPulse-Kafka
Start-Service PlantPulse-MQTT
Start-Service PlantPulse-TSE
Start-Service PlantPulse-CEP
Start-Service PlantPulse-Server
Start-Service PlantPulse-Agent
```

#### 배치 파일 시작

```bat
@echo off
REM plantpulse-start-all.bat - 전체 시작 배치 파일

echo [%date% %time%] PostgreSQL 시작 중...
net start PlantPulse-PostgreSQL
timeout /t 10 /nobreak > nul

echo [%date% %time%] Redis 시작 중...
net start PlantPulse-Redis
timeout /t 5 /nobreak > nul

echo [%date% %time%] Cassandra 시작 중...
net start PlantPulse-Cassandra
timeout /t 60 /nobreak > nul

echo [%date% %time%] Kafka 시작 중...
net start PlantPulse-Kafka
timeout /t 10 /nobreak > nul

echo [%date% %time%] MQTT 시작 중...
net start PlantPulse-MQTT
timeout /t 5 /nobreak > nul

echo [%date% %time%] 시계열 엔진 시작 중...
net start PlantPulse-TSE
timeout /t 10 /nobreak > nul

echo [%date% %time%] CEP 시작 중...
net start PlantPulse-CEP
timeout /t 10 /nobreak > nul

echo [%date% %time%] 웹서버 시작 중...
net start PlantPulse-Server
timeout /t 30 /nobreak > nul

echo [%date% %time%] OPC Agent 시작 중...
net start PlantPulse-Agent
timeout /t 10 /nobreak > nul

echo [%date% %time%] 전체 시작 완료
pause
```

***

## 종료 순서 <a href="#shutdown-order" id="shutdown-order"></a>

종료는 시작의 **역순**으로 수행해야 합니다. 데이터를 수집하는 에이전트부터 먼저 종료하고, 마지막으로 데이터베이스를 종료합니다.

| 순서 | 서비스                     | 설명         |
| -- | ----------------------- | ---------- |
| 1  | OPC Agent               | 데이터 수집 중지  |
| 2  | PlantPulse 웹서버 (Tomcat) | 웹 서비스 중지   |
| 3  | CEP                     | 이벤트 처리 중지  |
| 4  | TSE                     | 시계열 엔진 중지  |
| 5  | MQ (Kafka / MQTT)       | 메시지 브로커 중지 |
| 6  | Cassandra               | 시계열 DB 중지  |
| 7  | Redis (Valkey)          | 캐시 중지      |
| 8  | PostgreSQL              | 메타 DB 중지   |

> **주의:** Cassandra를 다른 서비스보다 먼저 종료하면 아직 플러시되지 않은 Memtable 데이터가 유실될 수 있습니다. 반드시 에이전트와 웹서버를 먼저 종료하여 데이터 쓰기를 중지한 후 Cassandra를 종료해 주세요. Cassandra 종료 전에 `nodetool drain` 명령으로 Memtable을 강제 플러시하는 것을 권장합니다.

### Linux 종료 명령어 <a href="#linux-shutdown" id="linux-shutdown"></a>

```bash
# 1. 에이전트 종료
sudo systemctl stop plantpulse-agent

# 2. 웹서버 종료
sudo systemctl stop plantpulse-server

# 3. 엔진 종료
sudo systemctl stop plantpulse-cep
sudo systemctl stop plantpulse-timeseries

# 4. 메시징 종료
sudo systemctl stop plantpulse-mqtt
sudo systemctl stop plantpulse-kafka

# 5. Cassandra 안전 종료 (Memtable 플러시 후 종료)
/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/bin/nodetool drain
sudo systemctl stop plantpulse-cassandra

# 6. Redis 종료
sudo systemctl stop plantpulse-redis

# 7. PostgreSQL 종료
sudo systemctl stop plantpulse-postgresql
```

### Windows 종료 명령어 <a href="#windows-shutdown" id="windows-shutdown"></a>

```powershell
# 역순으로 서비스 중지 (관리자 권한 PowerShell)
Stop-Service PlantPulse-Agent
Stop-Service PlantPulse-Server
Stop-Service PlantPulse-CEP
Stop-Service PlantPulse-TSE
Stop-Service PlantPulse-MQTT
Stop-Service PlantPulse-Kafka
Stop-Service PlantPulse-Cassandra
Stop-Service PlantPulse-Redis
Stop-Service PlantPulse-PostgreSQL
```

```bat
@echo off
REM plantpulse-stop-all.bat - 전체 종료 배치 파일

echo [%date% %time%] OPC Agent 종료 중...
net stop PlantPulse-Agent
timeout /t 5 /nobreak > nul

echo [%date% %time%] 웹서버 종료 중...
net stop PlantPulse-Server
timeout /t 10 /nobreak > nul

echo [%date% %time%] CEP 종료 중...
net stop PlantPulse-CEP
timeout /t 5 /nobreak > nul

echo [%date% %time%] 시계열 엔진 종료 중...
net stop PlantPulse-TSE
timeout /t 5 /nobreak > nul

echo [%date% %time%] MQTT 종료 중...
net stop PlantPulse-MQTT
timeout /t 5 /nobreak > nul

echo [%date% %time%] Kafka 종료 중...
net stop PlantPulse-Kafka
timeout /t 10 /nobreak > nul

echo [%date% %time%] Cassandra 종료 중...
net stop PlantPulse-Cassandra
timeout /t 30 /nobreak > nul

echo [%date% %time%] Redis 종료 중...
net stop PlantPulse-Redis
timeout /t 5 /nobreak > nul

echo [%date% %time%] PostgreSQL 종료 중...
net stop PlantPulse-PostgreSQL
timeout /t 10 /nobreak > nul

echo [%date% %time%] 전체 종료 완료
pause
```

***

## 재시작 <a href="#restart" id="restart"></a>

### 일반 재시작 <a href="#normal-restart" id="normal-restart"></a>

전체 플랫폼을 재시작하려면 종료 후 시작을 순서대로 수행합니다.

```bash
# 전체 종료 (역순)
sudo systemctl stop plantpulse-agent
sudo systemctl stop plantpulse-server
sudo systemctl stop plantpulse-cep
sudo systemctl stop plantpulse-timeseries
sudo systemctl stop plantpulse-mqtt
sudo systemctl stop plantpulse-kafka
/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/bin/nodetool drain
sudo systemctl stop plantpulse-cassandra
sudo systemctl stop plantpulse-redis
sudo systemctl stop plantpulse-postgresql

# 전체 시작 (정순)
sudo systemctl start plantpulse-postgresql
sudo systemctl start plantpulse-redis
sudo systemctl start plantpulse-cassandra
sleep 60  # Cassandra 시작 대기
sudo systemctl start plantpulse-kafka
sudo systemctl start plantpulse-mqtt
sudo systemctl start plantpulse-timeseries
sudo systemctl start plantpulse-cep
sudo systemctl start plantpulse-server
sudo systemctl start plantpulse-agent
```

### Rolling Restart (무중단 재시작) <a href="#rolling-restart" id="rolling-restart"></a>

클러스터 환경에서는 서비스 중단 없이 노드를 하나씩 재시작하는 Rolling Restart를 수행할 수 있습니다.

```bash
#!/bin/bash
# rolling-restart.sh - 클러스터 Rolling Restart
# 사용법: ./rolling-restart.sh node1 node2 node3

NODES=("$@")

for NODE in "${NODES[@]}"; do
    echo "=== $NODE 재시작 시작 ==="

    # 1. 로드밸런서에서 노드 제거
    echo "$NODE 로드밸런서에서 제거 중..."
    # curl -X POST http://loadbalancer/api/remove-node -d "node=$NODE"

    # 2. 연결 드레인 대기 (기존 요청 처리 완료 대기)
    echo "기존 연결 드레인 대기 (30초)..."
    sleep 30

    # 3. 서비스 재시작
    echo "$NODE 서비스 재시작 중..."
    ssh "$NODE" "sudo systemctl restart plantpulse-server"

    # 4. 헬스체크 통과 대기
    echo "$NODE 헬스체크 대기 중..."
    until ssh "$NODE" "curl -sf http://localhost/api/v3/ping > /dev/null 2>&1"; do
        sleep 5
    done

    # 5. 로드밸런서에 노드 재등록
    echo "$NODE 로드밸런서에 재등록 중..."
    # curl -X POST http://loadbalancer/api/add-node -d "node=$NODE"

    echo "=== $NODE 재시작 완료 ==="
    echo "다음 노드 진행 전 안정화 대기 (60초)..."
    sleep 60
done

echo "Rolling Restart 완료"
```

> **안내:** Rolling Restart는 웹서버(Tomcat)에 적용됩니다. Cassandra 클러스터의 Rolling Restart는 `nodetool drain` 후 각 노드를 순차적으로 재시작해 주세요.

***

## 상태 확인 <a href="#status-check" id="status-check"></a>

### 프로세스 확인 <a href="#process-check" id="process-check"></a>

```bash
# 전체 PlantPulse 관련 프로세스 확인
ps aux | grep plantpulse

# 특정 서비스 프로세스 확인
ps aux | grep plantpulse-server
ps aux | grep cassandra
ps aux | grep kafka
```

### 포트 확인 <a href="#port-check" id="port-check"></a>

```bash
# 핵심 포트 한 번에 확인
for port in 5432 6379 9042 9092 1883 7800 7400 80 60000; do
    if nc -z 127.0.0.1 $port 2>/dev/null; then
        echo "OK: 포트 $port 열림"
    else
        echo "FAIL: 포트 $port 닫힘"
    fi
done
```

### 헬스체크 API <a href="#healthcheck-api" id="healthcheck-api"></a>

PlantPulse 웹서버는 `/api/v3/ping` 엔드포인트를 통해 헬스체크를 제공합니다.

```bash
# 기본 헬스체크
curl -sf http://localhost/api/v3/ping
# 응답: {"status":"OK","timestamp":1709884800000}

# HTTP 상태 코드만 확인
curl -sf -o /dev/null -w "%{http_code}" http://localhost/api/v3/ping
# 200이면 정상
```

### 로그 확인 <a href="#log-check" id="log-check"></a>

```bash
# PlantPulse 웹서버 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-server/app/plantpulse-server-web/logs/plantpulse.log

# Cassandra 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra/logs/system.log

# Kafka 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/logs/server.log

# 에이전트 로그
tail -f /opt/kopens/plantpulse-platform/plantpulse-plugin/opc-ua/logs/agent.log

# 시작 시 에러 로그만 필터링
grep -i "error\|exception\|fail" /opt/kopens/plantpulse-platform/plantpulse-server/app/plantpulse-server-web/logs/plantpulse.log | tail -20
```

### JVM 상태 확인 <a href="#jvm-check" id="jvm-check"></a>

```bash
# Java 프로세스 목록 확인
jps -lv

# PlantPulse 서버 힙 메모리 확인
jstat -gc $(pgrep -f plantpulse-server) 1000 5

# GC 로그 확인
tail -f /opt/kopens/plantpulse-platform/plantpulse-server/app/plantpulse-server-web/logs/gc.log

# 스레드 덤프 (문제 진단 시)
jstack $(pgrep -f plantpulse-server) > /tmp/thread-dump-$(date +%Y%m%d%H%M%S).txt
```

### systemd 서비스 상태 <a href="#systemd-status" id="systemd-status"></a>

```bash
# 전체 PlantPulse 서비스 상태 확인
systemctl list-units 'plantpulse-*' --all

# 특정 서비스 상세 상태
sudo systemctl status plantpulse-server
sudo systemctl status plantpulse-cassandra
```

***

## 자동 시작 설정 <a href="#auto-start" id="auto-start"></a>

### Linux (systemd enable) <a href="#systemd-enable" id="systemd-enable"></a>

서버 부팅 시 자동으로 서비스가 시작되도록 설정합니다.

```bash
# 자동 시작 활성화
sudo systemctl enable plantpulse-postgresql
sudo systemctl enable plantpulse-redis
sudo systemctl enable plantpulse-cassandra
sudo systemctl enable plantpulse-kafka
sudo systemctl enable plantpulse-mqtt
sudo systemctl enable plantpulse-timeseries
sudo systemctl enable plantpulse-cep
sudo systemctl enable plantpulse-server
sudo systemctl enable plantpulse-agent

# 자동 시작 상태 확인
systemctl list-unit-files 'plantpulse-*' | grep enabled
```

> **안내:** systemd 유닛 파일에 `After=` 지시자를 사용하여 서비스 간 시작 순서 의존성을 설정해 두면, 부팅 시에도 올바른 순서로 시작됩니다. 예시:
>
> ```ini
> [Unit]
> Description=PlantPulse Server
> After=plantpulse-postgresql.service plantpulse-redis.service plantpulse-cassandra.service
> Requires=plantpulse-postgresql.service plantpulse-redis.service
>
> [Service]
> Type=forking
> User=kopens
> ExecStart=/opt/kopens/plantpulse-platform/plantpulse-server/bin/startup.sh
> ExecStop=/opt/kopens/plantpulse-platform/plantpulse-server/bin/shutdown.sh
> Restart=on-failure
> RestartSec=10
>
> [Install]
> WantedBy=multi-user.target
> ```

### Windows 서비스 자동 시작 <a href="#windows-auto-start" id="windows-auto-start"></a>

```powershell
# 서비스 자동 시작 설정
Set-Service -Name "PlantPulse-PostgreSQL" -StartupType Automatic
Set-Service -Name "PlantPulse-Redis" -StartupType Automatic
Set-Service -Name "PlantPulse-Cassandra" -StartupType Automatic
Set-Service -Name "PlantPulse-Kafka" -StartupType Automatic
Set-Service -Name "PlantPulse-Server" -StartupType Automatic
Set-Service -Name "PlantPulse-Agent" -StartupType Automatic

# 자동 시작 상태 확인
Get-Service PlantPulse-* | Select-Object Name, StartType, Status
```

***

## 비상 절차 <a href="#emergency-procedures" id="emergency-procedures"></a>

### 서버 응답 없음 <a href="#server-unresponsive" id="server-unresponsive"></a>

웹서버가 응답하지 않는 경우 다음 순서로 조치해 주세요.

```bash
# 1. 헬스체크 확인
curl -sf --connect-timeout 5 http://localhost/api/v3/ping
echo "HTTP 응답 코드: $?"

# 2. 프로세스 상태 확인
ps aux | grep plantpulse-server

# 3. 포트 점유 확인
ss -tlnp | grep ':80'

# 4. 스레드 덤프 (행(hang) 의심 시)
jstack $(pgrep -f plantpulse-server) > /tmp/thread-dump-$(date +%Y%m%d%H%M%S).txt

# 5. GC 상태 확인
jstat -gcutil $(pgrep -f plantpulse-server) 1000 3

# 6. 웹서버만 재시작 (다른 서비스는 유지)
sudo systemctl restart plantpulse-server

# 7. 재시작 후 헬스체크 확인
sleep 30
curl -sf http://localhost/api/v3/ping
```

### OOM (Out Of Memory) 발생 <a href="#oom" id="oom"></a>

```bash
# 1. OOM 발생 확인
dmesg | grep -i "out of memory\|oom"

# 2. 힙 덤프 확인 (자동 생성된 경우)
ls -la /opt/kopens/plantpulse-platform/plantpulse-server/app/plantpulse-server-web/logs/heapdump*

# 3. 메모리 사용량 확인
free -h
ps aux --sort=-%mem | head -10

# 4. JVM 힙 크기 조정 (catalina.sh 또는 setenv.sh)
# JAVA_OPTS="-Xms4g -Xmx8g -XX:+HeapDumpOnOutOfMemoryError"
# 설정 변경 후 재시작
sudo systemctl restart plantpulse-server
```

### DB 연결 실패 <a href="#db-connection-failure" id="db-connection-failure"></a>

```bash
# 1. PostgreSQL 연결 확인
psql -h 127.0.0.1 -U plantpulse -d plantpulse -c "SELECT 1"

# 2. Cassandra 연결 확인
cqlsh 127.0.0.1 -e "DESCRIBE KEYSPACES"

# 3. Redis 연결 확인
redis-cli -h 127.0.0.1 ping

# 4. 연결 수 확인 (PostgreSQL)
psql -h 127.0.0.1 -U plantpulse -d plantpulse -c "SELECT count(*) FROM pg_stat_activity"

# 5. DB 서비스 재시작 (필요 시)
# 주의: DB 재시작 전 반드시 웹서버와 에이전트를 먼저 종료해 주세요
sudo systemctl stop plantpulse-agent
sudo systemctl stop plantpulse-server
sudo systemctl restart plantpulse-postgresql
sudo systemctl start plantpulse-server
sudo systemctl start plantpulse-agent
```

***

## 운영 체크리스트 <a href="#operation-checklist" id="operation-checklist"></a>

### 일일 점검 <a href="#daily-check" id="daily-check"></a>

| 점검 항목        | 명령어 / 확인 방법                             | 정상 기준                   |
| ------------ | --------------------------------------- | ----------------------- |
| 전체 서비스 상태    | `systemctl list-units 'plantpulse-*'`   | 모든 서비스 active (running) |
| 핵심 포트 확인     | 포트 확인 스크립트 (위 참조)                       | 모든 포트 열림                |
| 헬스체크 API     | `curl http://localhost/api/v3/ping`     | HTTP 200, status OK     |
| 디스크 사용량      | `df -h`                                 | 사용률 80% 미만              |
| 메모리 사용량      | `free -h`                               | 사용률 85% 미만              |
| 에러 로그        | `grep ERROR plantpulse.log \| tail -20` | 반복적 에러 없음               |
| Cassandra 상태 | `nodetool status`                       | 모든 노드 UN (Up/Normal)    |

### 주간 점검 <a href="#weekly-check" id="weekly-check"></a>

| 점검 항목                | 명령어 / 확인 방법                           | 정상 기준            |
| -------------------- | ------------------------------------- | ---------------- |
| Cassandra Compaction | `nodetool compactionstats`            | Pending 작업 과다 아님 |
| PostgreSQL 통계        | `pg_stat_activity` 조회                 | idle 연결 과다 아님    |
| Kafka Consumer Lag   | `kafka-consumer-groups.sh --describe` | 지연 메시지 수 정상 범위   |
| JVM GC 통계            | `jstat -gcutil`                       | Full GC 빈도 낮음    |
| 백업 확인                | 최근 백업 파일 확인                           | 정상 백업 존재         |
| 로그 파일 용량             | `du -sh */logs/`                      | 비정상적 증가 없음       |
| 보안 업데이트              | OS 패키지 업데이트 확인                        | 알려진 취약점 없음       |
