WordPress Redis 객체 캐시 설정 및 VPS 최적화 가이드
WordPress 성능 향상을 위한 Redis 객체 캐시 설정 방법을 안내합니다. localhost 바인딩, maxmemory 설정, eviction 정책 선택 및 캐시 정상 작동 여부를 확인하는 실무 중심의 가이드를 통해 데이터베이스 부하를 효과적으로 줄이는 방법을 확인하십시오.
WordPress에서 Redis 객체 캐시의 역할
WordPress용 Redis 객체 캐시는 데이터베이스 쿼리 결과를 메모리에 저장합니다. 따라서 다음 요청 시에는 MySQL에 다시 질의하는 대신 Redis에서 결과를 읽어옵니다. WordPress 코어에는 이미 WP_Object_Cache이라는 객체 캐시가 내장되어 있지만, 이는 PHP 메모리에 상주하며 요청이 종료되면 삭제됩니다. 드롭인(drop-in) 파일을 사용하면 이를 Redis와 통신하는 방식으로 대체하여, 요청이 끝나도 캐시가 유지되도록 할 수 있습니다.
객체 캐싱은 페이지 캐싱과 다르며, 이 차이를 이해해야 이 가이드가 귀하에게 유용한지 판단할 수 있습니다. 페이지 캐시는 URL의 완성된 HTML을 저장했다가 PHP를 실행하지 않고 그대로 제공합니다. 이는 Redis가 할 수 있는 어떤 작업보다 빠르며, 로그인하지 않은 방문자에게 효과적입니다. 누군가 로그인하거나, 장바구니에 상품을 담거나, 관리자 페이지를 여는 순간 페이지 캐시는 작동을 멈추고 WordPress가 부트스트랩, 플러그인, 쿼리 등 전체 요청 과정을 수행합니다. 객체 캐시는 바로 그 요청을 더 효율적으로 만듭니다. 이는 페이지 캐시가 처리할 수 없는 로그인 세션, 장바구니, 결제, wp-admin과 같은 트래픽을 위한 도구입니다. WooCommerce 쇼핑몰에서는 이러한 트래픽이 가장 많은 비용을 발생시킵니다.
두 캐시는 함께 사용할 수 있으며, 트래픽이 많은 사이트라면 둘 다 필요합니다. 어떤 문제를 해결하려는지 명확히 하십시오. 익명 사용자가 방문하는 단순 홍보용 사이트는 페이지 캐시만으로도 대부분의 속도 향상을 얻을 수 있으며, Redis를 추가해도 큰 차이가 없습니다.
시작하기 전에 한 가지 솔직한 한계를 말씀드립니다. 객체 캐시는 느린 쿼리를 빠르게 만들지 않습니다. 이미 실행된 쿼리의 반복을 제거할 뿐입니다. 캐시 미스(miss) 이후의 첫 번째 요청은 여전히 전체 비용을 지불해야 하므로, 인덱싱되지 않은 쿼리를 실행하는 플러그인은 캐시 유효 기간 동안 한 번은 해당 쿼리를 실행하게 됩니다.
사전 준비 사항
- 셸과
sudo을 사용할 수 있는 Linux VPS가 필요합니다. 제어판은 필요하지 않습니다. - PHP-FPM으로 구동되는 WordPress가 필요합니다. 예를 들어 Ubuntu 24.04의 LAMP 스택 환경을 권장합니다.
- 서버에 WP-CLI가 설치되어 있어야 합니다. 이 문서의 모든 단계는 관리자 화면에서도 수행할 수 있지만, 셸을 이용하는 것이 더 빠릅니다.
- PHP와 동일한 머신에 Redis가 설치되어 있어야 합니다. 지연 시간 최소화가 핵심이므로, 네트워크 홉이 발생하면 성능 이점이 사라집니다.
아래 명령어는 PHP 8.3 및 www-data 웹 사용자를 사용하는 Ubuntu 24.04 환경을 기준으로 작성되었습니다. 사용 중인 서버 환경에 맞춰 PHP 버전과 사용자를 조정하십시오. wp 명령어는 wp-config.php 파일이 위치한 WordPress 디렉터리에서 실행하십시오.
Redis 및 PHP 확장 설치
sudo apt update
sudo apt install -y redis-server php-redis
sudo systemctl enable --now redis-server
redis-cli pingredis-cli ping는 PONG에 응답해야 합니다. 만약 Could not connect to Redis at 127.0.0.1:6379: Connection refused가 출력된다면 서버가 실행 중이지 않은 상태이므로, 다음 단계로 넘어가기 전에 systemctl status redis-server를 읽어보시기 바랍니다.
php-redis은 PECL에서 제공하는 C 확장인 PhpRedis입니다. 순수 PHP로 작성된 Predis보다 빠르며, 플러그인은 해당 확장이 존재할 경우 자동으로 이를 사용합니다. PHP-FPM은 시작 시점에 확장을 로드하므로, 새로운 확장을 추가한 뒤에는 풀을 재시작해야 적용됩니다.
sudo systemctl restart php8.3-fpm
php -m | grep redis마지막 확인 단계에서는 주의가 필요합니다. php -m은 명령줄 PHP의 모듈 목록을 보여주며, FPM은 이와 다른 모듈 세트를 로드할 수 있습니다. 가장 확실한 확인 방법은 아래에 설명된 플러그인 자체 진단 기능을 사용하는 것입니다.
2026년 8월 기준으로 Ubuntu 24.04는 Redis 7.0.15 버전을 패키지로 제공하며, 이는 객체 캐시 용도로 사용하기에 충분합니다. 최신 릴리스를 사용하려면 Redis에서 직접 운영하는 APT 저장소를 이용하십시오.
sudo apt install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt update
sudo apt install -y redis사용 중인 배포판이 2024년 라이선스 변경 이후 분기된 Valkey를 제공하는 경우, 동일한 프로토콜을 사용하므로 아래의 모든 내용은 그대로 적용됩니다.
Redis를 외부에서 접근할 수 없도록 바인딩하기
Redis는 기본적으로 비밀번호가 설정되어 있지 않습니다. 포트 6379에 연결할 수 있는 모든 대상은 모든 캐시 값을 읽을 수 있으며 FLUSHALL을 실행할 수 있습니다. 인터넷에 노출된 인스턴스는 몇 시간 내에 스캐너에 의해 발견되므로, 튜닝보다 네트워크 설정이 우선입니다.
/etc/redis/redis.conf를 열고 다음 줄을 확인하십시오.
bind 127.0.0.1 -::1
protected-mode yes설정 파일은 선언일 뿐이며 ss이 실제 증거이므로, 실제로 무엇이 리스닝 중인지 확인해야 합니다.
sudo ss -lntp | grep 6379원하는 상태는 127.0.0.1:6379입니다. 0.0.0.0:6379는 Redis가 공용 인터페이스에서 응답하고 있음을 의미하므로, bind 줄을 수정하고 재시작하십시오.
PHP와 Redis가 같은 서버에 있는 경우, 루프백 TCP보다 Unix 소켓이 더 좋습니다. 경로상에 TCP 스택이 존재하지 않으며, 나중에 변경될 수 있는 방화벽 규칙 대신 파일 권한으로 접근을 제어하기 때문입니다.
unixsocket /run/redis/redis-server.sock
unixsocketperm 770소켓의 소유자는 redis 사용자 및 그룹이므로, 웹 사용자를 해당 그룹에 추가해야 합니다.
sudo systemctl restart redis-server
sudo usermod -aG redis www-data
sudo systemctl restart php8.3-fpm
redis-cli -s /run/redis/redis-server.sock ping이 명령을 실행하면 PONG가 출력되어야 합니다. Could not connect to Redis at /run/redis/redis-server.sock: Permission denied은 그룹 설정이 적용되지 않았음을 의미합니다. id www-data을 확인하십시오. 실행 중인 PHP-FPM은 시작 시점의 그룹 정보를 유지하므로 목록에 재시작이 포함되어 있습니다. 소켓이 정상 작동하는지 확인하기 전까지는 TCP 설정을 유지하십시오. 그렇지 않으면 오타로 인해 두 경로 모두 차단될 수 있습니다.
Redis에는 메모리를 얼마나 할당해야 합니까?
사용 중인 서버의 사양에 맞춰 수치를 산출하십시오. maxmemory 설정이 없는 Redis는 커널이 메모리 부족 상태가 되어 OOM killer가 프로세스를 종료할 때까지 메모리를 점유합니다. 보통 가장 큰 프로세스가 종료되는데, WordPress 서버라면 대개 MySQL이 대상이 됩니다. journalctl -k | grep -i "out of memory" 명령으로 사후에 종료 사실을 확인할 수 있지만, 그때는 이미 사이트가 중단된 상태입니다.
전체 RAM에서 필요한 만큼을 빼는 방식으로 계산을 시작하십시오. MySQL이나 MariaDB는 innodb_buffer_pool_size 및 연결당 버퍼를 예약합니다. PHP-FPM은 pm.max_children에 워커 한 개당 실제 상주 메모리 크기(플러그인이 많은 사이트라면 보통 64 MB에서 128 MB)를 곱한 만큼의 비용이 듭니다. 커널과 웹 서버는 수백 MB를 필요로 합니다. 남은 공간이 가용 범위이며, Redis는 그중 일부를 할당받습니다.
4 GB VPS에서 쇼핑몰을 운영할 때의 예산 산출 예시
이 수치는 예시일 뿐이며 실제 서버 측정값이 아닙니다. 각 항목을 서버에서 확인한 값으로 대체하십시오.
- 1 GB 버퍼 풀을 사용하는 MariaDB: 1024 MB
- 96 MB씩 사용하는 PHP-FPM 워커 10개: 960 MB
- 커널, nginx 또는 Apache, sshd, 로깅: 512 MB
- 잔여 메모리: 약 1.5 GB
이 경우 maxmemory를 256 MB로 설정하는 것이 합리적인 시작점입니다. 충분한 여유 공간을 확보할 수 있으며, 단일 WordPress 사이트가 이보다 더 많은 메모리를 필요로 하는 경우는 드뭅니다.
이제 추측하지 말고 측정하십시오. 실제 트래픽을 하루 동안 처리한 후 다음을 확인합니다.
redis-cli info memory | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy'
redis-cli dbsizeused_memory_human가 제한값보다 훨씬 낮다면 제한을 낮추고 남은 RAM을 MySQL에 할당하여 더 효율적으로 사용하게 하십시오. 제한값에 도달하고 evicted_keys가 하루 종일 상승한다면 제한을 높이십시오. 값은 /etc/redis/redis.conf에서 설정합니다.
maxmemory 256mb
maxmemory-policy allkeys-lruredis-cli config set maxmemory 256mb은 즉시 적용되지만 재시작 시 초기화되므로, 일반 sysctl -w 설정과 동일한 함정에 빠질 수 있습니다. 파일을 편집한 후 sudo systemctl restart redis-server을 실행하고, 값을 다시 읽어 확인하십시오. 이중 안전장치를 마련하는 것이 좋습니다. systemd 유닛의 MemoryMax 제한을 설정하면 설정 오류가 발생한 Redis가 서버 전체를 중단시키는 것을 방지할 수 있습니다. 이 값은 maxmemory보다 높게 설정하십시오. cgroup 제한은 키를 삭제하는 대신 프로세스를 강제 종료하므로 절대 동일하게 설정해서는 안 됩니다. Redis가 WordPress와 함께 컨테이너에서 실행 중이라면 Compose 파일의 메모리 제한에도 동일한 수치를 적용해야 하며, 데이터베이스를 Docker에서 실행할지 호스트에서 실행할지 결정할 때도 같은 논리가 적용됩니다.
의도적으로 축출 정책 선택하기
새로 설치된 Redis의 기본값은 noeviction입니다. 현재 설정을 확인하십시오:
redis-cli config get maxmemory-policynoeviction 상태에서는 인스턴스가 쓰기 작업을 중단하고 다음과 같은 응답을 반환합니다:
(error) OOM command not allowed when used memory > 'maxmemory'.이 한 줄은 이 가이드에서 다루는 가장 최악의 장애 모드입니다. 사이트가 완전히 중단되지 않고 느려지기 때문입니다. 모든 캐시 쓰기 작업이 실패하므로, WordPress는 값을 얻기 위해 데이터베이스를 다시 조회합니다. 이후 다음 요청에서 다시 저장을 시도하지만 또 실패합니다. 결과적으로 사이트는 원래의 데이터베이스 작업에 더해 모든 키마다 Redis를 거치는 왕복 비용까지 부담하게 됩니다. WordPress 관리자 페이지 어디에서도 이런 상황을 알려주지 않습니다. 이 메시지는 PHP 에러 로그에 나타나므로, 캐시를 추가한 뒤 사이트가 느려진다면 OOM command not allowed를 grep으로 검색하십시오.
이 작업에는 allkeys-lru이 적절한 기본값입니다. 메모리가 부족할 때 Redis가 가장 최근에 사용되지 않은 키를 삭제하는데, 이는 객체 캐시가 원하는 동작 방식입니다. 캐시 내의 모든 값은 MySQL에 여전히 존재하는 데이터의 복사본이기 때문입니다. 키를 잃어버리면 쿼리 한 번이 발생하지만, 쓰기를 거부하면 누군가 알아차릴 때까지 모든 요청에서 모든 쿼리가 실패하게 됩니다.
이 작업에 volatile-* 정책은 피하십시오. 이 정책들은 만료 시간이 설정된 키만 고려하며, 만료 시간이 설정된 키가 없을 경우 noeviction처럼 동작한다고 Redis 문서에 명시되어 있습니다. WordPress는 대부분의 객체 캐시 항목을 TTL 없이 저장하므로, 객체 캐시에서 volatile-lru을 사용하면 메모리가 가득 차서 쓰기 작업을 거부하기 시작할 수 있습니다. 트래픽이 특정 키 집합에 자주 집중되는 경우라면, 최근 사용 여부가 아닌 빈도를 기준으로 축출하는 allkeys-lfu도 괜찮은 대안입니다. 정책을 신중하게 선택하고 그 이유를 기록해 두십시오.
지속성: 특별한 이유가 없다면 비활성화하십시오
패키지된 redis.conf은 save 900 1와 같은 줄을 통해 RDB 스냅샷을 활성화하며, append-only 파일은 비활성화 상태로 둡니다. 순수 객체 캐시의 경우 스냅샷은 아무런 이득이 없습니다. 데이터는 정의상 재생성 가능하며, 20분 전 파일에서 복원된 캐시는 WordPress가 신뢰하게 될 오래된 값들의 집합일 뿐입니다.
스냅샷은 비용을 발생시킵니다. BGSAVE은 프로세스를 포크(fork)하며, copy-on-write 방식은 자식 프로세스가 데이터를 쓰는 동안 메모리 사용량을 급격히 증가시킬 수 있습니다. 소규모 VPS에서는 Redis 로그에 다음과 같이 나타납니다.
Can't save in background: fork: Cannot allocate memory또한 시작 시 종종 다음과 같은 경고가 나타나는데, 이는 나중에 포크가 실패할 가능성이 높음을 Redis가 알리는 것입니다.
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.스냅샷을 끄려면 /etc/redis/redis.conf에서 save 일정을 비우고, 재시작한 뒤 값이 비어 있는지 확인하십시오.
save ""sudo systemctl restart redis-server
redis-cli config get save작업 큐나 속도 제한 카운터와 같이 재구축할 수 없는 데이터를 동일한 인스턴스에 보관하는 경우에만 지속성을 유지하십시오. 그런 경우에는 두 기능을 분리해야 합니다. 캐시는 키가 제거되기를 원하지만 내구성이 필요한 데이터는 키가 유지되기를 원하며, maxmemory와 제거 정책은 특정 데이터베이스 인덱스가 아닌 인스턴스 전체에 적용되기 때문입니다. 두 개의 소켓에서 두 개의 인스턴스를 운영하는 것이 깔끔한 해결책입니다.
플러그인을 설치하고 드롭인(drop-in) 이해하기
wp plugin install redis-cache --activate
wp redis enable
wp redis statuswp redis enable은 성공 시 Object cache enabled.를 출력합니다. 이 명령은 실제로 wp-content/plugins/redis-cache/includes/object-cache.php를 wp-content/object-cache.php으로 복사하는 역할을 합니다. 이 복사본이 바로 드롭인이며, 이 드롭인이 실제 기능을 수행합니다. WordPress는 모든 플러그인 코드가 실행되기 전인 매우 이른 시점에 wp-content/object-cache.php을 로드하므로, 전체 요청 과정에서 캐시를 사용할 수 있습니다. 드롭인이 없는 활성화된 플러그인은 아무것도 캐시하지 않습니다.
실패 메시지는 어느 단계에서 문제가 발생했는지 알려줍니다. Object cache could not be enabled.은 복사가 실패했음을 의미하며, 이는 WP-CLI를 실행하는 사용자가 wp-content에 쓰기 권한이 없기 때문입니다. A foreign object cache drop-in was found.은 다른 캐싱 플러그인이 이미 해당 파일명을 사용 중이라는 뜻이며, 해결 방법은 wp redis update-dropin입니다. Redis server is unreachable:로 끝나는 메시지와 함께 클라이언트 오류가 발생한다면 연결 설정이 잘못된 것이므로 redis-cli ping으로 돌아가 확인하십시오.
권한 문제로 복사가 실패했다면 수동으로 파일을 배치하고 웹 사용자에게 소유권을 부여하십시오.
cp wp-content/plugins/redis-cache/includes/object-cache.php wp-content/object-cache.php
sudo chown www-data:www-data wp-content/object-cache.php플러그인을 삭제해도 드롭인은 자동으로 제거되지 않습니다. 먼저 wp redis disable를 실행하십시오. 이 명령은 Object cache disabled.를 출력하고 파일을 삭제합니다. 드롭인을 남겨둔 채 플러그인 디렉터리만 삭제하면, 사이트는 업데이트할 플러그인 없이 이전 캐시 코드를 계속 실행하게 됩니다.
wp-config.php의 연결 설정
이 설정들을 /* That's all, stop editing! */ 줄 위에 추가하십시오. 이 줄 이후에 정의된 상수는 적용 시점이 너무 늦기 때문입니다.
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );Unix 소켓을 사용하는 경우, scheme과 path를 설정하십시오. 이 경우 host와 port는 무시됩니다.
define( 'WP_REDIS_SCHEME', 'unix' );
define( 'WP_REDIS_PATH', '/run/redis/redis-server.sock' );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );WP_REDIS_MAXTTL은 모든 키에 초 단위의 만료 시간을 강제합니다. allkeys-lru을 사용하는 경우에는 이 설정이 필요 없으며, 캐시된 값이 가질 수 있는 최대 유효 기간을 엄격하게 제한하고 싶을 때 유용합니다.
하나의 Redis, 여러 사이트: 접두사와 데이터베이스
Redis는 기본적으로 16개의 번호가 매겨진 데이터베이스를 제공하며, 각 데이터베이스 내부에는 하나의 평면적인 키 공간이 존재합니다. 접두사 없이 데이터베이스 0번을 사용하는 WordPress 설치가 두 개 있다면, 두 설치 모두 동일한 키 이름을 같은 공간에 기록하게 됩니다. 이로 인해 한 사이트가 다른 사이트의 옵션을 읽어와 잘못된 정보를 제공할 수 있습니다. 각 사이트에 고유한 접두사를 부여하십시오.
define( 'WP_REDIS_PREFIX', 'shopA_prod:' );
define( 'WP_REDIS_DATABASE', 1 );접두사는 키 이름을 구분합니다. 데이터베이스 인덱스는 키 공간을 구분하며, 이는 데이터를 비울 때 중요합니다. 특정 인덱스를 비워도 다른 인덱스는 영향을 받지 않기 때문입니다. 또한 해당 플러그인은 WP_REDIS_SELECTIVE_FLUSH를 문서화하고 있는데, 이는 전체 데이터베이스를 비우는 대신 접두사와 일치하는 키만 삭제합니다. 단, 이 과정에서 키를 스캔해야 하므로 비용이 발생합니다.
접두사와 인덱스가 구분하지 못하는 것은 메모리입니다. maxmemory 및 축출 정책(eviction policy)은 인스턴스 전체에 적용됩니다. 따라서 트래픽이 많은 사이트가 트래픽이 적은 사이트의 키를 밀어낼 수 있으며, 두 사이트 모두 이를 인지하지 못합니다. 서로 영향을 주어서는 안 되는 사이트들은 각각 고유한 소켓과 제한을 가진 별도의 Redis 인스턴스를 사용해야 합니다.
운영 환경의 캐시와 스테이징 환경 분리하기
스테이징 사이트는 보통 운영 환경의 파일과 데이터베이스를 복사한 것이며, 이는 곧 동일한 접두사와 데이터베이스 인덱스를 사용하는 wp-config.php의 복사본임을 의미합니다. 스테이징 환경을 운영 환경과 동일한 Redis를 가리키도록 설정하면, 스테이징 환경이 운영 환경의 키를 스테이징 값으로 덮어쓰게 됩니다. 이로 인해 테스트용 가격이나 변경된 옵션이 배포 과정이나 기록 없이 실제 운영 사이트에 노출될 수 있습니다.
각 환경마다 수동으로 고유한 접두사(salt)를 설정하십시오. 스테이징 환경의 wp-config.php에 다음을 추가합니다:
define( 'WP_REDIS_PREFIX', 'shop_staging:' );
define( 'WP_REDIS_DATABASE', 5 );더 나은 방법은 스테이징 환경에 별도의 Redis 인스턴스를 할당하거나, 아예 객체 캐시를 사용하지 않는 것입니다. define( 'WP_REDIS_DISABLED', true );을 사용하면 런타임에 캐시를 비활성화하면서도 드롭인 파일은 그대로 유지할 수 있으며, 이는 버그의 원인이 캐시인지 아닌지를 확인하는 가장 빠른 방법이기도 합니다.
이전 튜토리얼에서는 이를 위해 WP_CACHE_KEY_SALT를 설정하도록 안내했습니다. 해당 플러그인의 리드미(readme) 파일에는 이 상수가 더 이상 사용되지 않으며(deprecated) WP_REDIS_PREFIX로 대체되었다고 명시되어 있으므로, 새로운 이름을 사용하십시오.
신뢰하지 말고 검증하십시오
플러그인 자체 진단 도구부터 시작하십시오.
wp redis status가장 중요한 줄은 Drop-in입니다. Drop-in: Valid은 WordPress가 해당 플러그인 파일을 정상적으로 불러오고 있음을 의미합니다. Drop-in: Not installed은 파일 복사가 이루어지지 않았음을 뜻하며, 관리자 화면이 녹색으로 표시되더라도 사이트에 지속적인 캐시가 적용되지 않은 상태입니다. Status는 연결 상태를 보고하며, Client은 현재 사용 중인 확장 기능을 나타냅니다. 여기서 Predis가 아닌 PhpRedis가 사용되고 있는지 확인하십시오.
그다음 WordPress 코어에 직접 질의하십시오. WordPress 코어는 플러그인의 판단과 무관하게 동작하기 때문입니다.
wp eval 'var_dump( wp_using_ext_object_cache() );'bool(true)은 코어가 외부 객체 캐시와 통신하고 있음을 의미합니다.
그다음 설정한 접두사(prefix)와 함께 키가 실제로 도달하고 있는지 확인하십시오.
redis-cli -n 0 dbsize
redis-cli -n 0 --scan --pattern 'shop_prod:*' | head사이트를 탐색할 때 dbsize 값이 증가한다면 정상적으로 작동하는 것입니다. 올바른 drop-in 파일을 사용 중임에도 키 개수가 0이라면 연결이 조용히 실패하고 있거나, 접두사가 예상과 다른 경우입니다.
마지막으로 Redis가 측정하는 지표를 확인하십시오.
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'적중률(hit ratio)은 keyspace_hits / (keyspace_hits + keyspace_misses)이며, Redis 문서에서 해당 공식을 확인할 수 있습니다. 이 수치를 읽을 때는 두 가지 주의 사항이 있습니다. 카운터는 마지막 재시작 이후 인스턴스 전체를 대상으로 하므로, 동일한 인스턴스를 공유하는 모든 사이트와 애플리케이션의 데이터가 섞여 있습니다. 또한 캐시를 비우거나 재시작한 직후의 적중률은 캐시가 채워지는 중이므로 아무런 의미가 없습니다. 정상적인 트래픽이 발생하는 하루 동안 운영해 보십시오.
본인의 수치를 호스팅 업체가 공개한 적중률이나 쿼리 수와 비교하지 마십시오. 해당 수치는 그들의 사이트와 플러그인 환경을 기준으로 합니다. 중요한 것은 페이지 캐시가 처리할 수 없는 페이지에서 직접 측정한 본인의 수치입니다.
curl -o /dev/null -s -w '%{time_starttransfer}\n' -b cookies.txt https://example.com/my-account/로그인 쿠키를 유지한 상태에서 캐시를 끈 채로(WP_REDIS_DISABLED) 여러 번 실행한 뒤, 캐시를 켜고 다시 실행하십시오. 그 차이가 바로 결과값입니다.
Redis가 WordPress를 느리게 만드는 경우
잘못된 정책으로 설정된 전체 인스턴스가 가장 큰 원인이며, 위에서 다룬 바와 같이 로그에 OOM command not allowed when used memory > 'maxmemory'.가 기록되고 데이터베이스와 캐시 비용을 모두 지불하는 상황이 발생합니다.
두 번째 원인은 다른 호스트에 Redis를 두는 것입니다. WordPress는 한 번의 요청에서 수백 번의 객체 캐시 호출을 수행합니다. 요청 하나당 500번의 호출이 발생하고 각 왕복(round trip)에 1ms가 소요된다면, 로컬 소켓을 사용할 때는 없었을 0.5초의 대기 시간이 추가됩니다. Redis는 동일한 서버에 두거나, 1ms 미만의 지연 시간을 보장하는 사설 네트워크 내에 배치하십시오.
세 번째 원인은 과도하게 로드되는 autoloaded 옵션 테이블이며, 이는 오래된 사이트에서 흔히 발생합니다. WordPress는 모든 autoloaded 옵션을 하나의 키로 캐시하므로, 매 요청마다 수 메가바이트의 데이터가 연결을 통해 전송됩니다. 다음 명령으로 측정하십시오.
wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS kb FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');"WordPress 6.6에서 새로운 autoload 값이 추가되었으므로, 'yes'만 일치시키는 이전 쿼리는 최신 설치 환경에서 실제보다 적은 값을 보고할 수 있습니다. 1MB를 초과하는 데이터는 Redis가 아닌 options 테이블에서 해결해야 할 문제입니다.
재시작을 수행하면 모든 데이터가 비워지므로, systemctl restart redis-server 이후 몇 분 동안은 모든 요청이 캐시 미스가 되어 데이터베이스 작업이 집중됩니다. 트래픽이 적을 때 재시작하십시오. 또한 객체 캐시는 방문자가 페이지를 로드할 때 wp-cron.php이 실행되는 것을 막지 못하며, 이는 그 자체로 느린 요청의 원인이 됩니다. 이 작업을 수행하는 동안 WP-Cron을 실제 시스템 cron 작업으로 이동하십시오.
유지보수
옵션이나 테마 코드를 변경하는 배포를 수행한 뒤에는 wp cache flush를 사용하여 캐시를 비웁니다. 플러그인 업데이트 후 drop-in이 자동으로 갱신되지 않았다면 wp redis update-dropin을 실행하십시오. 이전 버전의 플러그인에서 생성된 drop-in을 최신 버전의 플러그인과 함께 사용하면 예기치 않은 동작이 발생할 수 있습니다. redis-cli --stat을 사용하여 실시간 서버 상태를 모니터링하십시오. 이 명령은 초당 한 줄씩 로그를 출력합니다. redis-cli monitor는 모든 명령을 출력하며 부하가 높은 인스턴스에서는 상당한 CPU 자원을 소모하므로, 문제를 재현하는 동안 잠시만 사용하고 즉시 중단하십시오.
알아두어야 할 마지막 수치가 하나 있습니다. redis-cli info clients은 connected_clients를 보고합니다. PHP-FPM은 워커당 하나의 연결을 유지하므로, 해당 수치는 pm.max_children와 비슷한 수준이어야 하며 그보다 한 자릿수 이상 커져서는 안 됩니다. 만약 수치가 훨씬 높다면, 어딘가에서 연결을 열고 닫지 않는 문제가 발생하고 있는 것입니다.
FAQ
Redis 오브젝트 캐시를 사용해도 페이지 캐시가 여전히 필요한가요?
네, 익명 사용자의 트래픽을 처리하기 위해 필요합니다. 페이지 캐시는 PHP를 실행하지 않고 저장된 HTML을 직접 제공하므로, 오브젝트 캐시가 활성화된 상태에서 WordPress를 실행하는 것보다 항상 비용이 적게 듭니다. 오브젝트 캐시는 페이지 캐시가 처리할 수 없는 요청(로그인한 사용자, 장바구니, 결제, wp-admin 등)을 담당합니다. 쇼핑몰이나 멤버십 사이트라면 두 캐시를 모두 사용하는 것이 좋습니다. 방문자가 로그인하지 않는 사이트라면 페이지 캐시가 거의 모든 작업을 수행합니다.
WordPress용 Redis에는 메모리를 얼마나 할당해야 하나요?
다른 곳의 수치를 복사하지 말고 본인의 서버 환경에 맞춰 산정하십시오. 전체 RAM에서 MySQL 버퍼 풀과 연결당 버퍼를 뺍니다. 여기에 pm.max_children에 PHP-FPM 워커 하나의 상주 메모리 크기를 곱한 값을 빼고, 커널과 웹 서버를 위해 수백 메가바이트를 추가로 뺍니다. 남은 메모리의 일부를 Redis에 할당한 뒤, 하루 정도 트래픽을 처리한 후 redis-cli info memory에서 used_memory_human을 확인하여 조정하십시오. 단일 WordPress 사이트는 보통 수십 메가바이트 정도를 사용하므로, 4 GB 서버라면 256 MB의 maxmemory는 넉넉한 시작점입니다.
Redis 오브젝트 캐시를 활성화한 후 사이트가 왜 더 느려졌나요?
일반적인 원인은 Redis 인스턴스가 가득 차서 noeviction 정책이 동작하는 경우입니다. Redis는 새로운 쓰기 요청을 거부하고 OOM command not allowed when used memory > 'maxmemory'.을 반환하므로, WordPress는 모든 값을 데이터베이스에서 다시 가져와야 하며 Redis와의 불필요한 왕복 시간까지 추가로 소요됩니다. redis-cli config get maxmemory-policy를 확인하고 allkeys-lru을 설정한 뒤, maxmemory가 너무 작지 않은지 확인하십시오. 또 다른 흔한 원인으로는 원격 호스트에 Redis 서버가 있어 요청당 수백 번의 왕복 시간이 누적되는 경우와, 모든 요청마다 연결을 통해 전송되는 수 메가바이트 크기의 자동 로드 옵션 값이 있는 경우입니다.
여러 WordPress 사이트가 하나의 Redis 서버를 공유할 수 있나요?
주의를 기울인다면 가능합니다. 각 사이트에 고유한 WP_REDIS_PREFIX를 부여하여 키 이름이 충돌하지 않게 하고, 별도의 WP_REDIS_DATABASE 인덱스를 사용하여 한 사이트의 캐시를 비울 때 다른 사이트의 데이터가 삭제되지 않도록 해야 합니다. 하지만 메모리는 여전히 공유됩니다. maxmemory과 데이터 축출(eviction)은 인스턴스 전체에 적용되므로, 트래픽이 많은 사이트가 트래픽이 적은 사이트의 키를 삭제할 수 있습니다. 서로 영향을 주어서는 안 되는 사이트들은 각각 별도의 제한이 설정된 Redis 인스턴스를 사용해야 합니다.
wp-content/object-cache.php 파일을 삭제해도 안전한가요?
네, 안전합니다. 이 파일은 WordPress 코어의 일부가 아닌 드롭인(drop-in) 파일이며, 삭제하면 WordPress는 요청 단위의 기본 내장 캐시로 돌아갑니다. 사이트는 계속 작동하지만 데이터베이스 쿼리 횟수가 늘어납니다. 파일을 깔끔하게 삭제하고 Object cache disabled.를 보고하는 wp redis disable을 사용하는 것을 권장합니다. Redis가 다운되었거나 오작동하여 관리자 페이지에 접근할 수 없는 긴급 상황이라면 수동으로 삭제하는 것이 올바른 대처 방법입니다.