Since writing Using PHP APC with Cherokee I noticed that my cache hits were dropping and my cache misses were growing. This is my first attempt at tweaking the configuration of php-apc
to try to eke out more performance.
I enabled my apc.php
page (check the previous article), checked the statistics, and saw that the Cache full count
was growing. My cache had filled several times.
According to the APC configuration documentation there are two settings that control the expiration of cache entries. They are:
By default, they are set to 0
.
According to the documentation:
In the event of a cache running out of available memory, the cache will be completely expunged if ttl is equal to 0. Otherwise, if the ttl is greater than 0, APC will attempt to remove expired entries.
Essentially, that meant my cache was completely expunged every time it filled and a new entry needed to be cached. Clearing the entire cache in order to store one more entry strikes me as less than optimal!
I'm surprised APC doesn't offer any smarts for managing a full or near-full cache (eg, using algorithms such as Least Recently Used or Second Chance Replacement to choose an entry to replace). The only option appears to be adjusting the cache expiry (apc.ttl
and apc.user_ttl
) or the size of the cache (apc.shm_segments
and apc.shm_size
).
At this stage I didn't think it was a good idea to increase the memory used by php-apc
. I'm on a Linode 512, a memory-constrained VPS. Also, by expiring infrequently-requested cache entries I might find that I can use less memory for the cache instead of more.
So I added the following to /etc/php5/cgi/conf.d/apc.ini
:
# Does exactly what you think it does...
apc.enabled=1
# Number of seconds (7200 == 2h) before cache
# entries are expired. Otherwise, the default (0)
# means that the entire cache will be expunged
# if/when the cache fills.
apc.ttl = 7200
apc.user_ttl = 7200
Of course, after making the changes there's still more to be done. I'm using Cherokee and FastCGI, so I need to restart the php-cgi
processes for the change to take effect. I've found that /etc/init.d/cherokee restart
doesn't take care of restarting the php-cgi
processes. Nor does using the Graceful restart
or Hard restart
options in cherokee-admin
. Instead, I believe (again, please correct me if I'm wrong) that sending the SIGTERM
to php- cgi
means that the php-cgi
processes will terminate when they have finished handling their current requests.
killall -TERM php-cgi
service cherokee start
After these changes:
if I find there is too much free memory in the cache and the cache misses are too high, I will increase the expiry times
if I find there is too much free memory but the cache hits are high (say, over 75%), I will probably decrease the size of the cache
if everything is just right, I'll leave things as they are
We'll find out in round 2...
In the meantime, follow me on Twitter. It's free. Cheers!