본문 바로가기
미디어위키

Manual Varnish caching

by 다움위키 2024. 1. 2.

바니쉬(Varnish) 자주-요청되는 페이지를 제공하기 위해 걸리는 시간을 줄여주는 가볍고, 효율적인 역방향 프록시 서버입니다.
바니쉬는 웹 서버에서 제공되는 페이지의 사본을 저장하는 HTTP 가속기입니다. 다음에 같은 페이지가 요청되면, 바니쉬는 웹 서버에서 페이지를 요청하는 대신에 사본을 제공할 것입니다. 이 캐싱 과정은 미디어위키가 같은 페이지를 다시 생성할 필요를 제거하며, 엄청난 성능 향상을 가져옵니다.
바니쉬는 HTTP 가속기 (역방향 프록시)로 사용하도록 특별히 설계된 이점을 가집니다. 그것은 캐시된 데이터의 대부분을 메모리에 저장하며, 더 크고, 보다 여러-목적 스퀴드(squid) 패키지보다 파일시스템에 대한 더 적은 디스크 파일과 더 적은 접근을 생성합니다. 스퀴드와 마찬가지로, 그것은 자주 요청되는 페이지를 원래 웹 서버에서 그것들을 요청하는 대신에 캐시에서 익명-IP 사용자에게 제공합니다. 이것은 기본 미디어위키 서버에 의한 CPU 사용량과 데이터베이스 접근을 감소시킵니다.
이 성능 향상때문에, 미디어위키는 웹 캐시와 밀접하게 통합되도록 설계되었고 페이지가 다시 생성되기 위해 캐시에서 제거되어야만 할 때 스퀴드 또는 바니쉬에 알릴 것입니다.
미디어위키의 관점에서, 올바르게-구성된 바니쉬 설치는 그것의 스퀴드 짝과 교환-가능합니다.

The architecture

단일 서버에서 바니쉬, 아파치 및 미디어위키의 예제 설정은 아래에 요약되어 있습니다. 보다 복잡한 캐싱 전략은 같은 바니쉬 캐시 뒤에 있는 여러 웹 서버를 사용하거나 (모두 단일 호스트로 보이도록 만들 수 있음) 독립적인 서버를 위키 또는 이미지 콘텐츠를 제공하기 위해 사용할 수 있습니다.

  서버
외부 세계<--->바니쉬 가속기
w.x.y.z:80
<--->엔진-엑스 웹서버
127.0.0.1:80

외부 세계로, 바니쉬가 웹 서버 역할을 하는 것처럼 보입니다. 실제로는, 그것은 엔진-엑스 웹 서버에 요청을 전달하지만, 오직 필요한 때 전달합니다. 같은 서버에서 실행되는 엔진-엑스는 오직 localhost (127.0.0.1)의 요청을 수신하지만, 바니쉬는 오직 서버의 외부 IP 주소에 대한 요청을 수신합니다. 두 서비스 모두는 각각이 다른 IP 주소에 바인딩될 때 충돌 없이 포트 80에서 실행됩니다.

Configuring Varnish

다음 구성은 바니쉬 버전 4와 윗 버전에서 작동합니다.

vcl 4.0;
# set default backend if no server cluster specified
backend default {
    .host = "127.0.0.1";
    .port = "8080";
    # .port = "80" led to issues with competing for the port with apache.
}

# access control list for "purge": open to only localhost and other local nodes
acl purge {
    "127.0.0.1";
}

# vcl_recv is called whenever a request is received 
sub vcl_recv {
        # Serve objects up to 2 minutes past their expiry if the backend
        # is slow to respond.
        # set req.grace = 120s;

        set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;

        set req.backend_hint= default;
 
        # This uses the ACL action called "purge". Basically if a request to
        # PURGE the cache comes from anywhere other than localhost, ignore it.
        if (req.method == "PURGE") {
            if (!client.ip ~ purge) {
                return (synth(405, "Not allowed."));
            } else {
                return (purge);
            }
        }
        
        # Pass requests from logged-in users directly.
        # Only detect cookies with "session" and "Token" in file name, otherwise nothing get cached.
        if (req.http.Authorization || req.http.Cookie ~ "session" || req.http.Cookie ~ "Token") {
            return (pass);
        } /* Not cacheable by default */
 
        # normalize Accept-Encoding to reduce vary
        if (req.http.Accept-Encoding) {
          if (req.http.User-Agent ~ "MSIE 6") {
            unset req.http.Accept-Encoding;
          } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
          } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
          } else {
            unset req.http.Accept-Encoding;
          }
        }
 
        return (hash);
}

