Zend OPcache 개념과 설치 및 설정: php.ini 값과 JIT 비활성화

Zend OPcache는 PHP 스크립트를 바이트코드로 컴파일해 공유 메모리에 저장하고, 같은 파일을 다시 실행할 때 컴파일을 건너뛰게 하는 PHP 확장입니다. PHP 8.3을 사용하는 워드프레스 서버에서 JIT을 활성화한 뒤 전 페이지에 500 오류가 나자, OPcache는 그대로 두고 JIT만 비활성화해 복구했습니다.
PHP 5.5부터는 OPcache가 PHP에 기본으로 포함되어 배포됩니다.
1️⃣ Zend OPcache 개념: 바이트코드 캐싱
PHP 스크립트는 요청이 올 때마다 파일 읽기, 바이트코드 컴파일, 실행의 세 단계를 거칩니다. OPcache가 동작하면 같은 파일의 두 번째 요청부터 앞의 두 단계가 빠지고 실행만 남습니다.
OPcache가 바이트코드를 저장하는 공유 메모리는 PHP-FPM의 모든 워커가 함께 사용합니다. 같은 PHP-FPM에 연결된 사이트가 여럿이면, 그 사이트들의 스크립트도 한 공유 메모리에 저장됩니다.
OPcache가 저장하는 대상은 컴파일된 PHP 코드라, 페이지를 열 때마다 PHP 실행과 데이터베이스 조회는 그대로 일어납니다. 완성된 HTML을 저장해 PHP 실행 자체를 건너뛰는 것은 페이지 캐시의 역할입니다.
2️⃣ PHP OPcache 설치 확인
OPcache가 설치되어 있는지는 [php -v] 출력의 마지막 줄에서 확인합니다.
php -vPHP 8.3.22 (cli) (built: Jun 3 2025 17:17:57) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.22, Copyright (c) Zend Technologies
with Zend OPcache v8.3.22, Copyright (c), by Zend Technologies마지막 줄이 없다면 dnf로 설치합니다. 패키지 이름은 보통 php-opcache이며, Remi 저장소로 여러 PHP 버전을 함께 설치했다면 php83-php-opcache처럼 버전이 붙습니다.
dnf -y install php-opcacheRemi 저장소의 php-opcache 패키지는 [/etc/php.d/10-opcache.ini]의 [zend_extension=opcache] 줄로 확장을 읽어 들입니다. 설치한 뒤 PHP-FPM을 다시 시작하면 웹 요청에도 OPcache가 적용됩니다.
3️⃣ OPcache 설정: php.ini 값
OPcache 설정은 [/etc/php.ini]의 [opcache] 부분과 [/etc/php.d/10-opcache.ini] 두 곳에 들어갈 수 있습니다.
php --iniConfiguration File (php.ini) Path: /etc
Loaded Configuration File: /etc/php.ini
Scan for additional .ini files in: /etc/php.d
Additional .ini files parsed: /etc/php.d/10-opcache.ini,php.d 폴더의 파일은 php.ini 다음에 읽히므로, 같은 항목을 두 곳에 적으면 php.d 쪽 값이 적용됩니다.
아래 표는 PHP 8.3의 기본값과, 확인한 워드프레스 서버에 적용된 값입니다.
| 항목 | PHP 8.3 기본값 | 적용 값 | 뜻 |
|---|---|---|---|
| opcache.enable | 1 | 1 | OPcache 사용 |
| opcache.enable_cli | 0 | 1 | 명령줄 PHP(wp-cli 등)에서도 사용 |
| opcache.memory_consumption | 128 | 1024 | 바이트코드를 저장하는 공유 메모리(MB) |
| opcache.interned_strings_buffer | 8 | 16 | 같은 문자열을 한 번만 저장하는 메모리(MB) |
| opcache.max_accelerated_files | 10000 | 10000 | 캐시할 수 있는 키 수 상한(실제 상한은 이 값 이상의 소수, 10000이면 16229) |
| opcache.max_wasted_percentage | 5 | 10 | 메모리가 모자라고 버려진 공간이 이 비율을 넘으면 캐시를 비우고 다시 시작 |
| opcache.validate_timestamps | 1 | 1 | 파일이 바뀌었는지 확인 |
| opcache.revalidate_freq | 2 | 60 | 파일 변경 확인 주기(초) |
| opcache.jit | tracing | disable | JIT 방식(PHP 8.4부터 기본값 disable) |
| opcache.jit_buffer_size | 0 | 0 | JIT 메모리, 0이면 JIT이 동작하지 않음(PHP 8.4부터 기본값 64M) |
[/etc/php.ini]의 [opcache] 부분에 넣은 값은 아래와 같습니다. 메모리 크기는 서버 메모리에, [opcache.max_accelerated_files]는 워드프레스 파일 수에 맞춰 정합니다.
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=1024
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=10
opcache.validate_timestamps=1
opcache.revalidate_freq=60php.ini에 [zend_extension] 줄을 다시 넣으면 확장을 두 번 읽게 되어 [Cannot load Zend OPcache] 경고가 출력됩니다.
[opcache.revalidate_freq]가 60이면 PHP 파일을 수정한 뒤 최대 60초 동안 이전 코드가 실행될 수 있습니다.
PHP 파일이 자주 바뀌는 워드프레스 서버는 [opcache.validate_timestamps]를 1로 두어 파일 변경을 확인하게 합니다. Symfony 문서가 운영 서버에 권하는 0은 새 버전을 배포할 때만 PHP 파일이 바뀌는 서버에 맞는 값입니다.
[opcache.validate_timestamps]를 0으로 두어도 관리자 화면에서 업데이트하면 워드프레스가 바뀐 파일의 캐시를 직접 비웁니다. 그러나 wp-cli로 업데이트하거나 SSH로 파일을 수정하면 PHP-FPM을 다시 시작하기 전까지 이전 코드가 실행됩니다.
4️⃣ OPcache JIT 비활성화
PHP 8의 JIT은 CPU 연산이 많은 작업을 빠르게 하는 기능이라, 워드프레스처럼 웹 요청을 처리하는 애플리케이션에서는 효과가 작습니다. PHP JIT RFC에 실린 워드프레스 측정에서도 JIT을 활성화한 쪽은 초당 326건, 비활성화한 쪽은 315건이었습니다.
PHP 8.3.22를 사용하는 워드프레스 서버에서 [opcache.jit=tracing]과 [opcache.jit_buffer_size=128M]으로 JIT을 활성화했습니다. 사흘 뒤 요청이 몰려 PHP-FPM 워커가 여러 번 다시 시작된 날, 전 페이지에서 500 오류가 발생했습니다.
오류 기록에는 [Allowed memory size of 1073741824 bytes exhausted] 메시지가 남았습니다. 메시지 뒤에 붙은 [tried to allocate 4295229440 bytes]는 PHP 메모리 한도 1GB에서 4GB를 한 번에 할당하려 한 기록입니다. JIT을 비활성화하자 같은 요청이 정상적으로 처리되었습니다.
JIT은 [/etc/php.d/10-opcache.ini]에 아래 두 줄을 넣어 비활성화합니다. [/etc/php.ini]에 JIT 설정이 남아 있어도 이 파일의 값이 적용됩니다.
opcache.jit=disable
opcache.jit_buffer_size=0PHP 8.3은 [opcache.jit_buffer_size] 기본값이 0이라, 따로 설정하지 않으면 JIT이 동작하지 않습니다. PHP 8.4부터는 [opcache.jit] 기본값도 disable입니다.
5️⃣ 설정 적용 및 확인
바꾼 설정은 PHP-FPM을 다시 시작해야 적용됩니다.
systemctl restart php-fpm다시 시작하면 OPcache 공유 메모리가 비워지고, 새 설정으로 다시 할당됩니다.
php -i | grep -E '^opcache\.(enable|memory_consumption|revalidate_freq|validate_timestamps|jit) 'opcache.enable => On => On
opcache.jit => disable => disable
opcache.memory_consumption => 1024 => 1024
opcache.revalidate_freq => 60 => 60
opcache.validate_timestamps => On => On[php -i]가 출력하는 값은 명령줄 PHP의 설정이며, RHEL 계열은 PHP-FPM도 같은 [/etc/php.ini]와 [/etc/php.d] 파일을 읽으므로 값이 같습니다.
명령줄에서 [opcache_get_status()]를 호출하면 캐시된 스크립트가 0개로 나옵니다. 명령줄 PHP는 실행할 때마다 공유 메모리를 새로 만들기 때문에, PHP-FPM의 사용량은 아래 파일을 웹 문서 폴더에 올려 브라우저로 확인합니다.
<?php
header('Content-Type: text/plain');
$s = opcache_get_status(false);
print_r($s['memory_usage']);
print_r($s['opcache_statistics']);
print_r($s['interned_strings_usage']);
var_dump($s['cache_full']);[cache_full]이 true면 공유 메모리나 키가 다 찬 상태입니다. 확인한 뒤에는 이 파일을 바로 삭제합니다.
워드프레스 사이트 세 곳이 같은 PHP-FPM을 사용하는 서버에서는 공유 메모리 1024MB 가운데 317MB를 사용하고 있었습니다. 캐시된 스크립트는 사이트마다 3,366~4,222개, 모두 11,358개였습니다.
OPcache는 스크립트를 실제 경로로 저장하고, 상대 경로로 불러온 파일에는 작업 디렉터리를 붙인 키를 하나 더 만들기 때문에 키 수가 스크립트 수보다 많아집니다. 스크립트 11,358개에 키는 상한 16,229개가 다 찼고, 문자열 버퍼 16MB도 남은 공간이 없었습니다.
키가 다 차면 새 스크립트는 캐시되지 않고 요청마다 컴파일됩니다. 5분 21초 사이에 캐시 미스는 18,408건에서 36,027건으로 늘었지만, 캐시된 스크립트 수는 11,358개 그대로였습니다.
워드프레스를 여러 개 운영하거나 플러그인이 많은 서버는 [opcache.max_accelerated_files]를 키 상한이 차지 않도록 넉넉하게 정합니다. 20000으로 정하면 실제 키 상한은 32,531개가 됩니다. 문자열 버퍼가 다 찼다면 [opcache.interned_strings_buffer]도 함께 늘립니다.
🔢 FAQ & 추천 콘텐츠
캐시
캐시: 정의와 캐싱이 사용되는 모든 분야
컴파일된 PHP 코드를 저장하는 OPcache와 완성된 HTML을 저장하는 페이지 캐시를 포함해, 캐시가 사용되는 분야를 나눈 글입니다.
PHP-FPM
php-fpm max_children 경고: 워커 증설 전에 로그로 원인 판별
OPcache 공유 메모리를 함께 사용하는 PHP-FPM 워커가 다 찼을 때 나오는 경고의 원인을 로그로 판별하는 글입니다.
PHP-FPM
PHP-FPM이란 | PHP-FPM 설치 및 설정
OPcache가 안에서 동작하는 PHP-FPM의 설치와 www.conf 풀 설정, 재시작 방법을 다룬 글입니다.
ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.