> 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/performance-tuning.md).

# 성능 튜닝

## 개요

PlantPulse 의 성능은 **수집 → 처리 → 저장** 의 각 계층 병목을 차례로 제거해야 향상됩니다. 무조건 모든 값을 키우는 것이 아니라, 모니터링 지표를 보고 **병목 지점만** 조정하는 것이 핵심입니다.

```mermaid
flowchart LR
  A[1. 측정<br/>monitor / status / ops-check] --> B[2. 병목 식별]
  B --> C{어디서 막힘?}
  C -->|입력 지연| D[Kafka / MQTT 튜닝]
  C -->|처리 적체| E[엔진 파이프라인 튜닝]
  C -->|쓰기 지연| F[Cassandra / PG 튜닝]
  C -->|메모리 부족| G[JVM 힙 / GC 튜닝]
  C -->|네트워크| H[OS 커널 / 네트워크 튜닝]
  D --> I[변경 적용]
  E --> I
  F --> I
  G --> I
  H --> I
  I --> J[재측정 / 비교]
  J --> A
```

> **튜닝 원칙 3가지**
>
> 1. **한 번에 하나만**: 동시에 여러 변수를 바꾸면 어떤 변경이 효과를 냈는지 알 수 없습니다.
> 2. **운영 데이터 기반**: stage 환경 + 실제 트래픽 재현 후 변경.
> 3. **기록 남기기**: 변경한 값, 변경 전후 지표를 GitOps / 운영 wiki 에 남기세요.

## 운영 환경별 권장 출발점

| 환경  | CPU      | 메모리     | 디스크  | 권장 PIPELINE\_THREADS | 권장 PIPELINE\_RATELIMIT |
| --- | -------- | ------- | ---- | -------------------- | ---------------------- |
| 개발  | 16 vCPU  | 64 GB   | SSD  | 16                   | 10,000 MPS             |
| 표준  | 32 vCPU  | 128 GB  | NVMe | 36                   | 40,000 MPS             |
| 대규모 | 48+ vCPU | 200+ GB | NVMe | 64                   | 100,000 MPS            |

## env.sh 기반 핵심 튜닝 변수

운영 환경에서 가장 자주 조정하는 변수는 `plantpulse-startup/env.sh` 한 곳에서 관리됩니다.

| 변수                          | 기본              | 영향                    |
| --------------------------- | --------------- | --------------------- |
| `PP_CLUSTER_CORES`          | 30              | Spark / 분석 코어 할당      |
| `PP_CLUSTER_MEMORY_BY_CORE` | 2G              | Spark executor 메모리/코어 |
| `PP_LANG` / `PP_TZ`         | ko / Asia/Seoul | JVM locale / timezone |
| `JAVA_TOOL_OPTIONS`         | 자동 생성           | 모든 자식 JVM 에 자동 적용     |

상세 변수는 [프로퍼티 레퍼런스](/plantpulse-platform/admin/properties-reference.md) 의 env.sh 변수 인덱스 참고.

## 측정 도구

튜닝 전후를 비교할 수 있는 도구:

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

./status.sh                            # 모듈별 CPU / 메모리(PSS) 요약
./ops-check.sh                         # 헬스 + critical log
./memory-check.sh                      # 모듈별 메모리 상세
./memory-rank.sh                       # 메모리 순위
./node-tpstats.sh                      # Cassandra 스레드풀
./node-compactionstats.sh              # Cassandra 컴팩션
./node-table-stats.sh                  # 테이블별 통계
./node-proxyhistograms.sh              # Cassandra 지연 히스토그램

# Kafka consumer lag
./node-topic.sh

