The current method for removing cached items from the Redis expires keys at 1 year, effectively not removing them from the cache. As Redis cannot remove keys systematically, and this modules allowing for sudo cache bins with the a prefix I understand why the keys are expired at a high rate. The problem is the expectation when running drush cr is that the entire cache is flushed at that time.
There is a simple way to solve the problem by doing either setting PTTL to 1 (millisecond) or TTL to 1 (sec) if supporting older Redis or just executing FLUSHALL.
Currently there is no way to flush the db.
Yes only using one prefix.
Example of whats happening
> redis-cli KEYS community_dev_:config:views.view.rising_sessions_search_view && redis-cli TTL community_dev_:config:views.view.rising_sessions_search_view && drush cr && redis-cli KEYS community_dev_:config:views.view.rising_sessions_search_view && redis-cli TTL community_dev_:config:views.view.rising_sessions_search_view
1) "community_dev_:config:views.view.rising_sessions_search_view"
(integer) 31535915
sh: module: line 1: syntax error: unexpected end of file
sh: error importing function definition for `BASH_FUNC_module'
Cache rebuild complete. [ok]
1) "community_dev_:config:views.view.rising_sessions_search_view"
(integer) 31535998
You can see the expire time actually increased for the key after Drush
| Comment | File | Size | Author |
|---|---|---|---|
| #16 | redis-n2765895-16.interdiff.txt | 1.86 KB | damienmckenna |
| #16 | redis-n2765895-16.patch | 1.38 KB | damienmckenna |
| #13 | 2765895-redis-cache-flush-solution.patch | 1.37 KB | incursus |
| #4 | redis-drush_cr-2765895-4.patch | 745 bytes | grimreaper |
Issue fork redis-2765895
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
berdir> The problem is the expectation when running drush cr is that the entire cache is flushed at that time.
That's a problem with the expecation :)
The expiration is set to 1 year when it is defined as unlimited.
There is no API for a full cache clear, it is only called per bin. Additionally there's the prefix. We don't know that there are no other prefixes and we can't identify a full cache clear.
Instead, the way it works is that a deleteAll() on a single cache bin sets a cache entry that contains the current time. If an entry is requested that was created before then, it is ignored.
Comment #3
ndrake86 commentedYes we are seeing a key being created for the last delete all
But what we are seeing is entries still being referenced which were created prior and not seeing new cache entries containing data we for pages that have been modified.
Are you stating that when clearing the cache via drush or the UI that I should not have an expectation that the cache is actually cleared and rebuilt? Or that when using this module, I should not have that expectation since there is no easy way to identify keys an selectively remove them?
Comment #4
grimreaperHello,
I encountered a fatal error after updating a project because "drush cr" did not flush redis cache.
Here is a small patch that allows to do that.
Thanks for the review.
Comment #5
incursus commentedYou can also use SiteCommander to flush the Redis cache. It's a Drupal sandbox project for now (still waiting for it to get approved), but you can snag it on GitHub if you want.
https://github.com/IncursusInc/sitecommander/tree/8.x-1.x-dev
Comment #6
incursus commentedAlso, confirming that the patch provided in #2765895-4: Currently Drush Cr or Cache Clear UI does not flush Redis cache seems to work fine after I patched my local copy for testing.
Cheers.
Comment #7
ndrake86 commentedTested, Working moving to RTBC hopefully we can get a maintainer to take a look.
Comment #8
mariancalinro commentedActually, the code doesn't take into consideration that other instances/apps may store something in the same redis instance. So, the implementation just deletes everything, for every instance, which is not something that is expected, or desired.
Setting back to needs work, but if your use case is more simple, with one app/site per redis server, the patch here will work for you.
Comment #9
grimreaperHello,
Yes, as I am not familiar with the Redis API and as I needed a quick solution, I don't go too far.
If a maintainer can tell how he/she wants a more sustainable implementation to be done, I will try to make a better patch.
Comment #10
incursus commentedCorrect me if I am wrong, but all of the cached Drupal stuff is prefixed anyway. Should be academic to just delete those keys.
Cheers.
Comment #11
ndrake86 commentedYou would have to recursively get all keys with that prefix store it in a object and issue the delete Key command. Unfortunately Redis doesn't have the ability to remove keys by a prefix (or a wild card). Its something that has been discussed by many as a wanted feature for Redis but AFAIK it hasn't been released in a version of Redis.
One potential way to do it on the terminal is but this is a rather expensive operation:
redis-cli --raw keys "$PATTERN" | xargs redis-cli delI also thought it was advised NOT to run multi-site on the same Redis server for this exact reason. I understand that you CAN but it was advised to not. In which case this patch is a perfectly legitimate way to clear.
Comment #12
incursus commentedIn our SiteCommander module, which will be published soon, we clear the keys out using $settings['cache_prefix'], and it only takes a split second to zap thousands of them. FWIW.
Comment #13
incursus commentedAttaching a patch that implements a fairly simple solution to the problem. Not perfect, but about the best I can come up with. Portions of this from our SiteCommander module (again, to be published soon).
You can read the comments in the patch to get the general approach taken. But the main caveat is that as long as they configure a 'base' value (database index from 0-15), all should be well since it deletes via their configured prefixes (or everything if they do not). And even that can be worked around as well if need be.
Cheers.
Comment #14
incursus commentedAlso, not sure I submitted that patch correctly. The interface for doing so is not terribly intuitive. But feel free to test/incorporate/edit/etc in any event.
Cheers.
Comment #15
ndrake86 commentedMoving to NR so if a bot is setup it will pick the code up for automated review.
Comment #16
damienmckennaThere are some minor Drupal coding standards mistakes, e.g. the 'else' statement should start on a new line instead of hanging at the end of the previous bracket, comments should end in a period, etc.
Comment #17
berdirThis might work if you have a few thousand keys, but what if you have a lot mor than this? This doesn't scale and it blocks redis.
I still don't understand the actual problem here. What exactly is the problem you see? Yes, the keys are not deleted, but the only problem with that should be that storage isn't freed up immediately. But eventually, on a sufficiently large site, redis will be full anyway. You should configure redis with some kind of eviction: http://redis.io/topics/lru-cache, e.g. allkeys-lru or volatile-lru. The second one should work fine as well, since all cache entries are set to an expiration of one year by default.
This should *not* affect caching as visible to Drupal. As explained above, we track for each bin the last full flush, and items older than that are discarded.
Comment #18
incursus commentedThe only way to truly do this seamlessly is to ensure that the Drupal cache is the only application using the configured database index (0-15). Then, a simple flushDB() call does the trick quickly.
You *could* do something like query to see if there are any other keys other than prefixed keys, and if so, throw a warning and abort the flushDB() call. Otherwise, just call flushDB() and move on. And put it in the docs. :) That might work.
Cheers.
Comment #19
manu manuI think too that there is a problem with the end result expected: it seems that some items are not discarded when running
drush crordrupal cache:rebuild all.Reproducible test case:
- Create a new template in a custom theme (eg:
field--text-with-summary.html.twig)- Run
drush cr- The template is not picked up.
Using:
Drupal 8.2.2
Redis module 8.1.x-dev using the PhpRedis client
Redis PHP extension 3.0.0
Redis 3.2.5 with
allkeys-lruSettings:
Willing to help, can I provide more infos?
Setting to major because side effects are impacting site functionality when doing continuous deployments, but correct if needed.
Comment #20
berdirMost likely what you all had problems with is that the default cache prefix was different for drush and the browser, that's why drush cache clear didn't work: #2846208: Improve default cache prefix
This is fixed now in beta1.
Introducing a command to actually delete all the records could be added but that would be a new feature and running drush redis-flushall isn't easier than running redis-cli flushall IMHO.
Comment #21
yang_yi_cn commentedThe logic in comment #16 seems to be during hook_cache_flush(), flush Redis cache (only when there's a prefix):
This should work in Drupal Admin UI at least.
With the cache prefix in #2846208, I think the approach of hook into hook_cache_flush() is appropriate, as it doesn't break other applications (if they are sharing same Redis instance).
For performance penalties:
- on dev / non-production environments, the ability to flush cache is definitely more important
- on production environment I think it's understandable that flushing Drupal cache could be an expensive operation.
So I think we should merge this patch.
We don't need invent another drush command for this.
Comment #22
berdirAgain, for what purpose? The data is not deleted, but functionally, as far as Drupal is concerned, the cache *is* invalidated. If you want to empty it, there is also redis-cli.
The patch doesn't scale if you have a lot of data, keys() should not be used for that and it could also be very slow.
#2840037: Allow dedicated redis connections and/or redis db numbers per feature is another issue that when resolved, would allow for actually deleting data.
IMHO this is a won't fix.
Comment #23
amonteroFYI, since KEYS command is not recommended in production, you might be interested in the somewhat related #2851625: New feature: option to use SCAN command instead of KEYS on cache wildcard deletions
Comment #24
grimreaperHello,
I am testing Redis 1.0.0-beta1 without the patch.
If I create a new template and run drush cr the template is taken into account.
EDIT: As said by Berdir this is now fixed by the improved cache prefix.
Comment #26
mstills commentedIs this patch no longer relevant for beta1?
https://www.drupal.org/files/issues/redis-n2765895-16.patch
I am having issues with cache flush on beta 1. Does not seem to be working correctly. Like many people, I am using base 0 (the default). However, this falsy check will fail you if you are using the default NULL or 0 database index:
Could I take a stab at a new patch for this please?
Comment #27
nimoatwoodwayAdding
$settings['cache_prefix']like described in README.md fixed it for me.Before I set cache_prefix I had to run
redis-cli FLUSHALLafter usingdrush cache:rebuildto get changes active. After adding the cache_prefix I even do not need acache:rebuildfor e.g. views config changes.Comment #28
weseze commentedI have a relevant use case that needs this behaviour. At the moment it is hypothetical for me, but will become a reality soon.
I have 1 Redis instance, shared with 100 websites, using prefixes to differentiate cache data for those websites.
A website is updated, causing almost all of the cache data to become irrelevant/stale. For example moving from a single language site to a multi-language site would cause all page cache to become invalid.
But now the Redis instance is at max memory usage and starts clearing old data to make room for this new cache data from the updated website.
So now valid cache-data from other websites, that is considered much older, is being deleted...
Running commands on a live webserver to fix this, is not something that can be expected from any developer on your team. Also, the timing in this use case would be very important. So waiting for a developer with access (and knowledge) to the live webserver might be a real issue in this scenario.
An option to flush these caches separately would be required in this scenario.
Ideally a complete cache rebuild would also flush redis cache, or maybe this could be a configuration that is disabled by default? (with a very big warning on possible performance impact)
Please consider reopening this ticket, perhaps marking it as a feature request because of the performance issues.
Comment #29
damienmckenna@weseze: Sounds like a feature request that should go into a new issue?
Comment #30
berdirYes. The module is specifically designed to not require KEYS or SCAN commands at runtime (except the report), with the downside of leaving data in place. In our case, we actually empty the redis cache on deployment with a flushall. It should be fairly easy to write a deploy script that uses KEYS or SCAN to only delete keys with a given prefix. But not sure about adding it to the project, could also just be a documentation page.
Comment #31
fengtanWe have been working on this recently and came up with this script -- does that make sense ?
Comment #32
axroth commentedWhat do you think of that approach?
Comment #33
kenorb commentedAs per #26 comment, "if (!$redisDatabaseIndex" won't work in patch #16, as it's ignoring "0", change it to "!isset($redisDatabaseIndex)" instead.
Comment #36
carlos romero commentedHello, I have made a fork and uploaded a commit with the code from DamienMcKenna comment #16, I have modified the first condition, replacing !$redisDatabaseIndex with "!isset($redisDatabaseIndex)" as kenorb commented #33.
For me, in a drupal 9 with the latest version of dockerhub of redis, clearing caches works using
$settings['redis.connection']['base'] = 0;
and
$settings['cache_prefix'] = 'mysite_';
Tested running DBSIZE on redis-cli after and before do drush cr on drupal terminal.
I have made the merge request.
Thanks.
Comment #37
johan den hollander commentedJust tested with #16 patch and MR #21.
With 16 the Redis cache is not flushed. While with the MR it works correctly.