-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Cache] Allow purge of expired caches (avoid filesystem overflow) #21764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I agree, it could be useful to have a "gc" method, that erases expired items. |
Thanks for your response! How do you want to handle this? I'd suggest a Alternatively, we could add Either way, I'd then suggest adding some indications in the docs which adapters require manual purging, and make people aware of this issue. Aside: As a PHP project (SilverStripe CMS), we ideally want cache to be plug-and-play, hence default to FileSystem (if APC and opcache aren't available). At the moment, no other system aspect requires SilverStripe devs to set up cron jobs for a base installation. So we'll likely implement randomised auto-purging as part of HTTP request execution. rather than complicating a baseline installation by having users figure out cron jobs on their hosting. |
Would you suggest that if someone wanted this feature that they create an LRUFilesystemAdapter? LRU (or some other way of deleting a portion of "old" items to fit within a cache-size quota) becomes important when you have a cache-invalidation approach based on changing the lookup key when a cache is invalidated (e.g. putting a known last-modified-timestamp into the cache key). Did you have an alternative solution to this or is supporting this caching approach not a primary design goal of symfony/cache? Would you see an LRU-based filesystem cache as being appropriate to including the symfony/cache package, or just make it a separate composer package? |
About vocabularies, I have a personal preference towards "gc" or "prune" for this. I'm not sure "purge" convey enough semantic difference from "delete" or "clear" (which just empty the pool). But I'm not a native English speaker so I might be wrong. Adding a new let's say About LRU, we might not need a new adapter, but maybe just a new |
I can't imagine that a relational database would be faster than a filesystem for this kind of thing (I haven't done benchmarks but I've been badly burned moving sessions from files to database in the past), but good point about recommending a faster (e.g. memory-based) system by default. |
@sminnee Assuming you are using InnoDB with an adequate buffer pool size, your database lookups will remain in memory, which will absolutely be faster than the filesystem, specifically on high volume websites, even with network/socket negotiation taken into account. The filesystem-backed adapter is going to start trailing heavily once a high enough volume of concurrent users starts hitting the site. In fact, the InnoDB buffer pool uses an LRU algorithm to determine what remains in memory and what is garbage collected (and must be re-read from disk on request). Furthermore, in the case of a cache (the intended use of these adapters), you could always use the memory engine for MySQL, which will ensure the disk is never touched (at the cost of purging the entire table contents on a MySQL server restart). Of course, you do need to be dedicating a large chunk of your RAM to MySQL for any useful performance under load, regardless of the engine. Anyway, if you want to control the cache size or implement LRU, the filesystem isn't going to be the fastest option for these features, unless you're mounting a |
Thanks for the info, @robfrawley, good insight! |
Would anyone want to give a try to a "gc" or "prune" method, that would remove all expired entries, with a console command to call it? |
@nicolas-grekas I'll take a stab, but to confirm, are you talking about just the |
Only FS, the other ones already manage purging expired items. |
I have an app-layer implementation of this that I'd be happy to share. You will need to do a little extra work to move it into the framework layer but it should get you 90% of the way there. I will try to post it here when I can, hopefully in the next day or two.
… On 7 Jul 2017, at 15:54, Nicolas Grekas ***@***.***> wrote:
Only FS, the other ones already manage purging expired items.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Here's my app-layer implementation of the above. To make this patch into a proper PR, you'll need to: 1) move the code into the framework 2) add tests etc. 3) add documentation. Ideally, I think there would be a note in the main caching documentation suggesting that users set up a
Hope this helps (sorry I don't have time to turn this into a proper PR for Symfony myself), Rich |
…e) prune method and prune command (robfrawley) This PR was merged into the 3.4 branch. Discussion ---------- [Cache] Add (filesystem|phpfiles) cache (adapter|simple) prune method and prune command | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #21764, #21764 (comment) | License | MIT | Doc PR | symfony/symfony-docs#8209 As requested in #21764 (comment), this PR adds a `prune()` method to [`FilesystemTrait`](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cache/Traits/FilesystemTrait.php). This placement seems reasonable as it exposes the method in [`FilesystemAdapter`](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php) and [`FilesystemCache`](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cache/Simple/FilesystemCache.php). The return value is a `bool` representing either a partial or complete failure (when `false`) *or* complete success (when `true`). Once the API for the `prune` method is confirmed, I'll introduce a documentation PR, as well. --- *Stale-detection implementation:* The file modification time is used to determine if a cache item should be pruned. This seems reasonable, given the use of [`touch` in the common trait](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php#L90). Interestingly, though, the [`doFetch` method](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Cache/Traits/FilesystemTrait.php#L38) uses the timestamp saved at the top of the file itself to determine the stale state. Should this latter implementation be used for `prune` as well (or is the current one ok), for example: ```php foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD) as $file) { if ($h = @fopen($file, 'rb')) { if ($time >= (int) $expiresAt = fgets($h)) { fclose($h); if (isset($expiresAt[0])) { $okay = (@Unlink($file) && !file_exists($file)) && $okay; } } } } ``` Commits ------- f0d0c5f add (filesystem|phpfiles) cache (adapter|simple) prune method and prune command
Note: the recently merged pruning logic prunes only namespaces that are know. But when the namespace seed changes, all namespaces change, and aren't referenced anymore, so that they can't be pruned (nor cleared really) anymore. |
Considering the previous comment, and since namespace seeds don't change randomly, I'm closing this one as fixed by the new 3.4 pruning logic (and |
The
FilesystemAdapter
implementation forSymfony/Cache
doesn't seem to have any mechanisms to constrain the used cache size, auto-purging cache entries by least-recently-used, or their expiry date. Most other adapters (e.g. PHP's opcache, memcache) handle this internally. The filesystem adapter clears out expired caches on access only. While you can technically avoid causing the webserver filesystem to overflow by designating a limited filesystem partition for your temp folder, that's not a very common practice - and hence will leave users of this library quite exposed to server capacity exhaustion.The StashPHP cache library has implemented a purge() action for this purpose (implementation details):
Zend_Cache used to deal with this by randomly calling a purge action every 100 cache accesses through the library - which makes app performance less predictable, but means you don't need to worry about cron jobs etc.
In general, there's not enough metadata to create a least-recently-used purge. The filesystem adapter uses touch() to set expiry metadata, but doesn't deal with last access.
If you consider this to be out of scope for the library itself, would you be open to a pull request which documents this fairly significant gotcha for the filesystem driver?
The text was updated successfully, but these errors were encountered: