> 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/modules/storage.md).

# storage (스토리지)

## 역할

PlantPulse 의 모든 데이터를 영구 저장하는 계층입니다. **데이터 종류에 따라 4개의 전문화된 엔진**을 단일 모듈로 묶어 운영합니다.

| 항목     | 값                                                     |
| ------ | ----------------------------------------------------- |
| 모듈명    | `plantpulse-storage`                                  |
| 설치 경로  | `/opt/kopens/plantpulse-platform/plantpulse-storage/` |
| 데이터 위치 | `/data1/pp-data/` (`PP_DATA_DIR`)                     |
| 백업 위치  | `/data1/pp-backup/` (`PP_BACKUP_DIR`)                 |

## 구성

```mermaid
graph TB
  subgraph STG["plantpulse-storage"]
    subgraph DB["관계형 / 시계열"]
      CASS[Cassandra :9042<br/>시계열 데이터]
      PG[PostgreSQL :5432<br/>메타데이터]
    end
    subgraph CACHE["캐시"]
      VK[Valkey :6379<br/>인메모리 캐시]
    end
    subgraph OBJ["오브젝트"]
      MN[MinIO :9000/9001<br/>S3 호환 스토리지]
    end
    subgraph TOOLS["운영 도구"]
      REAPER[Cassandra Reaper<br/>자동 복구]
    end
  end

  APP[애플리케이션] --> CASS
  APP --> PG
  APP --> VK
  APP --> MN
  REAPER -.-> CASS
```

## 디렉토리 구조

```
plantpulse-storage/
├── cache/
│   └── valkey/                  # Valkey 7.x (Redis 호환)
│       ├── bin/
│       ├── conf/valkey.conf
│       ├── logs/system.log
│       └── data/
├── db/
│   ├── cassandra/               # Cassandra 5.0
│   │   ├── bin/                 # cqlsh, nodetool, cassandra
│   │   ├── conf/cassandra.yaml
│   │   ├── conf/jvm-server.options
│   │   ├── logs/system.log
│   │   ├── data/                # SSTable, commitlog
│   │   ├── lib/
│   │   └── tools/
│   └── postgres/                # PostgreSQL 16
│       ├── bin/                 # psql, pg_ctl, initdb
│       ├── conf/postgresql.conf
│       ├── conf/pg_hba.conf
│       ├── logs/
│       ├── import/
│       └── sql/
├── object/
│   ├── minio/                   # MinIO (메인 오브젝트 스토리지)
│   │   ├── bin/
│   │   ├── conf/
│   │   ├── logs/
│   │   └── data/                # 버킷 데이터
│   ├── rustfs/                  # 분산 파일 시스템 (옵션)
│   └── weedfs/                  # SeaweedFS (옵션)
└── tools/
    └── reaper/                  # Cassandra 자동 복구
        ├── bin/
        ├── resource/
        ├── server/
        └── log/
```

## 각 엔진 상세

### Cassandra 5.0 — 시계열 데이터

산업 현장에서 들어오는 시계열 데이터를 저장하는 분산 NoSQL DB. 수십억 행 규모로 확장됩니다.

| 항목    | 값                                          |
| ----- | ------------------------------------------ |
| 버전    | 5.0                                        |
| 포트    | 9042 (CQL), 7000/7001 (Gossip), 7199 (JMX) |
| 키스페이스 | `pp` (기본, `PP_KEYSPACE`)                   |
| 인증    | `PasswordAuthenticator`                    |
| 압축    | ZStandard (`node-train-zstd.sh` 로 학습 가능)   |

#### 주요 테이블

| 테이블              | 용도                  |
| ---------------- | ------------------- |
| `tm_tag_point`   | 태그 시계열 데이터 (밀리초 단위) |
| `tm_tag_alarm`   | 태그 알람 이력            |
| `tm_asset_data`  | 에셋 집계 데이터           |
| `tm_asset_alarm` | 에셋 알람 이력            |
| `tm_asset_event` | 에셋 이벤트              |

#### 운영 명령

`plantpulse-startup/` 의 `node-*.sh` 스크립트를 사용합니다.

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

