Cache#
Nginx provides a caching facility that saves responses from proxied URLs and reuses them later. You can enable and configure it using directives that start with proxy_cache
. There is a special tutorial on the Nginx website that covers Nginx configuration.
There is a guide for caching at official nginx documentation.
In the next cell, the setup defined earlier is executed, and we access the root page.
docker compose -f ../reverse_proxy_files/docker-compose.yml up -d &> /dev/null
Don’t forget to clean up the environment after everything is done.
docker compose -f ../reverse_proxy_files/docker-compose.yml down &> /dev/null
Check cache status#
There is a special variable called upstream_cache_status
that holds the cache status. It is common practice to return this information in the X-Cache-Status
header.
The following cell shows the Nginx configuration that adds $upstream_cache_status
as X-Cache-Status
.
docker exec -i experiment_nginx sh -c 'cat > /etc/nginx/nginx.conf' << EOF
events {}
http {
proxy_cache_path /var/cache/nginx/proxy_cache keys_zone=my_cache:10m;
server {
listen 80;
location / {
proxy_cache my_cache;
proxy_cache_valid 200 5s;
proxy_pass http://client_container/bytes/50;
add_header X-Cache-Status \$upstream_cache_status;
}
}
}
EOF
docker exec -it experiment_nginx nginx -s reload
2024/09/10 09:43:30 [notice] 339#339: signal process started
The following cell requests the endpoint under caching several times and shows the values that the X-Cache-Status
header takes.
# clean case for prevent influece of the other runs
docker exec experiment_nginx bash \
-c "rm /var/cache/nginx/proxy_cache/*" &> /dev/null | true
curl -s -I localhost:80 | grep --color=never Cache
curl -s -I localhost:80 | grep --color=never Cache
sleep 10
curl -s -I localhost:80 | grep --color=never Cache
X-Cache-Status: MISS
X-Cache-Status: HIT
X-Cache-Status: EXPIRED
At the beginning, it shows MISS
because there is no cache for this request. Then it shows HIT
, meaning that Nginx returned a response from the cache. The last request completes after a while, and since the cache record was deleted due to being too old, it shows EXPIRED
.
Expire time#
You can regulate expiration type through the proxy_cache_valid
directive. Specify status codes and their expiration times within the location
directive.
The following cell configures Nginx to expire cached responses with a 200 status code after 5 seconds:
docker exec -i experiment_nginx sh -c 'cat > /etc/nginx/nginx.conf' << EOF
events {}
http {
proxy_cache_path /var/cache/nginx/proxy_cache keys_zone=my_cache:10m;
server {
listen 80;
location / {
proxy_cache my_cache;
proxy_cache_valid 200 5s;
proxy_pass http://client_container/bytes/50;
}
}
}
EOF
docker exec -it experiment_nginx nginx -s reload
2024/09/09 13:47:11 [notice] 39#39: signal process started
Now let’s check if it works—the following cell sends a request to Nginx every second for some time. After a few seconds, the output changes, indicating that the cache has expired and a new response is generated.
for i in {1..10}; do
echo $(curl -s localhost:80/ | tr -d '\0')
sleep 1
done
:M��7�e`�|��%��f�ܳgV�L�����YJ�μ �=� [��lu3
:M��7�e`�|��%��f�ܳgV�L�����YJ�μ �=� [��lu3
:M��7�e`�|��%��f�ܳgV�L�����YJ�μ �=� [��lu3
:M��7�e`�|��%��f�ܳgV�L�����YJ�μ �=� [��lu3
:M��7�e`�|��%��f�ܳgV�L�����YJ�μ �=� [��lu3
:M��7�e`�|��%��f�ܳgV�L�����YJ�μ �=� [��lu3
�R���y����7���N� ?2a�BI����$�_K���As�%�=��Z
�R���y����7���N� ?2a�BI����$�_K���As�%�=��Z
�R���y����7���N� ?2a�BI����$�_K���As�%�=��Z
�R���y����7���N� ?2a�BI����$�_K���As�%�=��Z
Max size#
In the proxy_cache_path
directive, you can set the max_size
argument to define the maximum disk space that the corresponding cache path can use.
The following cell defines two cache paths: one with max_size=1m
and another with max_size=2m
. These paths are tied to different locations.
docker exec -i experiment_nginx sh -c 'cat > /etc/nginx/nginx.conf' << EOF
events {}
http {
proxy_cache_path /var/cache/nginx/proxy_one_megabyte
keys_zone=one_megabyte:10m
max_size=1m;
proxy_cache_path /var/cache/nginx/proxy_two_megabyte
keys_zone=two_megabyte:10m
max_size=2m;
server {
listen 80;
location /one_megabyte {
proxy_cache one_megabyte;
proxy_cache_valid 200 1h;
proxy_pass http://client_container/bytes/50;
}
location /two_megabyte {
proxy_cache two_megabyte;
proxy_cache_valid 200 1h;
proxy_pass http://client_container/bytes/50;
}
}
}
EOF
docker exec -it experiment_nginx nginx -s reload
2024/09/09 14:43:50 [notice] 103#103: signal process started
Now, by exploring the corresponding locations, we’ll create logs for both paths. We’ll deliberately generate more cache than the maximum memory specified for each path.
for i in {1..1000}; do
echo $(curl -s localhost:80/one_megabyte?id=$i | tr -d '\0') &> /dev/null
echo $(curl -s localhost:80/two_megabyte?id=$i | tr -d '\0') &> /dev/null
done
Now let’s check the sizes of the folders with logs.
docker exec experiment_nginx bash -c "
du -h /var/cache/nginx/proxy_one_megabyte
du -h /var/cache/nginx/proxy_two_megabyte
"
1.1M /var/cache/nginx/proxy_one_megabyte
2.1M /var/cache/nginx/proxy_two_megabyte
They are taking approximately 1 and 2 megabytes, as specified in the Nginx configuration.