sub vcl_pipe {
        # Note that only the first request to the backend will have
        # X-Forwarded-For set.  If you use X-Forwarded-For and want to
        # have it set for all requests, make sure to have:
        # set req.http.connection = "close";
 
        # This is otherwise not necessary if you do not do any request rewriting.
 
        set req.http.connection = "close";
}

# Called if the cache has a copy of the page.
sub vcl_hit {
        if (!obj.ttl > 0s) {
            return (pass);
        }

        # Force lookup if the request is a no-cache request from the client.
        if (req.http.Cache-Control ~ "no-cache") {
            return (miss);
        }
}

# Called after a document has been successfully retrieved from the backend.
sub vcl_backend_response {
       if (beresp.ttl < 48h) {
          set beresp.ttl = 48h;
        }       
 
        if (!beresp.ttl > 0s) {
          set beresp.uncacheable = true;
          return (deliver);
        }
 
        if (beresp.http.Set-Cookie) {
          set beresp.uncacheable = true;
          return (deliver);
        }
 
#       if (beresp.http.Cache-Control ~ "(private|no-cache|no-store)") {
#          set beresp.uncacheable = true;
#          return (deliver);
#        }
 
        if (beresp.http.Authorization && !beresp.http.Cache-Control ~ "public") {
          set beresp.uncacheable = true;
          return (deliver);
        }

        return (deliver);
}

Configuring MediaWiki

바니쉬는 로컬호스트에서 요청을 수행하므로, 엔진-엑스는 직접 원격 주소로 "127.0.0.1"을 수신할 것입니다. 어쨌든, 바니쉬가 엔진-엑스에 요청을 전달할 때, 그것은 외부 세계에서 원격 주소가 보존되도록 "X-Forwarded-For" 헤더를 더하기 위해 구성됩니다. 미디어위키는 special:recentchanges에서 사용자 주소를 올바르게 표시하기 위해 "X-Forwarded-For" 헤더를 사용하기 위해 구성되어야 합니다.
필요한 구성은 스퀴드에 대한 것과 바니쉬에 대한 것과 같습니다. LocalSettings.php 파일에 다음 행이 포함되어 있는지 확인하십시오:

$wgUseCdn = true;
$wgCdnServers = array();
$wgCdnServers[] = "127.0.0.1";
$wgCdnServers[] = "192.168.0.1";
//Use $wgCdnServersNoPurge if you don't want MediaWiki to purge modified pages
//$wgCdnServersNoPurge[] = "192.168.0.2";

'192.168.0.1'을 바니쉬 캐시가 수신하는 IP 주소로 바꾸십시오. 이들 설정은 두 가지 용도로 사용됩니다:

  • 만약 요청이 바니쉬 캐시 서버에서 수신되면, 미디어위키 로그는 바니쉬의 IP 주소가 아닌 사용자의 IP 주소를 표시해야 합니다. 모든 각 편집이 '127.0.0.1'로 보고되는 special:recentchanges은 거의 쓸모가 없습니다; 해당 주소를 스퀴드/바니쉬 서버로 나열하면 미디어 위에 IP 주소를 무시하고 대신에 사용자의 IP에 대한 'x-forwarded-for' 헤더를 확인합니다.
  • 만약 페이지 또는 이미지가 위기에서 변경되면, 미디어위키는 $wgCdnServers에 나열된 모든 각 서버에 오래된 저장된 페이지를 삭제 (제거)하기 위해 그것을 말하는 알림을 보냅니다.

최근-변경사항(recentchanges)에서 보관해야 하지만 HTTP PURGE 메시지를 받지 않는 주소에 대해 $wgCdnServersNoPurge를 사용하십니다. 예를 들어, 엔진-엑스와 바니쉬가 같은 기계에서 127.0.0.1와 외부 주소가 있으면, 바니쉬를 위한 "purge" 메시지를 엔지-엑스에 보낼 필요가 없습니다. 마찬가지로, 만약 바니쉬가 여러 주소를 수신하면, 오직 그중 하나에 "purge"를 보냅니다.
역시 스퀴드/바니쉬 캐싱과 관련된 모든 설정에 대해 스퀴드 구성 설정(Squid configuration settings)을 참조하십시오.

Some notes

바니쉬가 스퀴드의 대안이지만, 다음과 같은 완전한 미디어위키 캐싱 전략(caching strategy)의 다른 부분을 대체하지는 않습니다:
미리-컴파일된 PHP 코드 엔진-엑스 아래에서 PHP의 기본 동작은 그것들이 접근되는 매 순간마다 PHP 웹 스크립트를 로드하고 해석하는 것입니다. APC와 같은 캐시 설치를 설치는 (sudo apt install php-pecl-apc, 그러-다음 apc.shm_size=128를 설정함으로써 메모리를 할당하십시오 또는 /etc/php.d/apc.ini에서 설정하십시오) PHP 콘텐츠를 제공하기 위해 엔진-엑스에 의해 요구된 CPU 시간의 총량을 크게 줄일 수 있습니다. 지역화/국제화 기본값으로, 미디어위키는 거대한 l10n_cache 데이터베이스 테이블을 생성하고 그것을 지속적으로 접근할 것입니다 – 아마도 최신 미디어위키 버전으로 "업그레이드"한 후 데이터베이스 서버의 부하를 두 배보다 더 늘릴 수 있습니다. 이 문제를 해결하기 위해 지역화 정보를 파일 시스템에 강제로 저장하기 위해 $wgLocalisationCacheConf를 설정하십시오. 변수와 세션 데이터 미디어위키 사이드바, 이름공간 목록 또는 스팸 블랙리스트와 같은 변수 데이터를 메모리 캐시에 저장하는 것은 미디어위키 설치 속도의 크게 향상시킬 것입니다. 사용자 로그인 데이터를 공통 위치에 저장되도록 강제하는 것은 역시 같은 위키에 대한 페이지를 제공하기 위한 같은 바니쉬 캐시 뒤에 여럿의 교환-가능한 엔진-엑스 서버가 숨겨져 있는 임의의 설치에 필수적입니다. memcached 패키지를 설치하고 LocalSettings.php에서 다음 옵션을 설정하여 사용자 로그인 정보와 캐시된 변수 모두를 memcache를 사용하도록 강제합니다: $wgMainCacheType = CACHE_MEMCACHED; $wgMemCachedServers = [ '127.0.0.1:11211' ]; $wgSessionsInObjectCache = true; 만약 여러 서버를 가지면, 로컬호스트 주소는 공유된 memcached 서버의 주소로 대체될 필요가 있으며, 이것은 사이트에서 일치하는 모든 웹 서버에 대해 같아야 함에 주목하십시오. 이것은 클러스터에서 한 서버에 사용자를 로그인하는 것이 모든 교환-가능한 웹 서버에 동작중인 위키에 사용자가 로그인된 것임을 보장합니다.
많은 경우에서, 같은 결과를 생성하는 여러 대안적인 캐싱 접근 방법이 있습니다. Manual:Cache를 참조하십시오.

Apache configuration

Log file

아파치 웹 서버 로그는, 기본값으로, 오직 바니쉬 캐시 서버, 이 예제에서 "127.0.0.1:80"의 주소를 보여줍니다.
아파치는 사용자-정의 로그 파일 형식 아래에서 "x-forwarded-for" 정보를 포획함으로써 원래 사용자의 주소를 기록하도록 구성할 수 있습니다.
아파치의 httpd.conf에 대해 x-forwarded-for의 로그인을 구성하기 위한 예제는 다음입니다:
LogFormat "%{X-Forwarded-for}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" cached

Image hotlinking

만약 사이트가 다른 웹 사이트의 이미지 핫 링크 시도를 차단하기 위해 아파치의 mod_rewrite를 사용하면, 이 구성은 제거될 필요가 있고 동등한 구성을 바니쉬의 구성 파일에 더할 필요가 있습니다. 이미지 서버가 바니쉬 뒤에 위치되는 곳에서, 전형적으로 공통적인 이미지 요청의 90% 이상이 아파치에 도달하지 않고 따라서 아파치의 구성에서 "http_referer" 검사에 의해 차단되지 않을 것입니다.

See also