./node-status.sh             # 클러스터 상태 (nodetool status)
./node-info.sh               # 노드 상세 정보
./node-cql.sh                # CQL 셸 접속 (cqlsh)
./node-compactionstats.sh    # 컴팩션 진행 상태
./node-compact.sh            # 수동 컴팩션
./node-cleanup.sh            # 노드 정리 (불필요 데이터 삭제)
./node-flush.sh              # Memtable → SSTable 플러시
./node-drain.sh              # 노드 Drain (안전 종료 준비)
./node-repair.sh             # 데이터 복구 (잉여 노드 일관성)
./node-repair-table.sh       # 특정 테이블만 복구
./node-tpstats.sh            # 스레드풀 통계
./node-disk.sh               # 디스크 사용량
./node-table-stats.sh        # 테이블별 통계
./node-sstable-size.sh       # SSTable 크기
./node-init-cms.sh           # CMS 초기화
./node-train-zstd.sh         # ZStandard 압축 학습
```

#### Cassandra 튜닝 포인트

| 항목                               | 위치                        | 권장                             |
| -------------------------------- | ------------------------- | ------------------------------ |
| 힙 크기                             | `conf/jvm-server.options` | 호스트 메모리의 1/4 (최대 32GB)         |
| GC                               | `conf/jvm-server.options` | G1GC 또는 ZGC                    |
| commitlog\_disk\_failure\_policy | `conf/cassandra.yaml`     | `die` (강한 보호)                  |
| compaction throughput            | `conf/cassandra.yaml`     | 128 MB/s (NVMe), 16 MB/s (HDD) |
| concurrent\_compactors           | `conf/cassandra.yaml`     | `min(코어 수, 8)`                 |
| keycache                         | `conf/cassandra.yaml`     | 200\~500MB                     |

#### Cassandra Reaper

자동 repair 를 관리하는 도구. 정기적으로 incremental repair 를 수행하여 일관성을 유지합니다.

```bash
# Reaper 웹 UI (포트: tools/reaper/resource/cassandra-reaper.yaml 참고)
# 기본: http://[HOST]:8085/webui
```

### PostgreSQL 16 — 메타데이터

사용자, 사이트, 자산 모델, 태그 정의 등 정형 메타데이터를 저장합니다.

| 항목     | 값                               |
| ------ | ------------------------------- |
| 버전     | 16                              |
| 포트     | 5432                            |
| 데이터베이스 | `pp` (기본, `PP_DB_NAME`)         |
| 사용자    | `plantpulse` (기본, `PP_PG_USER`) |
| 인증     | scram-sha-256                   |

#### 주요 스키마

| 스키마        | 용도                        |
| ---------- | ------------------------- |
| `public`   | 메인 메타데이터                  |
| `quartz`   | 스케줄러 (Quartz JDBC store)  |
| `temporal` | Temporal 워크플로우 (별도 DB 권장) |
| `kestra`   | Kestra 워크플로우 (별도 DB 권장)   |
| `hive`     | Hive Metastore            |

#### 운영 명령

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

./node-psql.sh           # psql 셸 접속

# 직접 접속
PGPASSWORD=$PP_PG_PASSWORD psql -h $PP_HOST_IP -U $PP_PG_USER -d pp
```

#### PostgreSQL 튜닝 포인트

`conf/postgresql.conf` 주요 항목:

| 항목                     | 권장                     |
| ---------------------- | ---------------------- |
| `shared_buffers`       | 호스트 메모리의 25%           |
| `effective_cache_size` | 호스트 메모리의 50\~75%       |
| `work_mem`             | 16\~64MB               |
| `maintenance_work_mem` | 512MB \~ 2GB           |
| `max_connections`      | 200 (대규모: 500)         |
| `wal_compression`      | `on`                   |
| `synchronous_commit`   | `on` (안전) / `off` (속도) |
| `random_page_cost`     | 1.1 (SSD)              |

### Valkey 7 — 인메모리 캐시

Redis 호환 인메모리 캐시. 실시간 데이터 버퍼링, 세션 관리, Pub/Sub 에 사용됩니다.

| 항목  | 값                       |
| --- | ----------------------- |
| 버전  | Valkey 7.x (Redis 7 호환) |
| 포트  | 6379                    |
| 인증  | `requirepass` 활성화       |
| 영속화 | RDB + AOF               |

#### 운영

```bash
# 컨테이너 / 호스트에서
redis-cli -h $PP_HOST_IP -p $PP_REDIS_PORT -a $PP_REDIS_PASSWORD

# 주요 명령
> PING                       # 연결 확인
> INFO memory                # 메모리 사용량
> INFO clients               # 연결 클라이언트
> SLOWLOG GET 10             # 슬로우 로그
> CONFIG GET maxmemory       # 메모리 한계
> CONFIG SET maxmemory 16gb  # 메모리 한계 변경
```

### MinIO — 오브젝트 스토리지

S3 호환 분산 오브젝트 스토리지. Iceberg 데이터, 백업, 첨부 파일을 저장합니다.