# JVM Heap / GC (컨테이너 진입 후)
./platform-bash.sh
jcmd <pid> GC.heap_info
jcmd <pid> GC.heap_dump /tmp/heap.hprof
```

외부 모니터링 (Grafana / Prometheus) 은 [시스템 모니터링](/plantpulse-platform/admin/monitoring.md) 페이지 참고.

> **안내:** 성능 튜닝은 서버 사양, 데이터 규모, 사용 패턴에 따라 최적값이 달라질 수 있습니다. 아래의 권장 설정을 기준으로 시작하시고, 모니터링 결과를 확인하면서 점진적으로 조정해 나가시는 것을 권장합니다.

## 엔진 파이프라인 튜닝 <a href="#pipeline-tuning" id="pipeline-tuning"></a>

설정 파일: `plantpulse-server/app/plantpulse-server-web/WEB-INF/classes/engine.properties`

> **안내:** 엔진 파이프라인은 센서에서 수집된 데이터가 처리되는 핵심 경로입니다. 이 설정을 통해 데이터의 처리 속도와 용량을 조절할 수 있습니다.

### 파이프라인 핵심 파라미터

| 파라미터                             | 기본값       | 설명                      | 튜닝 가이드                 |
| -------------------------------- | --------- | ----------------------- | ---------------------- |
| `engine.pipeline.threads`        | `36`      | 파이프라인 워커 스레드 수          | CPU 코어 수의 2\~4배를 권장합니다 |
| `engine.pipeline.ratelimit`      | `40000`   | 초당 최대 처리 메시지 수 (MPS)    | 서버 사양에 맞게 조정해 주세요      |
| `engine.pipeline.queue.size`     | `1200000` | 파이프라인 큐 최대 크기           | 메모리 여유분에 맞게 조정해 주세요    |
| `engine.pipeline.queue.o3.delay` | `50`      | Out-of-Order 지연 처리 (ms) | 네트워크 지연에 따라 조정해 주세요    |
| `engine.pipeline.task.mode`      | `SINGLE`  | 파이프라인 태스크 모드            | `SINGLE` 또는 `MULTI`    |
| `engine.async.parallelism`       | `256`     | 비동기 병렬 처리 수             | CPU 코어의 8\~16배를 권장합니다  |

### 스트리밍 설정

| 파라미터                                               | 기본값          | 설명                |
| -------------------------------------------------- | ------------ | ----------------- |
| `engine.stream.processor`                          | `DIRECT`     | 스트림 처리 모드         |
| `engine.streaming.messaging.warning.ms`            | `5000`       | 메시지 지연 경고 기준 (ms) |
| `engine.streaming.messaging.timeout.ms`            | `10000`      | 메시지 타임아웃 (ms)     |
| `engine.streaming.messaging.timeout.store.type`    | `FILE_QUEUE` | 타임아웃 메시지 저장 방식    |
| `engine.streaming.messaging.timeout.recovery.type` | `DB`         | 타임아웃 복구 방식        |

### 작업 스레드

| 파라미터                      | 기본값 | 설명           |
| ------------------------- | --- | ------------ |
| `engine.job.thread.asset` | `8` | 에셋 작업 스레드 수  |
| `engine.job.thread.point` | `8` | 포인트 작업 스레드 수 |

### 사양별 권장 설정

아래 표는 서버 사양에 따른 권장 설정값입니다. 운영 환경의 사양에 맞는 열을 참고하여 설정해 주세요.

| 항목                    | 소규모 (8코어/64GB) | 중규모 (16코어/128GB) | 대규모 (32코어/256GB) |
| --------------------- | -------------- | ---------------- | ---------------- |
| `pipeline.threads`    | 16             | 36               | 64               |
| `pipeline.ratelimit`  | 10,000         | 40,000           | 100,000          |
| `pipeline.queue.size` | 300,000        | 1,200,000        | 3,000,000        |
| `async.parallelism`   | 64             | 256              | 512              |

***

## Cassandra 튜닝 <a href="#cassandra-tuning" id="cassandra-tuning"></a>

설정 파일: `plantpulse-storage/db/cassandra/conf/cassandra.yaml`

> **안내:** Cassandra는 시계열 데이터를 저장하는 핵심 데이터베이스입니다. 데이터 규모가 커질수록 Cassandra 튜닝이 전체 성능에 큰 영향을 미치므로, 운영 환경에 맞게 조정해 주시는 것을 권장합니다.

### 메모리 설정

| 파라미터                       | 기본값               | 설명                    |
| -------------------------- | ----------------- | --------------------- |
| `memtable_heap_space`      | `2GiB`            | Memtable 힙 메모리        |
| `memtable_offheap_space`   | `2GiB`            | Memtable Off-Heap 메모리 |
| `memtable_allocation_type` | `offheap_objects` | 메모리 할당 타입             |
| `memtable_flush_writers`   | `8`               | Memtable 플러시 스레드 수    |

### 동시성 설정

| 파라미터                        | 기본값   | 설명         | 튜닝 가이드                           |
| --------------------------- | ----- | ---------- | -------------------------------- |
| `concurrent_reads`          | `256` | 동시 읽기 스레드  | 디스크 수 x 16을 권장합니다                |
| `concurrent_writes`         | `256` | 동시 쓰기 스레드  | CPU 코어 x 8을 권장합니다                |
| `concurrent_counter_writes` | `256` | 동시 카운터 쓰기  | concurrent\_writes와 동일하게 설정해 주세요 |
| `concurrent_compactors`     | `8`   | 동시 컴팩션 스레드 | CPU 코어 수의 1/4을 권장합니다             |

### 커밋로그

| 파라미터                     | 기본값        | 설명         |
| ------------------------ | ---------- | ---------- |
| `commitlog_sync`         | `periodic` | 동기 방식      |
| `commitlog_sync_period`  | `10000ms`  | 동기 주기      |
| `commitlog_segment_size` | `320MiB`   | 세그먼트 크기    |
| `commitlog_total_space`  | `32GiB`    | 전체 커밋로그 공간 |

### 타임아웃

| 파라미터                            | 기본값        | 설명            |
| ------------------------------- | ---------- | ------------- |
| `read_request_timeout`          | `10000ms`  | 읽기 타임아웃       |
| `write_request_timeout`         | `60000ms`  | 쓰기 타임아웃       |
| `counter_write_request_timeout` | `10000ms`  | 카운터 쓰기 타임아웃   |
| `cas_contention_timeout`        | `1000ms`   | CAS 경합 타임아웃   |
| `truncate_request_timeout`      | `600000ms` | Truncate 타임아웃 |

### 컴팩션 전략

PlantPulse는 시계열 데이터 특성에 맞는 \*\*UCS(Unified Compaction Strategy)\*\*를 사용합니다.

> **안내:** 컴팩션(Compaction)은 Cassandra가 디스크에 저장된 데이터 파일(SSTable)을 정리하고 병합하는 작업입니다. 적절한 컴팩션 전략을 사용하면 디스크 공간을 절약하고 읽기 성능을 향상시킬 수 있습니다.

`storage.properties` 설정:

| 파라미터                                                            | 기본값      | 설명                       |
| --------------------------------------------------------------- | -------- | ------------------------ |
| `storage.table.compaction.strategy`                             | `UCS`    | 컴팩션 전략 (`UCS` 또는 `TWCS`) |
| `storage.table.compaction.strategy.ucs.scailing_parameter`      | `T8`     | 스케일링 파라미터                |
| `storage.table.compaction.strategy.ucs.min_sstable_size`        | `128MiB` | 최소 SSTable 크기            |
| `storage.table.compaction.strategy.ucs.target_sstable_size`     | `512MiB` | 목표 SSTable 크기            |
| `storage.table.compaction.strategy.ucs.base_shard_count`        | `8`      | 베이스 샤드 수                 |
| `storage.table.compaction.strategy.ucs.max_sstables_to_compact` | `6`      | 최대 컴팩션 SSTable 수         |

### 압축

ZStandard 딕셔너리 압축을 사용합니다:

| 파라미터                             | 기본값                        | 설명                                       |
| -------------------------------- | -------------------------- | ---------------------------------------- |
| `storage.compression.zstd.type`  | `ZstdDictionaryCompressor` | 압축 방식                                    |
| `storage.compression.zstd.level` | `3`                        | 압축 레벨 (1\~22, 높을수록 압축률은 올라가지만 속도는 느려집니다) |

### TTL (데이터 보존 기간)

`storage.properties`에서 테이블별 TTL을 설정합니다. TTL이 지나면 해당 데이터는 자동으로 삭제되므로, 데이터 보존 요구사항에 맞게 설정해 주세요.

| 파라미터                                | 기본값       | 설명            |
| ----------------------------------- | --------- | ------------- |
| `storage.tag.point.ttl`             | `62` (일)  | 태그 포인트 원본 데이터 |
| `storage.tag.point.map.ttl`         | `1` (일)   | 태그 포인트 맵      |
| `storage.tag.point.sampling.ttl`    | `93` (일)  | 샘플링 데이터       |
| `storage.tag.point.snapshot.ttl`    | `93` (일)  | 스냅샷 데이터       |
| `storage.tag.point.aggregation.ttl` | `93` (일)  | 집계 데이터        |
| `storage.tag.point.archive.ttl`     | `365` (일) | 아카이브 데이터      |
| `storage.tag.blob.ttl`              | `93` (일)  | BLOB 데이터      |
| `storage.asset.data.ttl`            | `10` (일)  | 에셋 데이터        |
| `storage.asset.data.sampling.ttl`   | `31` (일)  | 에셋 샘플링 데이터    |

### Cassandra 성능 점검 명령어

아래 명령어를 사용하여 Cassandra의 성능 상태를 점검하실 수 있습니다:

```bash
# 컴팩션 상태 확인
/opt/kopens/plantpulse-platform/plantpulse-startup/node-compactionstats.sh

