Debugging Nginx Cache Misses: Hitting high number of MISS despite high proxy valid

Caching:

Are you enabling the proxy_cache in your location or server block?

For example, a few settings in the location / block from the Nginx docs.

proxy_cache_path  /var/lib/nginx/cache  levels=1:2   keys_zone=staticfilecache:180m  max_size=700m;


server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_cache_revalidate on;
        proxy_cache_min_uses 3;
        proxy_cache_use_stale error timeout updating http_500 http_502
                              http_503 http_504;
        proxy_cache_background_update on;
        proxy_cache_lock on;
    # ...
    }

For the cache to work you need at least the two mandatory settings:

  • proxy_cache_path
  • proxy_cache

If you set it in some location block, are you sure that's the one you want to be caching?


Analyzing

If you wish to analyze the hits, you can create a specific log for that:

log_format cache_st '$remote_addr - $upstream_cache_status [$time_local]  '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

And in the same server or location block, you can add it as a secondary log, so you don't miss the other stuff:

access_log   /var/log/nginx/domain.com.access.log;
access_log   /var/log/nginx/domain.com.cache.log cache_st;

You can then check some stats:

HIT vs MISS vs BYPASS vs EXPIRED

awk '{print $3}' cache.log | sort | uniq -c | sort -r

MISS URLs:

awk '($3 ~ /MISS/)' cache.log | awk '{print $7}' | sort | uniq -c | sort -r

BYPASS URLs:

awk '($3 ~ /BYPASS/)' cache.log | awk '{print $7}' | sort | uniq -c | sort -r

MISS vs BYPASS

  • MISS occurs when a pattern is configured to cache but at the time of request was not cached. In correct configuration, subsequent requests will be served from cache based on caching duration other parameters.
  • BYPASS occurs when a pattern was explicitly configured NOT to use cache. e.g. skipping cache for logged in user. Subsequent requests will also be bypassed.

Analyzing source: - https://easyengine.io/tutorials/nginx/upstream-cache-status-in-access-log/

Another option for analyzing on the fly via console is to use GoAccess, a really nice real time web log analyzer, which only needs ncurses to work: https://goaccess.io/


You may need to set the inactive parameter on proxy_cache_path to something greater than 120d (or whatever you want your max cache time to actually be). The default setting for inactive is 10 minutes. So long as the URL you're caching is accessed within the inactive parameter's time frame your cache is valid but if it's not accessed within that time frame it will fall out of cache. See Understanding the nginx proxy_cache_path directive for more information.

I believe this falls outside the typical $upstream_cache_status style debugging because cache cleanup doesn't happen within the request/response cycle. AFAIK an nginx worker process does cache clean up as a low priority task if it's not doing anything else. I'm not sure where this activity would show up in logs but it's likely only going to show up with a debug enabled build.


What are trying to cache? A cms? A static page? Usually if backed send no-cache , expire -1, or cache private, you will get misses . In case of cookie also you will hit misses.