| 항목    | 값                                |
| ----- | -------------------------------- |
| 포트    | 9000 (API), 9001 (Console)       |
| 사용자   | `minio` / `minio123!` (기본)       |
| 기본 버킷 | `plantpulse` (`PP_MINIO_BUCKET`) |
| 콘솔    | `http://[HOST]:9001/`            |

#### 주요 버킷

| 버킷                      | 용도          |
| ----------------------- | ----------- |
| `plantpulse`            | 메인 데이터      |
| `plantpulse-iceberg`    | Iceberg 테이블 |
| `plantpulse-backup`     | 백업          |
| `plantpulse-attachment` | 첨부파일        |

#### 운영

```bash
# mc 클라이언트 (MinIO Client)
mc alias set local http://127.0.0.1:9000 minio minio123!
mc ls local/
mc admin info local
mc admin trace local            # 실시간 트래픽
```

## 통합 운영 명령

### 시작 / 정지 / 재시작

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

./restart-storage.sh    # 스토리지 모듈 전체 재시작
```

> **주의**: 스토리지를 재시작하면 의존하는 모든 애플리케이션 (server / batch / cep / data-gateway / monitor 등) 도 함께 재시작해야 합니다. 가능하면 `./restart.sh` 로 전체 재시작을 권장합니다.

### 상태 점검

```bash
./status.sh                  # 포트 기반 RUNNING / STOPPED 확인
./node-status.sh             # Cassandra 클러스터
./node-disk.sh               # 디스크 사용량
```

## 백업 / 복구

자세한 절차는 [백업 및 복구](/plantpulse-platform/admin/backup-recovery.md) 페이지를 참고해 주세요. 핵심 도구:

| 엔진         | 도구          | 백업 방식                             |
| ---------- | ----------- | --------------------------------- |
| PostgreSQL | pgBackRest  | Full / Differential / Incremental |
| Cassandra  | Medusa      | Snapshot 기반                       |
| 파일 / 설정    | Restic      | 증분 백업                             |
| MinIO      | `mc mirror` | 외부 S3 복제                          |

플랫폼은 `plantpulse-backup` 모듈에 통합 백업 스크립트를 제공합니다.

```bash
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
./backup.sh --postgres        # PG Differential
./backup.sh --postgres full   # PG Full
./backup.sh --cassandra       # Cassandra
./backup.sh --purge           # 보관 정책 정리
./backup.sh --cron-install    # 크론 등록
```

## 자주 발생하는 문제

| 증상                                | 원인                     | 조치                                          |
| --------------------------------- | ---------------------- | ------------------------------------------- |
| Cassandra `WriteTimeout`          | 디스크 I/O 포화             | `node-compactionstats.sh` 확인, throughput 조정 |
| Cassandra 노드 down                 | 네트워크 / 디스크 / OOM       | `logs/system.log` 의 GC pause 확인             |
| PostgreSQL `Too many connections` | 연결 풀 누수                | `max_connections` 상향 + 애플리케이션 풀 점검          |
| Valkey 메모리 부족                     | `maxmemory-policy` 미설정 | `allkeys-lru` 또는 `volatile-lru` 설정          |
| MinIO 디스크 가득                      | Iceberg / 백업 누적        | `mc admin info` + 라이프사이클 정책 적용              |
| 스토리지 재시작 후 응답 지연                  | Cassandra warmup       | 정상 (3\~5분 대기)                               |

## 디스크 레이아웃 권장

```
/data1/                                  # 데이터 디스크 (NVMe SSD)
├── pp-data/
│   ├── cassandra/data/                   # SSTable (대용량)
│   ├── cassandra/commitlog/              # commitlog (sync I/O)
│   ├── cassandra/saved_caches/
│   ├── postgres/                          # PostgreSQL 데이터
│   ├── minio/                             # 오브젝트 데이터
│   └── valkey/                            # RDB / AOF
├── pp-temp/                                # 임시 처리
└── pp-backup/                              # 백업
    ├── pgbackrest/
    ├── cassandra-medusa/
    └── docker-volume/
```

> **고급**: Cassandra commitlog 와 data 를 별도 디스크 (또는 별도 LV) 로 분리하면 쓰기 처리량이 크게 향상됩니다. 운영 환경에서는 `commitlog_directory` 를 별도 디스크에 두는 것을 권장합니다.

## 관련 문서

* [모듈 인덱스](/plantpulse-platform/admin/modules.md)
* [백업 및 복구](/plantpulse-platform/admin/backup-recovery.md)
* [성능 튜닝](/plantpulse-platform/admin/performance-tuning.md)
* [문제 해결](/plantpulse-platform/admin/troubleshooting.md)
* [데이터베이스 스키마](/plantpulse-platform/developer/database-schema.md)
