We have some issues with the default fastcgi_cache_path settings.

1) /var/lib/nginx/speed is the physical disk on our platform. This is slow and leads to huge iowait times.
2) If we change the path to use our in-memory tmpfs, then levels=2:2:2 exhausts all inodes on the tmpfs.
3) keys_zone=speed:10m caches only about 80,000 objects. That could be a limiting factor for some larger servers.
4) inactive=10m is way to little time to cache objects.
5) max_size=3g is too big for any of our smaller VPSs, too small for others.

Here are our settings for a larger VPS:
fastcgi_cache_path /run/shm/nginx-speed
levels=2:2
keys_zone=speed:25m
inactive=24h
max_size=3g

And for a smaller VPS:
fastcgi_cache_path /run/shm/nginx-speed
levels=2:2
keys_zone=speed:10m
inactive=4h
max_size=512m

The problem with levels=2:2:2 is that it creates 256*256*256 subfolders (~16.77 million), and that exhausts all possible inodes available in a tmpfs (about 8 million). Instead, 2:2 creates 256*256 folders (65.5k)

Is there already a way to override these settings that won't be overwritten every time we verify the Aegir server, or can I propose a configuration page for these in Aegir?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

millenniumtree created an issue. See original summary.

memtkmcc’s picture

Title: Customizing fastcgi_cache_path settings » Nginx: default FastCGI cache levels value may exhaust all inodes
Category: Support request » Bug report
memtkmcc’s picture

Aegir utilizes Nginx FastCGI Cache in a "micro-cache" mode, with very short TTL (just 10 seconds for 200 OK responses), so it doesn't make any sense to keep large cache around, nor to use very long inactive parameter.

The max_size set to 3 GB seems to be a sane default, just to avoid having too small space there.

The only thing which really should be changed and just doesn't make any sense for micro-caching, is the default for levels parameter.

Even on extremely fast SSDs it can easily send your system to almost frozen state due to sudden high load spike if you will try to purge this cache with simple rm -rf /var/lib/nginx/speed/*.

But I don't see any reason to customize fastcgi_cache_path. You can always mount /var/lib/nginx/speed to anything you want, if you think you need to modify it.

Nginx is very fast in serving stuff from its cache, and it is the crazy 256*256*256 structure which may hit the hardware I/O limits.

memtkmcc’s picture

Status: Active » Needs review
FileSize
906 bytes

Attached patch fixes the most important problem here.

millenniumtree’s picture

FileSize
16.65 KB

Thanks. The 2:2 will help immensely. That was one of the big problems when I switched to the tmpfs and tried to delete the old disk cache. The system very quickly became unresponsive.

I actually had to write a small script to run every 15 seconds that deleted just one of the 2nd level folders at a time.
It took 11 days to remove the whole disk cache this way.

I know some people put varnish in front of their nginx, but we haven't yet, so we do rely on nginx as a primary cache.

Here's the script I used:
NOTE: Use at your own risk. There's an "rm -rf" in thar. I did test it thoroughly to make sure it didn't eat the world when the cache files were all gone. When you have tested it thoroughly on YOUR system, uncomment the "rm" line.

First, we rename the cache folder so that can be deleted slowly while the live directory is re-created when you restart nginx
(run this as root)

mv /var/lib/nginx/speed /var/lib/nginx/speed-old
service nginx restart

Now, here's the script that deletes one 2nd-level directory at a time:

#!/bin/bash

d=`ls -d /var/lib/nginx/speed-old/*/* |head -n1 |cut -d':' -f1`
if [[ "$d" != "" ]]; then
  echo "removing $d"
  #rm -rf "$d"
else
  echo "doing nothing"
fi

And the crons to run it 4 times a minute (done here between 1AM and 10PM to avoid our backup spike). These output to a log file so you can see what it's doing.

* 1-22 * * * /root/bin/rmspeed >> /root/rmspeed.log
* 1-22 * * * sleep 15; /root/bin/rmspeed >> /root/rmspeed.log
* 1-22 * * * sleep 30; /root/bin/rmspeed >> /root/rmspeed.log
* 1-22 * * * sleep 45; /root/bin/rmspeed >> /root/rmspeed.log

I've also attached a munin graph showing our inode exhaustion. I caught it after a couple of weeks, but at the same rate, we would have run out of inodes in about 7 weeks.

memtkmcc’s picture

It is also a good idea to run this script with some sane nice/ionice parameters, perhaps, not just sleep intervals.

We have a very fast hardware, so we were able to run global cleanup on many guests at once, but I wouldn't recommend this on any popular VPS, nor on a cheap bare metal hosting:

$ nice -n19 ionice -c2 -n7 find /var/lib/nginx/speed/* -mtime +1 -exec rm -rf {} \; &> /dev/null

Even on a very fast hardware, it took several hours to cleanup just a few GB of caches per guest, because of that crazy deep dirs structure (and because of aggressive nice/ionice, for sure.)

memtkmcc’s picture

Note that my example one-liner deletes only old enough stuff, to not cause problems on a high traffic system.

Important: once you apply the patch, it is not enough to reload nginx, you must **restart** nginx to get this updated levels parameter to work properly.

millenniumtree’s picture

I tried many combinations of ionice, and because our VPS drives are buffered so heavily, ionice still ended up queuing a massive # of deletions until they hit the drive and locked up the machine.

The script I used above should do it slowly enough to not take the system down. Each run only deletes one of the middle directories which could contain up to 256 3rd-level directories. Because of the minimal cache settings, the 3rd level dirs are basically empty.

I've also updated my previous comment to first rename the old cache directory so it can be cleaned up while the new 2:2 cache is created by nginx.

  • memtkmcc committed 138c42c on 7.x-3.x authored by omega8cc
    Issue: #2791885 Nginx: default FastCGI cache levels value may exhaust...
memtkmcc’s picture

Status: Needs review » Fixed

Fix committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.