스퀴드와 바니쉬 중에 어떤 것을 선택할지 고민이 되기도 합니다. 여기의 투표를 보면, 압도적으로 바니쉬를 많이 사용하는 것으로 집계가 되었습니다. 어쨌든, 오픈-소스 바니쉬는 SSL/TLS를 지원하지 않고, 상대적으로 많은 CPU와 메모리 자원을 차지합니다. 이것을 해결하는 방법은 Varnish (software)/SSL Redirect with Nginx 또는 HAProxy 등이 있습니다. 단지 전자의 경우는 문제가 있습니다.
바니쉬(Varnish)는 컨텐츠가 많은 동적 웹 사이트와 마찬가지로 API에 대해 설계된 HTTP 가속기입니다. 클라이언트-측 캐시로 수명을 시작했든 스퀴드, 또는 주로 원본 서버인, 아파치와 nginx엔진엑스]]와 같은 다른 웹 가속기와 대조적으로, 바니쉬는 HTTP 가속기로 설계되었습니다. 바니쉬는, 종종 FTP, SMTP 및 다른 네트워크 프로토콜을 지원하는 다른 프록시 서버와 달리 HTTP에 독점적으로 집중합니다.
바니쉬는 위키피디아를 포함하는 웹-사이트, The New York Times, The Guardian, The Hindu, Corriere della Sera와 같은 온라인 신문 사이트, Facebook, Twitter, Reddit, Vimeo, 및 Tumblr과 같은 소셜 미디어와 컨텐츠 사이트에서 사용됩니다. 2012년 웹 사이트의 상위 10,000개 사이트 중 5%가 이 소프트웨어를 사용했습니다.
Introduction
바니쉬는 웹 캐시 및 HTTP 가속기로써, 캐시된 컨텐츠를 제공하거나, 또는 서버에서 컨텐츠를 검색하여 캐시할 수 있습니다. 이렇게 하면, 많은 클라이언트에게 서비스를 제공하거나 많은 요청을 하는 웹 서버의 I/O 부담을 줄일 수 있습니다.
Installation
데비안 저장소에서 설치할 수 있습니다:
- sudo apt install varnish
다음 명령으로 설치 상태를 확인할 수 있습니다:
- ss -tlnf inet
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 1000 0.0.0.0:6081 0.0.0.0:*
LISTEN 0 10 127.0.0.1:6082 0.0.0.0:*
결과로부터, 엔진엑스 서버가 포트 80에서 청취하고 있고, 바니쉬는 6081 및 6082 포트를 모두 사용하고 있음을 알 수 있습니다.
Configure Nginx Server
엔진엑스 서버의 역할은 바니쉬 캐시 서버 뒤에 놓을 것이기 때문에, 기본 포트 80을 다른 포트로 할당하도록 /etc/nginx/site-available/default를 수정합니다.
server {
# listen 80 default_server;
# listen [::]:80 default_server;
listen 8080 default_server;
listen [::]:8080 default_server;
엔진엑스를 재시작합니다:
- sudo systemctl restart nginx
제대로 포트가 바뀌었는지 확인을 합니다.
- ss -tlnf inet
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 511 0.0.0.0:8080 0.0.0.0:*
LISTEN 0 1000 0.0.0.0:6081 0.0.0.0:*
LISTEN 0 10 127.0.0.1:6082 0.0.0.0:*
Setup Varnish Cache Server
엔진엑스로 접근하면, 바니쉬 캐시 서버를 통해 트래픽을 라우팅하기 위해서, 바니쉬 캐시 서버의 포트를 80번으로 수신 대기하도록 변경해야 합니다. 이렇게 하려면 systemd 구성 파일 /lib/systemd/system/varnish.service를 수정해야 합니다. 바니쉬가 사용하던 6081 포트를 80 포트로 바꾸어 줍니다:
[Unit]
Description=Varnish HTTP accelerator
Documentation=https://www.varnish-cache.org/docs/5.2/ man:varnishd
[Service]
Type=simple
LimitNOFILE=131072
LimitMEMLOCK=82000
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a localhost:80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m
ExecReload=/usr/share/varnish/varnishreload
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
[Install]
WantedBy=multi-user.target
이제 엔진엑스에서 사용하는 8080 포트를 바니쉬 설정에서 변경해 주어야 합니다. 이를 수정할 때에, 엔진엑스와 바니쉬가 같은 호스트일 경우에는 127.0.0.1을 사용하고, 그렇지 않으면, 엔진엑스 서버의 ip 주소를 /etc/varnish/default.vcl를 수정해 주어야 합니다:
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
이제, systemd 데몬을 reload하고 바니쉬 캐시 서버를 재시작합니다:
- sudo systemctl daemon-reload
- sudo service varnish restart
모든 설정이 끝났습니다. 마지막으로 설정이 제대로 동작하는지 확인을 합니다:
- ss -tlnf inet
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 1000 0.0.0.0:80 0.0.0.0:*
LISTEN 0 511 0.0.0.0:8080 0.0.0.0:*
LISTEN 0 10 127.0.0.1:6082 0.0.0.0:*
Testing Varnish Cache Server
바니쉬 캐시 서버 구성을 테스트하는 가장 간단한 방법은 curl 명령을 사용하는 것입니다. 자신의 호스트명을 통해 바니쉬 캐시 서버 IP 주소를 확인할 수 있습니다:
- curl -I dawoum.duckdns.org
HTTP/1.1 301 Moved Permanently
Server: nginx/1.14.0 (Ubuntu)
Date: Mon, 07 May 2018 20:45:04 GMT
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff
Vary: Accept-Encoding, Cookie
Cache-Control: s-maxage=1200, must-revalidate, max-age=0
Last-Modified: Mon, 07 May 2018 20:45:04 GMT
Location: http://dawoum.duckdns.org/wiki/Main_Page
X-Varnish: 65560 3
Age: 164
Via: 1.1 varnish (Varnish/5.2)
Connection: keep-alive
결과에서 Via: 1.1 varnish (Varnish/5.2)를 볼 수 있습니다.
다음으로, 호스트명으로 웹브라우저에서 URL http://dawoum.duckdns.org로 접근해 봅니다. 정상적으로 출력되지 않을 경우에는 설정을 확인해야 합니다.
잘 작동하고 있다면, varnishstat 명령을 사용하여 바니쉬 캐싱 통계를 확인할 수 있습니다:
- sudo varnishstat
HAProxy 설정 후에 통계입니다.
MGT.uptime 1+02:33:08
MAIN.uptime 1+02:33:09
MAIN.sess_conn 61215 0.00 0.64
MAIN.client_req_400 1 0.00 0.00
MAIN.client_req 112791 0.00 1.18
MAIN.cache_hit 24574 0.00 0.26
MAIN.cache_hit_grace 4941 0.00 0.05
MAIN.cache_hitmiss 311 0.00 0.00
MAIN.cache_miss 37183 0.00 0.39
MAIN.backend_conn 7344 0.00 0.08
MAIN.backend_reuse 84070 0.00 0.88
MAIN.backend_recycle 91384 0.00 0.96
MAIN.fetch_length 76630 0.00 0.80
MAIN.fetch_chunked 14484 0.00 0.15
Varnish setting from MediaWiki
미디어위키에서 추천하는 설정을 추가해 줍니다. 5.x에 대한 부분이 없기 때문에, 가장 가까운 버전 설정을 /etc/varnish/default.vcl를 추가합니다.
# 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 any requests that Varnish does not understand straight to the backend.
if (req.method != "GET" && req.method != "HEAD" &&
req.method != "PUT" && req.method != "POST" &&
req.method != "TRACE" && req.method != "OPTIONS" &&
req.method != "DELETE") {
return (pipe);
} /* Non-RFC2616 or CONNECT which is weird. */
# Pass anything other than GET and HEAD directly.
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
} /* We only deal with GET and HEAD by default */
# 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 */
# Pass any requests with the "If-None-Match" header directly.
if (req.http.If-None-Match) {
return (pass);
}
# Force lookup if the request is a no-cache request from the client.
if (req.http.Cache-Control ~ "no-cache") {
ban(req.url);
}
# 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 (req.method == "PURGE") {
ban(req.url);
return (synth(200, "Purged"));
}
if (!obj.ttl > 0s) {
return (pass);
}
}
# Called if the cache does not have a copy of the page.
sub vcl_miss {
if (req.method == "PURGE") {
return (synth(200, "Not in cache"));
}
}
# Called after a document has been successfully retrieved from the backend.
sub vcl_backend_response {
# set minimum timeouts to auto-discard stored objects
set beresp.grace = 120s;
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);
}
External Resources
- https://github.com/miraheze/puppet/blob/master/modules/varnish/templates/default.vcl
- https://wiki.gentoo.org/wiki/Varnish
- https://linuxconfig.org/how-to-install-varnish-cache-server-with-nginx-on-ubuntu-18-04-bionic-beaver-linux
- https://devdocs.magento.com/guides/v2.0/config-guide/varnish/tshoot-varnish-503.html
- https://stackshare.io/stackups/squid-vs-varnish