CentOS에서 PHP-FPM과 Redis를 같이 쓰는 서비스는 대체로 빠르지만, 어느 순간부터 “페이지가 전체적으로 굼떠졌다” 같은 체감 문제가 생길 수 있습니다. 이럴 때는 감으로 튜닝하기보다 측정→병목 특정→개선 순서를 지키면, 위험한 변경을 줄이면서도 효과를 빨리 얻습니다.
아래는 “설정 파일 예시 + 검증/재시작 절차” 중심으로, 현장에서 바로 적용 가능한 점검 흐름입니다.
1) 먼저 ‘느림’을 수치로 고정하기(측정 기준 만들기)
체감 성능 문제는 원인이 여러 층(PHP-FPM, Redis, DB, 네트워크, 디스크 I/O)에 걸쳐 있을 수 있어요. 그래서 첫 단계는 “지금 얼마나 느린지”를 재현 가능하게 만드는 겁니다.
- 기간: 최소 10~30분(피크 시간 포함) 데이터를 봅니다.
- 지표: 평균보다 p95/p99 지연이 튀는지 확인합니다(간헐적 병목일수록 꼬리가 길어짐).
- 구간 분리: 웹 서버 응답시간 vs PHP 실행시간 vs Redis 응답시간(가능하면)으로 나눕니다.
빠른 현장 확인용으로는 다음을 함께 보세요.
- CPU/Load: load average가 코어 수 대비 과한지, run queue가 길어지는지
- 메모리: swap 사용이 증가하는지(특히 PHP-FPM 워커 수 과다 시)
- 연결 대기: PHP-FPM이 busy여서 큐가 쌓이는지
2) 병목을 좁히는 체크리스트(현장용)
아래 체크리스트는 “느림의 주범이 어디인지”를 빠르게 갈라주는 질문들입니다. 가능한 것부터 위에서 아래로 보시면 됩니다.
- PHP-FPM 큐/워커 포화? 요청이 들어오는데 처리 워커가 없어서 대기하는지
- slow request 존재? 특정 PHP 스크립트가 2~5초 이상 잡고 있는지
- Redis 호출이 느린가? Redis 자체가 느린지, 네트워크/timeout 때문에 기다리는지
- swap/thrashing? 메모리 부족으로 스왑이 발생해 전체가 느려졌는지
- OPcache 비활성/부족? 코드가 매 요청마다 과도하게 컴파일되는지
- 재시작/배포 직후만 느림? 캐시 warm-up, opcode 캐시 미적중, Redis cold cache 여부
3) PHP-FPM에서 ‘대기’인지 ‘실행’인지 분리(상태 페이지·slowlog)
PHP-FPM이 느린 것처럼 보여도, 실제로는 “워커가 부족해서 대기”하는 경우와 “워커는 있는데 특정 요청이 오래 실행”되는 경우가 완전히 다릅니다. 둘을 분리하려면 status와 slowlog가 효과적입니다.
pool 설정 예시(배포 환경에 맞게 경로/버전은 조정):
/etc/php-fpm.d/www.conf에 아래 항목을 추가/수정합니다.
예시(핵심만)
pm = dynamic
pm.max_children = 30
pm.start_servers = 6
pm.min_spare_servers = 6
pm.max_spare_servers = 12
pm.max_requests = 500
request_terminate_timeout = 30s
request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/www-slow.log
pm.status_path = /fpm-status
해석 포인트는 간단합니다.
- pm.max_children: 워커 상한입니다. 너무 낮으면 대기 증가, 너무 높으면 메모리 부족→swap로 전체 성능 악화.
- pm.max_requests: 워커를 주기적으로 교체해 메모리 누수/단편화 영향을 완화합니다(너무 낮으면 재시작 비용 증가).
- request_slowlog_timeout + slowlog: “어떤 PHP 코드가 느린지” 증거가 남습니다.
- request_terminate_timeout: 무한 대기/외부 의존성 정체로 워커가 고착되는 상황을 줄입니다(서비스 특성에 맞게 신중히).
status 페이지는 보안상 외부 공개를 피하고, 내부에서만 접근되게 제한하세요(예: Nginx location allow/deny). 여기서는 원리만 언급합니다.
4) Redis 연동 병목: timeout·연결 방식·느린 명령부터 확인
PHP-FPM과 Redis 조합에서 자주 나오는 병목은 “Redis가 느리다”라기보다 연결/timeout 설계 때문에 PHP 워커가 기다리면서 막히는 케이스입니다. 특히 네트워크 이슈, 순간 부하, DNS/라우팅 흔들림에서도 지연이 늘어납니다.
우선 점검할 것
- PHP Redis 클라이언트 timeout: connect timeout과 read timeout이 과도하게 큰지(문제 시 워커를 오래 점유)
- persistent connection 사용 여부: 요청마다 connect/disconnect하면 지연과 부하가 증가
- Redis 서버의 slowlog: 특정 명령이 오래 걸리는지(큰 key, 과도한 scan, Lua 등)
- maxmemory 정책: eviction이 잦아 cache miss가 늘면 백엔드(예: DB)까지 느려짐
Redis 설정 예시(원칙 수준에서 확인용):
/etc/redis.conf에서 자주 보는 항목들
tcp-keepalive 60
timeout 0
slowlog-log-slower-than 10000
slowlog-max-len 128
여기서 중요한 건 “값을 무조건 이렇게 하라”가 아니라, slowlog로 근거를 확보하고 “PHP 워커를 오래 붙잡는 대기”를 줄이는 방향으로 보는 겁니다. 예를 들어 read timeout이 너무 길면 장애/지연 시 워커가 한참 묶입니다.
5) OPcache와 PHP-FPM 튜닝: 메모리-워커 균형으로 접근
CentOS에서 PHP-FPM 성능을 체감으로 끌어올리는 대표 조합이 OPcache 최적화 + 적정 워커 수입니다. 단, 워커를 늘리기 전에 메모리 한도를 계산하지 않으면 swap으로 역효과가 날 수 있어요.
OPcache 설정 예시(설치/활성화되어 있다는 전제):
/etc/php.d/10-opcache.ini 또는 /etc/php.ini에 아래처럼 조정합니다.
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=100000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
- memory_consumption: 프레임워크/코드 규모가 크면 기본값으로 부족해 성능이 들쭉날쭉할 수 있습니다.
- validate_timestamps: 배포 방식에 따라 조정합니다. 무중단 배포/컨테이너라면 정책이 달라질 수 있어요.
워커 수( pm.max_children )는 이렇게 접근
- PHP-FPM 워커 1개가 실제로 점유하는 RSS가 얼마인지(대략) 확인
- 서버 가용 메모리에서 OS/Redis/DB/버퍼를 빼고, 남는 메모리를 워커에 배정
- 그 결과로 max_children을 잡고, p95 지연과 swap 여부를 다시 측정
6) 변경은 작게, 검증은 확실하게(설정 테스트·재시작·롤백 습관)
성능 튜닝은 “좋아진 것 같음”이 아니라 “좋아졌다는 근거”가 남아야 합니다. 아래 순서로 진행하면 안전합니다.
- 1) 설정 백업: 변경 전 파일을 복사해 보관
- 2) 단일 변경: 한 번에 하나(예: pm.max_children만 먼저)
- 3) 문법/구동 검증: 설정 오류로 장애가 나지 않게 확인
- 4) 재시작: systemd로 상태 확인 포함
- 5) 효과 측정: 같은 시간대/같은 트래픽 조건에서 p95/p99 비교
- 6) 문제 시 롤백: 즉시 되돌리고 원인 기록
CentOS(systemd) 기준 재시작/상태 확인 예시
systemctl status php-fpm
systemctl reload php-fpm
systemctl restart php-fpm
journalctl -u php-fpm -n 200 --no-pager
systemctl status redis
systemctl restart redis
journalctl -u redis -n 200 --no-pager
가능하면 restart보다 reload로 먼저 시도하되(환경에 따라 적용 범위가 다릅니다), 변경이 반영되지 않거나 상태가 불안정하면 restart로 전환합니다.
마무리
CentOS에서 PHP-FPM + Redis 성능 문제는 “워커 수만 늘리면 해결”처럼 단순하지 않은 경우가 많습니다. 먼저 측정으로 사실을 만들고, PHP-FPM의 대기/실행을 분리한 뒤, Redis timeout·slowlog·OPcache 같은 근거 기반 설정을 순서대로 조정하는 게 가장 안전합니다.
튜닝 후에는 꼭 p95/p99 지연과 swap 여부를 다시 확인해서, 개선이 ‘기분’이 아니라 ‘데이터’로 남게 해두면 다음 장애 대응이 훨씬 쉬워집니다.