NGINX Cache 시스템 이해하기
이번 모범사례는 가장 대중적으로 사용하는 NGINX Cache 시스템에 대한 이해를 돕습니다.
우리는 모두 응용 프로그램과 웹 사이트의 성능이 성공의 중요한 요소라는 것을 알고 있습니다. 그러나 응용 프로그램이나 웹 사이트의 성능을 향상시키는 프로세스가 항상 명확한 것은 아닙니다. 코드 품질과 인프라는 물론 중요하지만 대부분의 경우 매우 기본적인 애플리케이션 제공 기술에 집중함으로써 애플리케이션의 최종 사용자 경험을 크게 개선할 수 있습니다. 그러한 예 중 하나는 애플리케이션 스택에서 캐싱을 구현하고 최적화하는 것입니다.
이 모범 사례에서는 초보자와 고급 사용자 모두 NGINX 및 NGINX Plus에 포함된 콘텐츠 캐시 기능을 활용하여 더 나은 성능을 볼 수 있도록 도와주는 기술을 다룹니다.
※ NGINX Cache 자주 묻는 질문(FAQ) 15가지
목차
1. 개요
2. 기본 캐싱을 설정 및 구성하는 방법
3. Origin이 다운된 경우 캐시된 Content Delivering
4. 캐시 미세 조정 및 성능 향상
5. 여러 하드 드라이브에 캐시 분할
1. 개요
콘텐츠 캐시는 클라이언트와 “Origin 서버” 사이에 위치하며 보이는 모든 콘텐츠의 복사본을 저장합니다. 클라이언트가 캐시에 저장된 콘텐츠를 요청하면 Origin 서버에 연결하지 않고 직접 콘텐츠를 반환합니다. 이렇게 하면 콘텐츠 캐시가 클라이언트에 더 가깝기 때문에 성능이 향상되고 매번 처음부터 페이지를 생성하는 작업을 수행할 필요가 없기 때문에 애플리케이션 서버를 보다 효율적으로 사용합니다.
웹 브라우저와 애플리케이션 서버 사이에는 클라이언트의 브라우저 캐시, 중간 캐시, CDN(Content Delivery Networks), 애플리케이션 서버 앞에 있는 로드 밸런서 또는 리버스 프록시와 같은 잠재적으로 여러 캐시가 있습니다. 리버스 프록시/로드 밸런서 수준에서도 캐싱은 성능을 크게 향상시킬 수 있습니다.
예를 들어 작년에 느리게 로딩되는 웹사이트의 성능 조정 작업을 맡았습니다. 가장 먼저 눈에 띄는 것은 메인 홈페이지를 생성하는 데 1초 이상이 걸렸다는 것입니다. 일부 디버깅 후에 페이지가 캐시할 수 없는 것으로 표시되어 각 요청에 대한 응답으로 동적으로 생성된다는 것을 발견했습니다. 페이지 자체는 자주 변경되지 않고 개인화되지 않았기 때문에 이것이 필요하지 않았습니다. 실험으로 홈페이지에 로드밸런서가 5초 동안 캐싱하도록 표시해 보았는데, 그렇게 하는 것만으로도 눈에 띄게 개선되었습니다. 첫 번째 바이트까지의 시간은 몇 밀리초로 줄어들었고 페이지는 눈에 띄게 빠르게 로드되었습니다.
NGINX는 일반적으로 애플리케이션 스택에서 리버스 프록시 또는 로드 밸런서로 배포되며 전체 캐싱 기능 세트를 갖추고 있습니다. 다음 섹션에서는 NGINX로 기본 캐싱을 구성하는 방법에 대해 설명합니다.
2. 기본 캐싱을 설정 및 구성하는 방법
기본 캐싱을 활성화하려면 proxy_cache_path 및 proxy_cache의 두 가지 지시문만 필요합니다. proxy_cache_path 지시자는 캐시의 경로와 구성을 설정하고 proxy_cache 지시자는 이를 활성화합니다.
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
inactive=60m use_temp_path=off;
server {
# ...
location / {
proxy_cache my_cache;
proxy_pass http://my_upstream;
}
}
proxy_cache_path 지시문에 대한 매개변수는 다음 설정을 정의합니다.
- 캐시의 로컬 디스크 디렉토리는 /path/to/cache/입니다.
- levels은 /path/to/cache/ 아래에 2단계 디렉터리 계층 구조를 설정합니다. 단일 디렉터리에 많은 수의 파일이 있으면 파일 액세스 속도가 느려질 수 있으므로 대부분의 배포에 2단계 디렉터리 계층 구조를 사용하는 것이 좋습니다. 수준 매개 변수가 포함되지 않은 경우 NGINX는 모든 파일을 동일한 디렉터리에 넣습니다.
- keys_zone은 캐시 키 및 사용 타이머와 같은 메타데이터를 저장하기 위한 공유 메모리 영역을 설정합니다. 메모리에 키 복사본이 있으면 NGINX에서 디스크로 이동할 필요 없이 요청이 HIT인지 MISS인지 빠르게 결정할 수 있어 검사 속도가 크게 빨라집니다. 1MB 영역은 약 8,000개의 키에 대한 데이터를 저장할 수 있으므로 예제에서 구성된 10MB 영역은 약 80,000개의 키에 대한 데이터를 저장할 수 있습니다.
- max_size는 캐시 크기의 상한을 설정합니다(이 예에서는 10GB). 선택 사항입니다. 값을 지정하지 않으면 캐시가 사용 가능한 모든 디스크 공간을 사용하도록 확장됩니다. 캐시 크기가 제한에 도달하면 캐시 관리자라는 프로세스가 캐시 크기를 제한 아래로 되돌리기 위해 가장 최근에 사용된 파일을 제거합니다.
- inactive는 항목이 액세스되지 않고 캐시에 남아 있을 수 있는 기간을 지정합니다. 이 예에서 60분 동안 요청되지 않은 파일은 만료 여부에 관계없이 캐시 관리자 프로세스에 의해 캐시에서 자동으로 삭제됩니다. 기본값은 10분(10m)입니다. 비활성 콘텐츠는 만료된 콘텐츠와 다릅니다. NGINX는 캐시 제어 헤더(예: Cache-Control:max-age=120)에 정의된 대로 만료된 콘텐츠를 자동으로 삭제하지 않습니다. 만료된(부실) 콘텐츠는 inactive로 지정된 시간 동안 액세스하지 않은 경우에만 삭제됩니다. 만료된 콘텐츠에 액세스하면 NGINX는 Origin 서버에서 콘텐츠를 새로 고치고 비활성 타이머를 재설정합니다.
- NGINX는 먼저 캐시로 향하는 파일을 임시 저장 영역에 기록하고 use_temp_path=off 지시문은 NGINX에 해당 파일이 캐시될 동일한 디렉터리에 쓰도록 지시합니다. 파일 시스템 간에 불필요한 데이터 복사를 방지하려면 이 매개변수를 off로 설정하는 것이 좋습니다. use_temp_path는 NGINX 버전 1.7.10 및 NGINX Plus R6에서 도입되었습니다.
마지막으로 proxy_cache 지시문은 상위 위치 블록의 URL(예: /)과 일치하는 모든 콘텐츠의 캐싱을 활성화합니다. 서버 블록에 proxy_cache 지시문을 포함할 수도 있습니다. 자체 proxy_cache 지시문이 없는 서버의 모든 위치 블록에 적용됩니다.
3. Origin이 다운된 경우 캐시된 Content Delivering
NGINX 콘텐츠 캐싱의 강력한 기능은 Origin 서버에서 새로운 콘텐츠를 가져올 수 없을 때 캐시에서 오래된 콘텐츠를 전달하도록 NGINX를 구성할 수 있다는 것입니다. 이것은 캐시된 리소스의 모든 Origin 서버가 다운되거나 일시적으로 사용 중인 경우 발생할 수 있습니다. 오류를 클라이언트에 전달하는 대신 NGINX는 캐시에서 오래된 버전의 파일을 전달합니다. 이는 NGINX가 프록시하는 서버에 대해 추가 수준의 내결함성을 제공하고 서버 오류 또는 트래픽 급증 시 가동 시간을 보장합니다. 이 기능을 활성화하려면 proxy_cache_use_stale 지시문을 포함하십시오:
location / {
# ...
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}
이 샘플 구성을 사용하면 NGINX가 Origin 서버로부터 오류, 시간 초과 또는 지정된 5xx 오류를 수신하고 캐시에 요청된 파일의 오래된 버전이 있는 경우 클라이언트에 오류를 전달하는 대신 오래된 파일을 전달합니다.
4. 캐시 미세 조정 및 성능 향상
NGINX에는 캐시 성능을 미세 조정하기 위한 다양한 옵션 설정이 있습니다. 다음은 그 중 몇 가지를 활성화하는 예입니다.
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
inactive=60m use_temp_path=off;
server {
# ...
location / {
proxy_cache my_cache;
proxy_cache_revalidate on;
proxy_cache_min_uses 3;
proxy_cache_use_stale error timeout updating http_500 http_502
http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
proxy_pass http://my_upstream;
}
}
이러한 지시문은 다음 동작을 구성합니다.
- proxy_cache_revalidate는 Origin 서버에서 콘텐츠를 새로 고칠 때 조건부 GET 요청을 사용하도록 NGINX에 지시합니다. 클라이언트가 캐시 제어 헤더에 정의된 대로 캐시되었지만 만료된 항목을 요청하는 경우 NGINX는 원본 서버에 보내는 GET 요청 헤더에 If-Modified-Since 필드를 포함합니다. NGINX가 원래 캐시했을 때 파일에 첨부된 Last-Modified 헤더에 기록된 시간 이후에 수정된 경우에만 서버가 전체 항목을 전송하기 때문에 대역폭이 절약됩니다.
- proxy_cache_min_uses는 NGINX가 캐시하기 전에 클라이언트가 항목을 요청해야 하는 횟수를 설정합니다. 이것은 가장 자주 액세스하는 항목만 캐시에 추가되도록 하므로 캐시가 계속 채워지는 경우에 유용합니다. 기본적으로 proxy_cache_min_uses는 1로 설정됩니다.
- proxy_cache_use_stale 지시문에 대한 업데이트 매개변수는 proxy_cache_background_update 지시문 활성화와 결합되어 클라이언트가 만료되었거나 원본 서버에서 업데이트 중인 항목을 요청할 때 NGINX에 오래된 콘텐츠를 전달하도록 지시합니다. 모든 업데이트는 백그라운드에서 수행됩니다. 업데이트된 파일이 완전히 다운로드될 때까지 모든 요청에 대해 오래된 파일이 반환됩니다.
- proxy_cache_lock이 활성화된 상태에서 여러 클라이언트가 현재 캐시에 없는 파일(MISS)을 요청하는 경우 해당 요청 중 첫 번째 요청만 Origin 서버를 통과할 수 있습니다. 나머지 요청은 해당 요청이 충족될 때까지 기다린 다음 캐시에서 파일을 가져옵니다. proxy_cache_lock이 활성화되지 않으면 캐시 누락을 초래하는 모든 요청이 Origin 서버로 바로 이동합니다.
5. 여러 하드 드라이브에 캐시 분할
하드 드라이브가 여러 개인 경우 NGINX를 사용하여 하드 드라이브 간에 캐시를 분할할 수 있습니다. 다음은 요청 URI를 기반으로 두 개의 하드 드라이브에 균등하게 클라이언트를 분할하는 예입니다.
proxy_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m
max_size=10g inactive=60m use_temp_path=off;
proxy_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m
max_size=10g inactive=60m use_temp_path=off;
split_clients $request_uri $my_cache {
50% “my_cache_hdd1”;
50% “my_cache_hdd2”;
}
server {
# ...
location / {
proxy_cache $my_cache;
proxy_pass http://my_upstream;
}
}
두 개의 proxy_cache_path 지시문은 두 개의 다른 하드 드라이브에 두 개의 캐시(my_cache_hdd1 및 my_cache_hdd2)를 정의합니다. split_clients 구성 블록은 요청의 절반(50%)의 결과가 my_cache_hdd1에 캐시되고 나머지 절반은 my_cache_hdd2에 캐시되도록 지정합니다. $request_uri 변수(요청 URI)를 기반으로 하는 해시는 각 요청에 사용되는 캐시를 결정하며, 그 결과 주어진 URI에 대한 요청이 항상 동일한 캐시에 캐시됩니다.
이 접근 방식은 RAID 하드 드라이브 설정을 대체하지 않습니다. 하드 드라이브 오류가 있는 경우 사용자에게 오류가 발생한 하드 드라이브로 전달된 요청에 대해 500개의 응답 코드가 표시되는 등 시스템에서 예측할 수 없는 동작이 발생할 수 있습니다. 적절한 RAID 하드 드라이브 설정은 하드 드라이브 오류를 처리할 수 있습니다.