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

9.7 KiB

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 적용 (권장)

모니터링 명령어

# 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 설정

-- 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)

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)

session.save_handler = redis
session.save_path = "tcp://redis:6379"

업로드 (upload.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

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 (주요 부분)

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 설정

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 방지

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 증가

# /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. 부하 테스트 명령어

# 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
/ 필터링