# 테이블별 통계 확인
/opt/kopens/plantpulse-platform/plantpulse-startup/node-table-stats.sh

# 테이블 히스토그램 (읽기/쓰기 지연)
/opt/kopens/plantpulse-platform/plantpulse-startup/node-table-histograms.sh

# SSTable 크기 확인
/opt/kopens/plantpulse-platform/plantpulse-startup/node-sstable-size.sh

# 스레드풀 통계
/opt/kopens/plantpulse-platform/plantpulse-startup/node-tpstats.sh

# DB 성능 테스트
/opt/kopens/plantpulse-platform/plantpulse-db-performance/bin/run.sh
```

***

## Spark 튜닝 <a href="#spark-tuning" id="spark-tuning"></a>

설정 파일: `plantpulse-analytics/spark/conf/spark-defaults.conf`

> **안내:** Apache Spark는 대용량 데이터 분석을 위한 분산 처리 엔진입니다. 분석 작업의 속도와 안정성을 높이기 위해 아래 설정을 참고해 주세요.

### 리소스 할당

| 파라미터                            | 기본값  | 설명                |
| ------------------------------- | ---- | ----------------- |
| `spark.cores.max`               | `16` | Spark 최대 사용 코어    |
| `spark.driver.cores`            | `2`  | 드라이버 코어 수         |
| `spark.driver.memory`           | `4g` | 드라이버 메모리          |
| `spark.executor.cores`          | `1`  | Executor 코어 수     |
| `spark.executor.memory`         | `2G` | Executor 메모리      |
| `spark.executor.memoryOverhead` | `2g` | Executor 오버헤드 메모리 |

### 동적 할당

| 파라미터                                          | 기본값    | 설명                    |
| --------------------------------------------- | ------ | --------------------- |
| `spark.dynamicAllocation.enabled`             | `true` | 동적 Executor 할당        |
| `spark.dynamicAllocation.minExecutors`        | `2`    | 최소 Executor 수         |
| `spark.dynamicAllocation.maxExecutors`        | `16`   | 최대 Executor 수         |
| `spark.dynamicAllocation.executorIdleTimeout` | `30`   | 유휴 Executor 해제 시간 (초) |

### 셔플 및 병렬도

| 파라미터                                            | 기본값    | 설명                       |
| ----------------------------------------------- | ------ | ------------------------ |
| `spark.default.parallelism`                     | `64`   | 기본 병렬도                   |
| `spark.sql.shuffle.partitions`                  | `128`  | SQL 셔플 파티션 수             |
| `spark.sql.adaptive.enabled`                    | `true` | Adaptive Query Execution |
| `spark.sql.adaptive.coalescePartitions.enabled` | `true` | 파티션 자동 병합                |

### JVM 설정

Spark 드라이버/Executor 모두 **ZGC**를 사용합니다:

```
-XX:+UseZGC
-XX:+AlwaysPreTouch
-XX:+UseTLAB
-XX:+ResizeTLAB
-XX:+DisableExplicitGC
```

### S3 (MinIO) 연동 설정

| 파라미터                                     | 기본값     | 설명         |
| ---------------------------------------- | ------- | ---------- |
| `spark.hadoop.fs.s3a.connection.maximum` | `400`   | 최대 S3 연결 수 |
| `spark.hadoop.fs.s3a.threads.max`        | `128`   | 최대 S3 스레드  |
| `spark.hadoop.fs.s3a.max.total.tasks`    | `1024`  | 최대 비동기 작업  |
| `spark.hadoop.fs.s3a.fast.upload`        | `true`  | 빠른 업로드 활성화 |
| `spark.hadoop.fs.s3a.fast.upload.buffer` | `disk`  | 업로드 버퍼 타입  |
| `spark.hadoop.fs.s3a.block.size`         | `128MB` | S3 블록 크기   |

### Iceberg 설정

| 파라미터                                             | 기본값     | 설명            |
| ------------------------------------------------ | ------- | ------------- |
| `spark.sql.iceberg.write.target-file-size-bytes` | `256MB` | 대상 파일 크기      |
| `spark.sql.iceberg.column-stats.enabled`         | `true`  | 컬럼 통계 활성화     |
| `spark.sql.iceberg.vectorization.enabled`        | `true`  | 벡터화 읽기 활성화    |
| `spark.sql.iceberg.manifest.merge.enabled`       | `true`  | 매니페스트 병합      |
| `spark.sql.parquet.compression.codec`            | `zstd`  | Parquet 압축 코덱 |

***

## Kafka 튜닝 <a href="#kafka-tuning" id="kafka-tuning"></a>

설정 파일: `plantpulse-messaging/kafka/config/server.properties`

> **안내:** Kafka는 센서 데이터를 실시간으로 전달하는 메시지 브로커입니다. 데이터 양이 많아지면 Kafka 설정을 조정하여 처리 성능을 높일 수 있습니다.

### 핵심 설정

| 파라미터                          | 기본값          | 설명               |
| ----------------------------- | ------------ | ---------------- |
| `num.network.threads`         | `3`          | 네트워크 처리 스레드      |
| `num.io.threads`              | `8`          | I/O 처리 스레드       |
| `socket.send.buffer.bytes`    | `102400`     | 소켓 전송 버퍼         |
| `socket.receive.buffer.bytes` | `102400`     | 소켓 수신 버퍼         |
| `socket.request.max.bytes`    | `104857600`  | 최대 요청 크기 (100MB) |
| `num.partitions`              | `1`          | 기본 파티션 수         |
| `log.retention.hours`         | `168`        | 로그 보존 기간 (7일)    |
| `log.segment.bytes`           | `1073741824` | 로그 세그먼트 크기 (1GB) |

### 대용량 처리 튜닝

대량의 IoT 데이터를 처리하실 경우, 아래 설정을 참고하여 조정해 주세요:

```properties
# 파티션 수 증가 (메시지 병렬 처리)
num.partitions=4

