Skip to content
This repository was archived by the owner on May 28, 2023. It is now read-only.

Commit 0bf814b

Browse files
author
Fifciuu
committed
MVP
1 parent 481f49d commit 0bf814b

File tree

7 files changed

+386
-0
lines changed

7 files changed

+386
-0
lines changed

config/default.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@
116116
]
117117
}
118118
},
119+
"varnish": {
120+
"host": "185.246.52.88",
121+
"port": 80,
122+
"method": "BAN",
123+
"enabled": false
124+
},
119125
"redis": {
120126
"host": "localhost",
121127
"port": 6379,

docker-compose.nodejs.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,9 @@ services:
2626
- /var/www/dist
2727
ports:
2828
- '8080:8080'
29+
networks:
30+
- some-net
31+
32+
networks:
33+
some-net:
34+
driver: bridge

docker-compose.varnish.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: '3.0'
2+
services:
3+
varnish:
4+
build:
5+
context: .
6+
dockerfile: varnish/Dockerfile
7+
volumes:
8+
- ./docker/varnish/config.vcl:/usr/local/etc/varnish/default.vcl
9+
ports:
10+
- '1234:80'
11+
networks:
12+
- vuestorefrontapi_some-net
13+
14+
networks:
15+
vuestorefrontapi_some-net:
16+
external: true

docker-compose.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ services:
1717
- cluster.name=docker-cluster
1818
- bootstrap.memory_lock=true
1919
- "ES_JAVA_OPTS=-Xmx512m -Xms512m"
20+
networks:
21+
- vuestorefrontapi_some-net
2022

2123
kibana:
2224
build: docker/kibana/
@@ -26,11 +28,19 @@ services:
2628
- '5601:5601'
2729
depends_on:
2830
- es1
31+
networks:
32+
- vuestorefrontapi_some-net
2933

3034
redis:
3135
image: 'redis:4-alpine'
3236
ports:
3337
- '6379:6379'
38+
networks:
39+
- vuestorefrontapi_some-net
3440

3541
volumes:
3642
esdat1:
43+
44+
networks:
45+
vuestorefrontapi_some-net:
46+
external: true

docker/varnish/Dockerfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM cooptilleuls/varnish:6.0-stretch
2+
3+
# install varnish-modules
4+
RUN apt-get update -y && \
5+
apt-get install -y build-essential automake libtool curl git python-docutils && \
6+
curl -s https://packagecloud.io/install/repositories/varnishcache/varnish60/script.deb.sh | bash;
7+
8+
RUN apt-get install -y pkg-config libvarnishapi1 libvarnishapi-dev autotools-dev;
9+
10+
RUN git clone https://github.com/varnish/varnish-modules.git /tmp/vm;
11+
RUN cd /tmp/vm; \
12+
git checkout 6.0; \
13+
./bootstrap && \
14+
./configure;
15+
16+
RUN cd /tmp/vm && \
17+
make && \
18+
make check && \
19+
make install;

docker/varnish/README.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
### Tutorial
2+
1. Create network with `docker network create <your_network>`
3+
2. Use `docker network ls` and find your network. It should have prefix!
4+
E.g. when I used `docker network create some-net`, I have network with name `vuestorefrontapi_some-net`
5+
3. Open docker-compose.yml:
6+
At the end:
7+
```
8+
networks:
9+
vuestorefrontapi_some-net:
10+
external: true
11+
```
12+
Set vuestorefrontapi_some-net to your network name
13+
14+
4. Check each `docker-compose` file and set proper network name.
15+
5. In the docker-compose.nodejs.yml it should not have a prefix, e.g:
16+
```
17+
networks:
18+
- some-net
19+
20+
networks:
21+
some-net:
22+
driver: bridge
23+
```
24+
25+
### How does it work?
26+
1. I add output tags to the VSF-API response:
27+
```
28+
const tagsHeader = output.tags.join(' ')
29+
res.setHeader('X-VS-Cache-Tag', tagsHeader)
30+
```
31+
32+
2. After it invalidates cache in the Redis. I forward request to the:
33+
```
34+
http://${config.varnish.host}:${config.varnish.port}/
35+
```
36+
With invalidate tag in headers:
37+
```
38+
headers: {
39+
"X-VS-Cache-Tag": tag
40+
}
41+
```
42+
43+
I set Varnish invalidate method to `BAN` but you can change it in your config + varnish's config.
44+
45+
3. Configuration of BANning we have inside `docker/varnish/config.vcl` in `vcl_recv`.
46+
It tries to BAN resource which has `X-VS-Cache-Tag` header:
47+
```
48+
# Logic for the ban, using the X-Cache-Tag header.
49+
if (req.http.X-VS-Cache-Tag) {
50+
ban("obj.http.X-VS-Cache-Tag ~ " + req.http.X-VS-Cache-Tag);
51+
}
52+
```
53+
54+
Below under BANning logic. I have to tell Varnish what to cache.
55+
```
56+
if (req.url ~ "^\/api\/catalog\/") {
57+
if (req.method == "POST") {
58+
# It will allow me to cache by req body in the vcl_hash
59+
std.cache_req_body(500KB);
60+
set req.http.X-Body-Len = bodyaccess.len_req_body();
61+
}
62+
63+
if ((req.method == "POST" || req.method == "GET")) {
64+
return (hash);
65+
}
66+
}
67+
```
68+
69+
I am caching request that starts with `/api/catalog/`. As you can see I cache both POST and GET.
70+
This is because in my project I use huge ES requests to compute Facted Filters. I would exceed HTTP GET limit.
71+
72+
Thanks to this line and `bodyaccess`, I can distinguish requests to the same URL by their body!
73+
```
74+
std.cache_req_body(500KB);
75+
```
76+
77+
Then in `vcl_hash` I create hash for POST requests with `bodyaccess.hash_req_body()`:
78+
```
79+
sub vcl_hash {
80+
# To cache POST and PUT requests
81+
if (req.http.X-Body-Len) {
82+
bodyaccess.hash_req_body();
83+
} else {
84+
hash_data("");
85+
}
86+
}
87+
```
88+
89+
By default, Varnish change each request to HTTP GET. We need to tell him to send POST requests to the VSF-API as POST - not GET.
90+
We will do it like that:
91+
```
92+
sub vcl_backend_fetch {
93+
if (bereq.http.X-Body-Len) {
94+
set bereq.method = "POST";
95+
}
96+
}
97+
```
98+
99+
100+
### Caching Stock
101+
It might be a good idea to cache stock requests if you check it lifetime in VSF-PWA in visiblityChanged hook (product listing).
102+
In one project when I have slow Magento - it reduced Time-To-Response from ~2s to ~70ms.
103+
104+
```
105+
if (req.url ~ "^\/api\/stock\/") {
106+
if (req.method == "GET") {
107+
# M2 Stock
108+
return (hash);
109+
}
110+
}
111+
```
112+
113+
Then in `vcl_backend_response` you should set safe TTL (Time to live) for your stock cache. I've set 15 minutes (900 seconds)
114+
```
115+
sub vcl_backend_response {
116+
# Set ban-lurker friendly custom headers.
117+
if (beresp.http.X-VS-Cache && beresp.http.X-VS-Cache ~ "Miss") {
118+
set beresp.ttl = 0s;
119+
}
120+
if (bereq.url ~ "^\/api\/stock\/") {
121+
set beresp.ttl = 900s; // 15 minutes
122+
}
123+
set beresp.http.X-Url = bereq.url;
124+
set beresp.http.X-Host = bereq.http.host;
125+
}
126+
```
127+
128+
For X-VS-Cache, I set TTL 0s so it is permanent. Because it will be automaticly invalidated when needed.
129+
130+
### Caching Extensions
131+
You might want to cache response from various extensions.
132+
E.g. I am fetching Menus, Available Countries (for checkout) from M2 by VSF-API proxy.
133+
As in this project Magento is pretty slow. By caching responses I've changed response time from ~2s
134+
to around ~50ms.
135+
136+
How to do that?
137+
Inside `vcl_recv` add:
138+
```
139+
// As in my case I want to cache only GET requests
140+
if (req.method == "GET") {
141+
# Countries for storecode GET - M2 - /directory/countries
142+
if (req.url ~ "^\/api\/ext\/directory\/") {
143+
return (hash);
144+
}
145+
146+
# Menus GET - M2 - /menus & /nodes
147+
if (req.url ~ "^\/api\/ext\/menus\/") {
148+
return (hash);
149+
}
150+
}
151+
```
152+
153+
How to invalidate extension's tag?
154+
You can do it by sending request with `X-VS-Cache-Ext` header.
155+
If value of this header is part of any cached URL - it will be invalidated.
156+
E.g. for menus extension:
157+
```
158+
/api/ext/menus
159+
```
160+
You could send:
161+
BAN `http://${config.varnish.host}:${config.varnish.port}/`
162+
headers: {
163+
"X-VS-Cache-Ext": "menus"
164+
}
165+
166+
But sending HTTP requests is not so handy. So I've extended Invalidate endpoint. To the same you could just open:
167+
```
168+
http://localhost:8080/invalidate?key=aeSu7aip&ext=menus
169+
```
170+
171+
As value of the `ext` will be searched inside `Cached URL`.
172+
If you would provide here `product` it would cache product's catalog. You should have it in mind.
173+
174+
### Banning permissions
175+
It will be allowed only from certain IPs. In my case I put here only VSF-API IP. But here we have `app` as Docker will resolve it as VSF-API IP:
176+
```
177+
acl purge {
178+
"app"; // IP which can BAN cache - it should be VSF-API's IP
179+
}
180+
```
181+
182+
### What to cache
183+
We should provide to Varnish - IP & Port to cache, there we have it:
184+
```
185+
backend default {
186+
.host = "app";
187+
.port = "8080";
188+
}
189+
```
190+
191+
### URL
192+
Varnish by default using port `80` but by Docker's port mapping we are using `1234`
193+
194+
### How to install on VPS
195+
1. Install Varnish
196+
2. Install Varnish Modules
197+
3. By using Reverse Proxy output `/api` from Varnish, to the world
198+
199+
I'll try to prepare more detailed tutorial (with commands) as I will probably do it again in the following month.

0 commit comments

Comments
 (0)