Files
runbooks/anvil-load-test-report.md
kappa 53a655d4d5 Initial commit: Add runbooks collection
- anvil-load-test-report.md
- claude_communication_flow.md
- incus-crowdsec-architecture.md
- incus-meilisearch-manual.md
- kitty-setup-guide.md
- OpenAppSec_WAF_Operations_Guide.md
- openappsec-setup-20250817.md
- xray-proxy-guide.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 00:31:54 +09:00

407 lines
9.7 KiB
Markdown

# Anvil 부하테스트 및 성능 최적화 보고서
**작성일**: 2026-01-10
**환경**: Incus jp1 → k8s (k3s) → anvil namespace
---
# Part 1. 핵심 요약
## 1. 아키텍처
```
┌─────────────────────────────────────────┐
│ k8s (k3s, max-pods=200) │
│ │
[Client] ──▶ Cloudflare ─┼─▶ Traefik (x3) │
(권장) │ │ │
│ ▼ │
│ Nginx (x2~15, HPA) │
│ │ │
│ ▼ │
│ PHP-FPM (x5~30, HPA) ─▶ Redis │
│ │ (Session) │
│ ▼ │
│ ProxySQL (Cache 256MB) │
│ │ │
└───────┼─────────────────────────────────┘
┌────────────┴────────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ MariaDB-1 │ │ MariaDB-2 │
│ (Primary) │──Repl───▶ │ (Replica) │
└─────────────┘ └─────────────┘
```
---
## 2. 최종 성능 결과
### 2.1 Gnuboard5 (실제 애플리케이션)
| 항목 | Origin Only | + Cloudflare (예상) |
|------|-------------|---------------------|
| **최대 RPS** | **505.9** | **2,000+** |
| 성공률 | 100% | 100% |
| 평균 응답 | 390ms | ~50ms (캐시 HIT) |
### 2.2 simple-db.php (단순 쿼리)
| 항목 | 값 |
|------|-----|
| **최대 RPS** | **3,466** |
| 성공률 | 100% |
| 평균 응답 | 56ms |
### 2.3 예상 동시 접속자
| 시나리오 | Gnuboard5 |
|----------|-----------|
| Origin Only | ~1,700명 |
| **Cloudflare 70% 캐시** | **~5,600명** |
| **Cloudflare 80% 캐시** | **~8,500명** |
---
## 3. 최적화 적용 현황
| 영역 | 최적화 | 효과 | 상태 |
|------|--------|------|------|
| ProxySQL | Query Cache 256MB | DB 부하 99% 감소 | ✅ |
| ProxySQL | Read Replica 활용 | +21% RPS | ✅ |
| PHP | OPcache 256MB | PHP 컴파일 캐시 | ✅ |
| PHP | Redis 세션 | 세션 공유/속도 | ✅ |
| HPA | minReplicas 설정 | Cold Start 방지 | ✅ |
| MariaDB | Buffer Pool 512MB | 99.998% 히트율 | ✅ |
| **CDN** | **Cloudflare** | **+300% 예상** | ⏳ 권장 |
---
## 4. 핵심 설정값
### 4.1 HPA 설정
| Deployment | Min | Max | CPU Target |
|------------|-----|-----|------------|
| nginx | 2 | 15 | 70% |
| php-fpm | 5 | 30 | 70% |
### 4.2 리소스 설정
| 구성요소 | 설정 | 값 |
|----------|------|-----|
| MariaDB | max_connections | 500 |
| ProxySQL | Query Cache | 256MB, TTL 5초 |
| ProxySQL | Read Replica | hostgroup 1 |
| PHP | OPcache | 256MB, 20K files |
| PHP | Session | Redis |
| k3s | max-pods | 200 |
### 4.3 업로드 제한
| 구성요소 | 값 |
|----------|-----|
| Nginx | 100MB |
| PHP | 100MB |
---
## 5. 운영 체크리스트
### 필수 확인 사항
- [ ] HPA minReplicas 설정 확인 (nginx: 2, php-fpm: 5)
- [ ] ProxySQL Read Replica 설정 확인 (hostgroup 1)
- [ ] ProxySQL PVC 마운트 확인 (설정 영구 저장)
- [ ] OPcache 활성화 확인
- [ ] Redis 세션 연결 확인
- [ ] Cloudflare 적용 (권장)
### 모니터링 명령어
```bash
# k9s 실행
k9s
# HPA 상태
kubectl get hpa -n anvil
# Pod 리소스
kubectl top pods -n anvil
# ProxySQL 캐시 상태
kubectl exec -n anvil deploy/proxysql -- mysql -h127.0.0.1 -P6032 -uadmin -padmin \
-e "SELECT * FROM stats.stats_mysql_global WHERE Variable_Name LIKE '%Query_Cache%';"
```
---
## 6. 변경 이력
| 일시 | 변경 내용 | 효과 |
|------|----------|------|
| 2026-01-09 | MariaDB max_connections 151→500 | 연결 여유 확보 |
| 2026-01-09 | nginx/php-fpm CPU 2코어 | 처리량 증가 |
| 2026-01-09 | ProxySQL Query Cache 256MB | +17% RPS |
| 2026-01-09 | k3s max-pods 200 | Pod 확장성 |
| 2026-01-09 | OPcache 최적화 | PHP 성능 향상 |
| 2026-01-09 | HPA minReplicas 설정 | +6% RPS |
| 2026-01-09 | ProxySQL Read Replica | +21% RPS |
| 2026-01-09 | Real IP 설정 | 클라이언트 IP 추적 |
| 2026-01-09 | 파일 업로드 100MB | 대용량 파일 지원 |
| 2026-01-10 | 최종 문서 정리 | - |
---
# Part 2. 상세 설정 (참고)
## A. ProxySQL 설정
### Query Cache 설정
```sql
-- ProxySQL Admin (포트 6032) 접속
SET mysql-query_cache_size_MB = 256;
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
-- SELECT 쿼리 캐시 + Read Replica 라우팅
INSERT INTO mysql_query_rules
(rule_id, active, match_digest, cache_ttl, destination_hostgroup, apply)
VALUES
(100, 1, '^SELECT', 5000, 1, 1);
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
```
### Hostgroup 구성
| Hostgroup | 서버 | 용도 |
|-----------|------|------|
| 0 | Primary (10.253.101.133) | Write |
| 1 | Primary + Replica | Read (캐시 + 부하분산) |
### 캐시 동작 흐름
```
요청 ──▶ ProxySQL
├─ Cache HIT (99.5%) ──▶ 즉시 응답 (0.1ms)
└─ Cache MISS (0.5%) ──▶ MariaDB (Primary/Replica)
└──▶ 캐시 저장 ──▶ 응답
```
---
## B. PHP 설정
### OPcache (opcache.ini)
```ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.fast_shutdown=1
opcache.interned_strings_buffer=16
```
### 세션 (session.ini)
```ini
session.save_handler = redis
session.save_path = "tcp://redis:6379"
```
### 업로드 (upload.ini)
```ini
upload_max_filesize = 100M
post_max_size = 100M
max_file_uploads = 20
max_execution_time = 300
max_input_time = 300
```
---
## C. Nginx 설정
### nginx.conf
```nginx
worker_processes auto;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Real IP
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# Gzip
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript;
}
```
### default.conf (주요 부분)
```nginx
upstream php-upstream {
server php-fpm:9000;
keepalive 32;
}
server {
client_max_body_size 100m;
location ~ \.php$ {
fastcgi_pass php-upstream;
fastcgi_keep_conn on;
fastcgi_buffer_size 32k;
fastcgi_buffers 16 16k;
}
}
```
---
## D. Traefik Real IP 설정
```yaml
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
additionalArguments:
- "--entryPoints.web.forwardedHeaders.insecure=true"
- "--entryPoints.websecure.forwardedHeaders.insecure=true"
```
---
## E. HPA 설정
### Cold Start 방지
```bash
kubectl patch hpa nginx-hpa -n anvil -p '{"spec":{"minReplicas":2}}'
kubectl patch hpa php-fpm-hpa -n anvil -p '{"spec":{"minReplicas":5}}'
```
---
## F. k3s 설정
### max-pods 증가
```bash
# /etc/rancher/k3s/config.yaml
kubelet-arg:
- "max-pods=200"
```
---
## G. MariaDB 상태 (참고)
| 지표 | 값 | 평가 |
|------|-----|------|
| Buffer Pool Size | 512MB | 적정 |
| Buffer Pool Hit Rate | 99.998% | 최상 |
| max_connections | 500 | 적정 |
| Slow Queries | 0 | 최상 |
---
## H. Cloudflare 설정 가이드 (권장)
### Cache Rules 설정
**Rule 1: 정적 파일**
```
If: File extension = css, js, jpg, png, gif, ico, woff2
Then: Cache (Edge TTL: 1 month)
```
**Rule 2: 게시판 페이지 (비로그인)**
```
If: URI contains "/gb5/" AND Cookie NOT contains "ck_mb_id"
Then: Cache (Edge TTL: 5 minutes)
```
**Rule 3: 관리자/글쓰기 제외**
```
If: URI contains "/adm" OR "/bbs/write" OR Cookie contains "ck_mb_id"
Then: Bypass cache
```
### 예상 효과
| 캐시 히트율 | 유효 RPS |
|------------|----------|
| 50% | ~1,000 |
| 70% | ~1,700 |
| 80% | ~2,500 |
---
## I. 성능 튜닝 히스토리
| 설정 | RPS | 성공률 | 비고 |
|------|-----|--------|------|
| 초기 상태 | ~150 | 93% | Cold Start |
| + CPU 2코어 | ~370 | 99% | - |
| + minReplicas | 419 | 99.98% | +6% |
| **+ Read Replica** | **505.9** | **100%** | **+21%** |
---
## J. 부하 테스트 명령어
```bash
# Gnuboard5 테스트
hey -n 20000 -c 200 -t 20 -host "gnu.anvil.it.com" "http://10.253.103.124/gb5/"
# simple-db.php 테스트
hey -n 20000 -c 200 -t 20 -host "gnu.anvil.it.com" "http://10.253.103.124/simple-db.php"
# ProxySQL 캐시 히트율 확인
kubectl exec -n anvil deploy/proxysql -- mysql -h127.0.0.1 -P6032 -uadmin -padmin \
-e "SELECT * FROM stats.stats_mysql_global WHERE Variable_Name LIKE '%Query_Cache%';"
```
---
## K. k9s 단축키
| 키 | 기능 |
|----|------|
| `:ns` | 네임스페이스 선택 |
| `:pod` | Pod 목록 |
| `:hpa` | HPA 목록 |
| `l` | 로그 보기 |
| `s` | Shell 접속 |
| `d` | Describe |
| `/` | 필터링 |