# I/O 스레드 증가
num.io.threads=16

# 네트워크 스레드 증가
num.network.threads=8

# 소켓 버퍼 증가
socket.send.buffer.bytes=1048576
socket.receive.buffer.bytes=1048576
```

***

## 메시징 설정 <a href="#messaging-config" id="messaging-config"></a>

설정 파일: `plantpulse-server/app/plantpulse-server-web/WEB-INF/classes/mq.properties`

### Kafka DDS 토픽

| 파라미터                                      | 기본값                       | 용도       |
| ----------------------------------------- | ------------------------- | -------- |
| `mq.dds.kafka.topic.tag.point`            | `pp-tag-point`            | 태그 포인트 값 |
| `mq.dds.kafka.topic.tag.alarm`            | `pp-tag-alarm`            | 태그 알람    |
| `mq.dds.kafka.topic.asset.data`           | `pp-asset-data`           | 에셋 데이터   |
| `mq.dds.kafka.topic.asset.alarm`          | `pp-asset-alarm`          | 에셋 알람    |
| `mq.dds.kafka.topic.asset.event`          | `pp-asset-event`          | 에셋 이벤트   |
| `mq.dds.kafka.topic.asset.aggregation`    | `pp-asset-aggregation`    | 에셋 집계    |
| `mq.dds.kafka.topic.domain.changed.event` | `pp-domain-changed-event` | 메타데이터 변경 |

### MQTT DDS 토픽

| 파라미터                              | 기본값                        | 용도        |
| --------------------------------- | -------------------------- | --------- |
| `mq.dds.mqtt.topic.tag.point`     | `tag/point/{tag_id}`       | 태그별 포인트 값 |
| `mq.dds.mqtt.topic.tag.alarm`     | `tag/alarm/{tag_id}`       | 태그별 알람    |
| `mq.dds.mqtt.topic.asset.data`    | `asset/data/{asset_id}`    | 에셋별 데이터   |
| `mq.dds.mqtt.topic.asset.command` | `asset/command/{asset_id}` | 에셋 제어 명령  |

***

## WebSocket 설정 <a href="#websocket-config" id="websocket-config"></a>

설정 파일: `plantpulse-server/app/plantpulse-server-web/WEB-INF/classes/websocket.properties`

| 파라미터                        | 기본값            | 설명               |
| --------------------------- | -------------- | ---------------- |
| `websocket.server.host`     | `192.168.0.41` | WebSocket 서버 호스트 |
| `websocket.server.port`     | `8000`         | WebSocket 포트     |
| `websocket.server.port_ssl` | `8004`         | WebSocket SSL 포트 |

***

## 스케줄러 설정 <a href="#scheduler-config" id="scheduler-config"></a>

설정 파일: `plantpulse-server/app/plantpulse-server-web/WEB-INF/classes/quartz.properties`

| 파라미터                                   | 기본값 | 설명         |
| -------------------------------------- | --- | ---------- |
| `org.quartz.threadPool.threadCount`    | `8` | 스케줄러 스레드 수 |
| `org.quartz.threadPool.threadPriority` | `5` | 스레드 우선순위   |

***

## 메일 / 알림 설정 <a href="#mail-config" id="mail-config"></a>

설정 파일: `plantpulse-server/app/plantpulse-server-web/WEB-INF/classes/mail.properties`

| 파라미터                        | 기본값            | 설명         |
| --------------------------- | -------------- | ---------- |
| `mail.smtp.host`            | `192.168.0.41` | SMTP 서버 주소 |
| `mail.smtp.port`            | `25`           | SMTP 포트    |
| `mail.smtp.auth`            | `false`        | 인증 사용 여부   |
| `mail.smtp.starttls.enable` | `false`        | TLS 사용 여부  |

***

## 애플리케이션 설정 <a href="#app-config" id="app-config"></a>

설정 파일: `plantpulse-server/app/plantpulse-server-web/WEB-INF/classes/application.properties`

### 알람

| 파라미터                              | 기본값     | 설명               |
| --------------------------------- | ------- | ---------------- |
| `alarm.list.page.index.limit`     | `100`   | 알람 목록 페이지 크기     |
| `alarm.list.page.advsearch.limit` | `1000`  | 고급 검색 최대 건수      |
| `alarm.duplicate.check.minutes`   | `10`    | 중복 알람 체크 간격 (분)  |
| `alarm.read.check.interval.ms`    | `60000` | 알람 읽기 체크 간격 (ms) |
| `alarm.new.audio.play`            | `true`  | 새 알람 사운드 재생      |

### 스냅샷

| 파라미터                                   | 기본값             | 설명            |
| -------------------------------------- | --------------- | ------------- |
| `snapshot.tagmap.timer.period.ms`      | `1000`          | 태그맵 스냅샷 주기    |
| `snapshot.asset.event.timer.period.ms` | `1000`          | 에셋 이벤트 스냅샷 주기 |
| `asset.point.insert.schedule.cron`     | `0 */1 * * * ?` | 에셋 포인트 집계 크론  |

### 진단

| 파라미터                        | 기본값          | 설명             |
| --------------------------- | ------------ | -------------- |
| `diagnostic.webhook.enable` | `false`      | Webhook 알림 활성화 |
| `diagnostic.webhook.level`  | `ERROR,WARN` | 알림 레벨          |

***

## 성능 병목 진단 <a href="#bottleneck-diagnosis" id="bottleneck-diagnosis"></a>

성능 문제가 발생했을 때 아래 증상별 진단 방법과 해결책을 참고해 주세요.

### 1. 파이프라인 큐 적체

**증상**: 파이프라인 대기 큐가 지속적으로 증가합니다

```bash
# Grafana 대시보드에서 "파이프라인 대기 큐" 패널을 확인해 주세요
# 또는 JMX: pipeline.queue.size 값을 확인해 주세요
```

**해결**:

* `engine.pipeline.threads` 값을 늘려 주세요
* `engine.pipeline.ratelimit` 값을 상향 조정해 주세요
* Cassandra 쓰기 성능을 확인해 주세요

### 2. Cassandra 쓰기 지연

**증상**: 쓰기 타임아웃 또는 `WriteTimeoutException`이 발생합니다

```bash
# 컴팩션 상태 확인
/opt/kopens/plantpulse-platform/plantpulse-startup/node-compactionstats.sh

# Memtable 플러시
/opt/kopens/plantpulse-platform/plantpulse-startup/node-flush.sh
```

**해결**:

* `concurrent_writes` 값을 늘려 주세요
* `compaction_throughput` 값을 늘려 주세요
* 디스크 I/O 성능을 점검해 주세요 (SSD 사용을 권장합니다)

### 3. 메모리 부족

**증상**: JVM GC가 빈번하게 발생하거나 `OutOfMemoryError`가 발생합니다

**해결**:

* 서비스 모듈의 `bin/start.sh`에서 `-Xmx` 값을 늘려 주세요
* `engine.pipeline.queue.size` 값을 줄여 메모리 사용을 절약해 주세요
* 불필요한 캐시를 비활성화해 주세요

### 4. 네트워크 지연

**증상**: 데이터 수신 지연이 증가합니다 (Grafana "네트워크 지연" 패널에서 확인 가능)

**해결**:

* OPC 서버와 PlantPulse 간 네트워크 상태를 확인해 주세요
* `engine.streaming.messaging.timeout.ms` 값을 조정해 주세요
* MQTT QoS 레벨을 확인해 주세요

***

## 기술 지원

성능 튜닝 관련 문의: <webmaster@kopens.com>
