PHP
Apache
Performance
OPcache
PHP-FPM
Cache
Monitoring
PHP & Apache 성능 튜닝 완전 가이드
PHP & Apache 성능 튜닝 완전 가이드
이 문서는 트래픽 증가에 대비해 PHP와 Apache 스택을 체계적으로 최적화하는 방법을 제공합니다. 빠른 승수효과(저비용 고효율)부터 인프라 확장까지, 실무 기준의 우선순위로 정리했습니다.
1) 빠른 체감 성능 개선 (Low-hanging fruits)
- gzip/br 압축 활성화 (정적/동적)
- HTTP/2, HTTP/3(QUIC) 활성화
- 이미지 최적화(WebP/AVIF) 및 Lazy-loading
- 정적 파일 캐시 헤더(Cache-Control, ETag) 강화
- CDN 도입으로 Edge 캐시 활용
# Apache도 유사 정책 적용 (mod_headers)
add_header Cache-Control "public, max-age=31536000, immutable";
2) PHP 레이어 최적화
2.1 OPcache 활성화
PHP 코드를 바이트코드로 캐싱해 CPU 사용량을 크게 줄입니다.
; php.ini 또는 opcache.ini
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=50000
opcache.validate_timestamps=0 ; 배포 시 재시작 또는 preloading 사용
opcache.preload=/var/www/app/preload.php
- 배포 파이프라인에서
opcache:reset훅 또는 PHP-FPM 재시작 포함 - 프레임워크(Route/Config) 프리로드로 콜드스타트 최소화
2.2 PHP-FPM 풀 튜닝
; www.conf
pm=dynamic ; 트래픽 예측 가능하면 static, 아니면 dynamic
pm.max_children=64 ; 서버 메모리/응답시간 기준 산정
pm.start_servers=8
pm.min_spare_servers=8
pm.max_spare_servers=16
pm.max_requests=1000 ; 메모리 누수 방지
request_terminate_timeout=60s
- 계산법(대략):
(총 RAM - OS/DB/캐시)/프로세스별 피크RSS ≈ max_children slowlog활성화로 느린 스크립트 추적
slowlog=/var/log/php-fpm/slow.log
request_slowlog_timeout=2s
2.3 Composer Autoload 최적화
composer dump-autoload --optimize --classmap-authoritative --no-dev
- prod 빌드 이미지/아티팩트 단계에서 수행
3) Apache 레이어 최적화
3.1 MPM 선택
- event MPM 권장(Keep-Alive 처리에 유리)
# /etc/apache2/mods-available/mpm_event.conf
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 5000
</IfModule>
- PHP 처리 자체는
php-fpm으로 분리하고 Apache는 리버스 프록시+정적 서빙 역할에 집중
3.2 HTTP/2, 압축, 캐시 헤더
# http2
Protocols h2 http/1.1
# 압축(brotli>gzip)
LoadModule brotli_module modules/mod_brotli.so
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json image/svg+xml
# 캐시 헤더
<FilesMatch "\.(js|css|png|jpg|jpeg|gif|svg|webp|avif|woff2?)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
4) 애플리케이션 레이어
4.1 데이터 캐시 전략
- PSR-16/PSR-6 캐시 추상화 사용 (Redis 권장)
- 핫패스(메뉴, 설정, 권한, 카운트) 캐시
- 쓰기경쟁은 분산락(Redis SET NX PX)으로 보호
$cacheKey = 'article:'.$id;
$data = $cache->get($cacheKey);
if ($data === null) {
$data = $repo->fetch($id);
$cache->set($cacheKey, $data, 300);
}
4.2 세션/큐 외부화
- 세션: 파일 → Redis/Memcached
- 큐: sync → Redis/RabbitMQ (이메일, 썸네일, 웹훅 비동기)
4.3 DB 최적화
- N+1 제거(ORM eager loading)
- 적절한 인덱스와 커버링 인덱스
- 슬로우쿼리 로그 분석 + 쿼리캐시 금지(MySQL8 미제공)
5) 아키텍처 다이어그램
아래 이미지는 본 문서의 권장 아키텍처를 시각화한 것입니다. (확대 가능한 원본은 저장소의 /snapshot/ 폴더를 참고하세요.)

확장 아키텍처 (수평 확장)

6) 모니터링 & 관측성
- 시스템:
htop,iostat,vmstat,sar - 웹: Apache status (
mod_status),ab,wrk,k6 - PHP:
prometheus_client,blackfire,xdebug profiler(스테이징) - APM: OpenTelemetry → Tempo/Jaeger, Metrics → Prometheus + Grafana
# mod_status
<Location "/server-status">
SetHandler server-status
Require local
</Location>
7) 배포 파이프라인 체크리스트
- [ ] 빌드 시
composer install --no-dev --classmap-authoritative - [ ] 에셋 빌드/압축, 파일 지문(fingerprint)
- [ ] OPcache 프리로드/리셋
- [ ] DB 마이그레이션 트랜잭션
- [ ] 헬스체크 + 카나리 배포
8) 성능 벤치마크 예시(k6)
import http from "k6/http";
import { sleep } from "k6";
export const options = {
vus: 50,
duration: "1m",
thresholds: {
http_req_duration: ["p(95)<300"],
},
};
export default function () {
http.get("https://stoni.space/");
sleep(1);
}
결론
- 프론트(압축/캐시/HTTP2) → 2) PHP(OPcache/FPM) → 3) Apache(MPM/헤더) → 4) 데이터/캐시/큐 → 5) 모니터링/확장 순으로 진행하면 위험을 줄이면서 성능을 크게 끌어올릴 수 있습니다.
