Direct Answers
1. Filesystem locking bottlenecks: Yes, the flock()-based locking in the Filesystem adapter creates measurable contention under high concurrent write loads. Each cache write acquires an exclusive lock on the cache file (or directory, depending on implementation), serializing writers. In PHP-FPM pools with many workers, this becomes a throughput ceiling.
2. Traffic threshold for Memcached overhead: There is no universal requests-per-second number. The crossover depends on deployment topology, not raw traffic. If your application runs on a single server with sticky sessions, Filesystem remains viable well into thousands of writes/second on modern NVMe. The moment you add a second web node or remove sticky sessions, Filesystem becomes incorrect for shared state (CSRF tokens, auth sessions, rate-limit counters) regardless of load.
Confirmed Facts from Zend Cache Internals
- Filesystem adapter stores each entry as a separate serialized file; cleanup of expired entries is not automatic — you must schedule
->cleanExpired() via cron or risk inode exhaustion.
- Memcached adapter requires the
ext-memcached PHP extension (not the older ext-memcache) and a running memcached daemon. It uses consistent hashing (libketama) so adding/removing nodes invalidates minimal keys.
- Both implement
Zend\\Cache\\Storage\\AdapterInterface; switching is a configuration change, but TTL granularity differs: Filesystem respects mtime (1-second resolution), Memcached uses second-resolution expiry.
- Memcached evicts silently under memory pressure (LRU); Filesystem fills disk until cleanup runs. Monitoring
stats (evictions, bytes_used) is mandatory for Memcached.
Likely Explanation (Not Benchmarked Here)
Under pure write-heavy workloads on a single node, Filesystem latency is dominated by fsync/directory metadata updates. Memcached avoids disk entirely but adds network round-trip (even localhost UNIX socket) and serialization overhead. For 2 KB payloads, expect Filesystem writes at 0.5–2 ms vs Memcached at 0.2–0.8 ms on localhost — but the variance under concurrency is far wider for Filesystem due to lock queuing.
Verification Steps for Your Environment
- Create a micro-benchmark using
Zend\\Cache\\StorageFactory::factory() with both adapters; measure p50/p99 latency for 10k mixed read/write operations with your actual payload size. - Run
echo stats | nc -U /var/run/memcached.sock (or TCP 11211) and confirm evictions=0 and get_hits > get_misses under load. - Inspect Filesystem cache directory:
find /var/cache/zend -type f -mmin +60 | wc -l should stay near zero if cleanup runs. - Test failover: stop memcached, verify application catches
Zend\\Cache\\Exception\\RuntimeException and degrades gracefully.
One Diagnostic Detail That Changes the Recommendation
Are you deploying to a single server or multiple load-balanced nodes (or a container orchestration platform where pods share no local disk)? If multiple nodes or no shared filesystem, Filesystem adapter is incorrect for any shared state — choose Memcached (or Redis) regardless of traffic volume.