Varnish Cache és un accelerador d'aplicacions web, s'instal·la davant de qualsevol servidor HTTP i es configura per emmagatzemar a la memòria cau del servidor una còpia del recurs sol·licitat. Magento 2 té mecanismes de memòria cau incorporats i el sistema de memòria cau de pàgina completa té suport natiu per a Varnish.
Aquest article és una guia pas a pas sobre com configurar Varnish per a la Imatge preinstal·lada de Magento 2.
Instal·lació de Varnish
El repositori d'Ubuntu incorpora el paquet de Varnish, no cal afegir el repositori oficial ni de tercers per instal·lar-lo. Directament pots executar:
# apt install varnish -yActualment obtindràs la versió Varnish 6.2.1 i és compatible amb el Magento de la imatge preinstal·lada. Pots comprovar la versió instal·lada des del repositori executant el següent:
# varnishd -VHauria d'aparèixer el resultat següent:
varnishd (varnish-6.2.1 revision 9f8588e4ab785244e06c3446fe09bf9db5dd8753)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2019 Varnish Software ASConfiguració de Varnish i Magento
Un cop instal·lat, caldrà modificar la configuració per defecte. Edita el fitxer del servei Varnish de systemd:
# nano /lib/systemd/system/varnish.serviceNomés has de modificar el port per defecte (6081) pel port HTTP (80) i augmentar el límit de mida de la memòria cau. Hauria de quedar semblant al següent:
[Unit]
Description=Varnish Cache, a high-performance HTTP accelerator
After=network-online.target nss-lookup.target
[Service]
Type=forking
KillMode=process
# Nombre màxim de fitxers oberts (per a ulimit -n)
LimitNOFILE=131072
# Memòria compartida blocada - hauria de ser suficient per blocar el registre de memòria compartida
# (argument varnishd -l)
# La mida del registre per defecte és de 80MB vsl + 1M vsm + capçalera -> 82MB
# la unitat és bytes
LimitMEMLOCK=85983232
# Activa això per evitar "fork failed" en tornar a carregar.
TasksMax=infinity
# Mida màxima del fitxer de bolcat de memòria.
LimitCORE=infinity
ExecStart=/usr/sbin/varnishd \
-a :80 \
-a localhost:8443,PROXY \
-p feature=+http2 \
-f /etc/varnish/default.vcl \
-s malloc,2g
ExecReload=/usr/sbin/varnishreload
[Install]
WantedBy=multi-user.targetUn cop afegida la configuració, bloca el fitxer perquè no pugui ser modificat per alguna actualització del paquet de Varnish:
# chattr +i /lib/systemd/system/varnish.serviceUn cop modificat i blocat, pots configurar-lo a Magento a Stores, Configuration, Advanced, System i desplegar l'apartat Full Page Cache:
Desmarca les caselles d'utilitzar els valors del sistema per seleccionar Varnish Cache, descarregar-te el VCL de la versió corresponent i desa els canvis.
Configuració de NGINX i implementació de Varnish
La imatge preinstal·lada utilitza NGINX com a servidor web, però pots implementar-lo en qualsevol servidor web. Per tant, abans d'implementar Varnish, canvia el port HTTP d'escolta per defecte de NGINX per 8080 TCP editant el fitxer del lloc:
# nano /etc/nginx/sites-enabled/defaultSubstitueix el valor de listen:
listen 8080;Introdueix també el domini o subdomini del teu lloc a server_name:
server_name ejemplo.com;I afegeix health_check a la línia del location de php:
location ~ (index|get|static|report|404|503|health_check)\.php$ {Un cop desats els canvis, reinicia el servei per aplicar els canvis:
# systemctl restart nginx.serviceComprova que el port s'ha canviat:
# ss -tulpn | grep nginxHa d'aparèixer el següent:
tcp LISTEN 0 511 0.0.0.0:8080 0.0.0.0:* users:(("nginx",pid=50572,fd=6),("nginx",pid=50571,fd=6))Un cop descarregat el VCL, substitueix l'actual pel descarregat i afegeix-hi el port configurat de NGINX:
# rm /etc/varnish/default.vcl && nano /etc/varnish/default.vclPots copiar directament el següent, ja configurat: El comentari de bloc indica que les peticions no conformes a l'RFC esmentat o amb CONNECT són estranyes.
# La versió 5.0 de VCL no és compatible, per tant ha de ser 4.0 encara que la versió de Varnish utilitzada sigui la 6
vcl 4.0;
import std;
# La versió mínima de Varnish és 6.0
# per a la delegació del processament SSL, passa la capçalera següent al teu servidor intermediari o equilibrador de càrrega: 'X-Forwarded-Proto: https'
backend default {
.host = "127.0.0.1";
.port = "8080";
.first_byte_timeout = 600s;
.probe = {
.url = "health_check.php";
.timeout = 2s;
.interval = 5s;
.window = 10;
.threshold = 5;
}
}
acl purge {
}
sub vcl_recv {
if (req.restarts > 0) {
set req.hash_always_miss = true;
}
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
# Per utilitzar la capçalera X-Pool per purgar varnish durant els desplegaments automatitzats, assegura't que la capçalera X-Pool
# s'ha afegit a la resposta a la configuració del servidor de rerefons. Això ho utilitza, per exemple, la
# gem capistrano-magento2 per purgar contingut antic de varnish durant la seva rutina de desplegament.
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required"));
}
if (req.http.X-Magento-Tags-Pattern) {
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
}
if (req.http.X-Pool) {
ban("obj.http.X-Pool ~ " + req.http.X-Pool);
}
return (synth(200, "Purged"));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# Per defecte només tractem GET i HEAD
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Omet la memòria cau per al carretó de compra i la finalització de la compra
if (req.url ~ "/checkout") {
return (pass);
}
# Omet la memòria cau per a les peticions de comprovació d'estat
if (req.url ~ "/pub/health_check.php") {
return (pass);
}
# Estableix l'estat inicial d'ús del període de gràcia
set req.http.grace = "none";
# normalitza l'url si comença amb l'esquema HTTP i el domini
set req.url = regsub(req.url, "^http[s]?://", "");
# recull totes les galetes
std.collect(req.http.Cookie);
# Filtre de compressió. Consulta https://www.varnish-cache.org/trac/wiki/FAQ/Compression
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|flv)$") {
# No té sentit comprimir aquests fitxers
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate" && req.http.user-agent !~ "MSIE") {
set req.http.Accept-Encoding = "deflate";
} else {
# algorisme desconegut
unset req.http.Accept-Encoding;
}
}
# Elimina tots els paràmetres get de màrqueting per minimitzar els objectes de la memòria cau
if (req.url ~ "(\?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") {
set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
set req.url = regsub(req.url, "[?|&]+$", "");
}
# Emmagatzematge de fitxers estàtics a la memòria cau
if (req.url ~ "^/(pub/)?(media|static)/") {
# Els fitxers estàtics no s'han d'emmagatzemar a la memòria cau per defecte
return (pass);
# Però si utilitzes poques configuracions regionals i no utilitzes CDN pots activar l'emmagatzematge de fitxers estàtics a la memòria cau comentant la línia anterior (#return (pass);) i descomentant les 3 línies següents
#unset req.http.Https;
#unset req.http.X-Forwarded-Proto;
#unset req.http.Cookie;
}
# Les peticions GraphQL autenticades no s'han d'emmagatzemar a la memòria cau per defecte
if (req.url ~ "/graphql" && req.http.Authorization ~ "^Bearer") {
return (pass);
}
return (hash);
}
sub vcl_hash {
if (req.http.cookie ~ "X-Magento-Vary=") {
hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
}
# Per assegurar que els usuaris http no vegin l'avís ssl
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}
if (req.url ~ "/graphql") {
call process_graphql_headers;
}
}
sub process_graphql_headers {
if (req.http.Store) {
hash_data(req.http.Store);
}
if (req.http.Content-Currency) {
hash_data(req.http.Content-Currency);
}
}
sub vcl_backend_response {
set beresp.grace = 3d;
if (beresp.http.content-type ~ "text") {
set beresp.do_esi = true;
}
if (bereq.url ~ "\.js$" || beresp.http.content-type ~ "text") {
set beresp.do_gzip = true;
}
if (beresp.http.X-Magento-Debug) {
set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
}
# emmagatzema a la memòria cau només les respostes correctes i les 404
if (beresp.status != 200 && beresp.status != 404) {
set beresp.ttl = 0s;
set beresp.uncacheable = true;
return (deliver);
} elsif (beresp.http.Cache-Control ~ "private") {
set beresp.uncacheable = true;
set beresp.ttl = 86400s;
return (deliver);
}
# comprova si cal emmagatzemar-ho a la memòria cau i impedeix que s'estableixi una galeta
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
unset beresp.http.set-cookie;
}
# Si la pàgina no es pot emmagatzemar a la memòria cau, omet varnish durant 2 minuts com a Hit-For-Pass
if (beresp.ttl <= 0s ||
beresp.http.Surrogate-control ~ "no-store" ||
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "no-cache|no-store") ||
beresp.http.Vary == "*") {
# Marca com a Hit-For-Pass durant els 2 minuts següents
set beresp.ttl = 120s;
set beresp.uncacheable = true;
}
return (deliver);
}
sub vcl_deliver {
if (resp.http.X-Magento-Debug) {
if (resp.http.x-varnish ~ " ") {
set resp.http.X-Magento-Cache-Debug = "HIT";
set resp.http.Grace = req.http.grace;
} else {
set resp.http.X-Magento-Cache-Debug = "MISS";
}
} else {
unset resp.http.Age;
}
# No permet que el navegador emmagatzemi fitxers no estàtics a la memòria cau.
if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
set resp.http.Pragma = "no-cache";
set resp.http.Expires = "-1";
set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
}
unset resp.http.X-Magento-Debug;
unset resp.http.X-Magento-Tags;
unset resp.http.X-Powered-By;
unset resp.http.Server;
unset resp.http.X-Varnish;
unset resp.http.Via;
unset resp.http.Link;
}
sub vcl_hit {
if (obj.ttl >= 0s) {
# Encert dins del període TTL
return (deliver);
}
if (std.healthy(req.backend_hint)) {
if (obj.ttl + 300s > 0s) {
# Encert després del venciment del TTL, però dins del període de gràcia
set req.http.grace = "normal (healthy server)";
return (deliver);
} else {
# Encert després del venciment del TTL i del període de gràcia
return (restart);
}
} else {
# el servidor no està en bon estat, recupera de la memòria cau
set req.http.grace = "unlimited (unhealthy server)";
return (deliver);
}
}Després, torna a carregar els dimonis per aplicar el canvi del servei:
# systemctl daemon-reloadI posteriorment reinicia el servei:
# systemctl restart varnishComprova que Varnish està escoltant pel port HTTP (80 TCP):
# ss -tulpn | grep varnishHauria de mostrar el resultat següent:
tcp LISTEN 0 1024 0.0.0.0:80 0.0.0.0:* users:(("cache-main",pid=56913,fd=3),("varnishd",pid=56889,fd=3))
tcp LISTEN 0 10 127.0.0.1:6082 0.0.0.0:* users:(("varnishd",pid=56889,fd=7))
tcp LISTEN 0 1024 [::]:80 [::]:* users:(("cache-main",pid=56913,fd=4),("varnishd",pid=56889,fd=4))
Configuració HTTPS per a NGINX
Si ja tens configurat HTTPS per a NGINX mitjançant Configurar SSL a la imatge de Magento, omet l'obtenció del certificat i configura únicament el servidor intermediari invers (substituint la configuració de 443 per 8080).
Per obtenir el certificat, executa el següent (modifica el domini d'exemple):
# apt install python3-certbot-nginx -y && certbot certonly --webroot -w /var/www/html/magento2/ -d ejemplo.comUn cop obtingut i configurat el certificat, a la configuració d'HTTPS de NGINX configura el servidor intermediari invers per a Varnish:
server {
server_name ejemplo.com;
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/ejemplo.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ejemplo.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS (cal ngx_http_headers_module) (63072000 segons)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
location / {
proxy_pass http://127.0.0.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
fastcgi_buffer_size 32k;
fastcgi_buffers 4 32k;
}
}
Després, pots purgar la memòria cau de Magento directament eliminant-la:
# rm -R /var/www/html/magento2/var/cache/*Finalment, reinicia els serveis per a la nova configuració:
# systemctl restart varnish && systemctl restart nginx.serviceEnhorabona, Varnish configurat! Ara pots iniciar la preparació de la teva botiga Magento.
Comparativa de rendiment web
En el següent banc de proves s'utilitza la imatge preinstal·lada de Magento 2 per a tots dos servidors, amb els mateixos recursos de maquinari i configuració. L'única diferència serà que un dels servidors estarà configurat amb Varnish i l'altre sense.
La primera prova consistirà en una execució de l'eina httpstat per revisar el TTFB.
Els resultats del servidor sense Varnish són els següents:
DNS Lookup TCP Connection SSL Handshake Server Processing Content Transfer
[ 2ms | 2ms | 11ms | 59ms | 3ms ]
| | | | |
namelookup:2ms | | | |
connect:4ms | | |
pretransfer:15ms | |
starttransfer:74ms |
total:77ms
El temps de processament del servidor és de 59 ms, un temps raonable.
Resultat del servidor Magento amb Varnish configurat:
DNS Lookup TCP Connection SSL Handshake Server Processing Content Transfer
[ 4ms | 2ms | 12ms | 10ms | 2ms ]
| | | | |
namelookup:4ms | | | |
connect:6ms | | |
pretransfer:18ms | |
starttransfer:28ms |
total:30ms
La diferència és molt notable, només 10 ms de processament i és aprox. sis vegades més ràpid.
En la segona prova s'executarà més d'una petició; per fer-ho es pot utilitzar l'eina h2load.
Resultat d'una execució de deu peticions al servidor sense Varnish:
finished in 477.89ms, 20.93 req/s, 184.71KB/s
requests: 10 total, 10 started, 10 done, 10 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 10 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 88.27KB (90390) total, 26.72KB (27360) headers (space savings 0.00%), 60.58KB (62030) data
min max mean sd +/- sd
time for request: 156.07ms 463.20ms 305.79ms 120.96ms 60.00%
time for connect: 4.26ms 13.67ms 8.31ms 3.21ms 60.00%
time to 1st byte: 160.34ms 476.87ms 314.09ms 124.00ms 60.00%
req/s : 2.10 6.22 3.77 1.73 70.00%
Un total de deu peticions completades en 477.89 ms, un màxim de 463.20 ms de temps de petició i amb 20,93 peticions per segon de mitjana.
El temps ha augmentat considerablement; com qualsevol aplicació PHP amb base de dades SQL, Magento pateix considerablement amb moltes peticions. Tot i que amb Varnish hauria de ser diferent:
finished in 26.26ms, 380.88 req/s, 3.25MB/s
requests: 10 total, 10 started, 10 done, 10 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 10 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 87.29KB (89380) total, 18.15KB (18590) headers (space savings 26.49%), 68.39KB (70030) data
min max mean sd +/- sd
time for request: 6.90ms 11.62ms 9.08ms 1.97ms 50.00%
time for connect: 12.00ms 15.23ms 13.54ms 876us 80.00%
time to 1st byte: 19.20ms 25.57ms 22.62ms 2.60ms 60.00%
req/s : 38.81 51.64 44.43 5.21 60.00%
Les deu peticions s'han completat en només 26,26 ms, amb 380,88 peticions per segon de mitjana i un temps màxim d'11,62 ms. La diferència parla per si sola, però es pot exigir més amb wrk per comprovar els resultats.
Resultat del servidor sense Varnish, deu connexions en un sol fil durant cinc segons amb wrk:
Running 5s test @ https://magento.clouding.host/
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 481.68ms 74.20ms 654.80ms 84.69%
Req/Sec 20.11 10.31 40.00 91.11%
98 requests in 5.01s, 865.06KB read
Requests/sec: 19.57
Transfer/sec: 172.79KB
Només 98 peticions en els cinc segons, amb una latència una mica més elevada que abans. Modificant la configuració per defecte, hauria de donar millors resultats.
En canvi, amb el servidor amb Varnish:
Running 5s test @ https://magentovarnish.clouding.host/
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.17ms 4.54ms 96.11ms 78.07%
Req/Sec 1.69k 132.41 1.82k 90.00%
8408 requests in 5.00s, 77.60MB read
Requests/sec: 1680.60
Transfer/sec: 15.51MB
Un total de 8408 peticions en cinc segons! Amb una latència màxima de 96,11 ms i una mitjana inferior a 10 ms.
Recorda, si tens consultes sobre aquesta o qualsevol altra qüestió relacionada amb els teus servidors a Clouding, no dubtis a escriure a soporte@clouding.io Som al teu costat per al que necessitis, consulta'ns!