aspnet/Caching

建议增加按前缀清理缓存的接口

molinjinyi opened this issue · 2 comments

public static void KeyDeleteWithPrefix(this IDatabase database, string prefix)
        {
            if (database == null)
            {
                throw new ArgumentException("Database cannot be null", "database");
            }

            if (string.IsNullOrWhiteSpace(prefix))
            {
                throw new ArgumentException("Prefix cannot be empty", "database");
            }

            database.ScriptEvaluate(@"
                local keys = redis.call('keys', ARGV[1]) 
                for i=1,#keys,5000 do 
                redis.call('del', unpack(keys, i, math.min(i+4999, #keys)))
                end", values: new RedisValue[] {prefix});
        }
public void Clear()
        {
            Database.KeyDeleteWithPrefix(GetLocalizedKey("*"));
        }

对于列表数据,你很难用明确的key来定位删除,没有这个接口缓存是不完美的

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading.Tasks;

namespace Microsoft.Extensions.Caching.Distributed
{
    public interface IDistributedCache
    {
        byte[] Get(string key);

        Task<byte[]> GetAsync(string key);

        void Set(string key, byte[] value, DistributedCacheEntryOptions options);

        Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options);

        void Refresh(string key);

        Task RefreshAsync(string key);

        void Remove(string key);

        Task RemoveAsync(string key);
    }
}

或者把连接暴露出来,让开发者更自由的使用

See it seems to be the official issue to talk about the use cases around prefix based operation. It would be a good idea to translate the issue in english :) (yes I know about google translate ^^).

As I have a similar need, I'd like to share where I stand today.

Use case

I have a tree which takes a lot of computing to be built and which is different for each user depending on there permissions (ACL on that tree). Currently I build a full tree whenever it's invalidated and put it in cache. When a user requests it, I'd filter it based on his permissions and put it in cache so further requests would be fast.

When the tree is update, I would need to expire all user specific keys.

First Idea

At first I tried to find a way to clear keys with a specified prefix and I was headed towards a similar solution as the OP. Except I was going to base it on HSCAN instead of KEYS which could lead to serious performance issues. However, the cursor approach can skip newly created keys, which would add a bit more work on my business logic to make sure that everything behave as expected.

A more generic way of describing my need is I have n keys which share a dependencies. How can we expire them when the dependencies changes.

In addition this solution would have been tightly coupled to Redis

Second Idea

Someone suggested on another issue over here to try to the loop on the server client side and delete the keys whether they exist or not. In my case it felt really weird as I would try to delete thousands of keys to delete only a couple hundreds maybe less. It felt pretty ineffective but at least it would not be dependent on Redis

What I'm doing

I finally decided to go towards a third solution. root dependencies (authorizations and tree) are now versioned. the value of the keys are prefix with that version. When I fetch the data from the cache, I fetch two keys one which is the current version of the dependencies and the user cache key. I compare the prefix of the user cached value with the version. If there a mismatch I discard it and compute fresh data.

I see redis specific possible improvments using keyspace notifications to have the current version being pushed instead of pulled.

Conclusion

It can be implemented today on top of the current DistributedCache interface so no big deal. However supporting something in the cache would enable optimizations for each providers.

As I feel that it is not an uncommon use case, I would be really happy to hear about any suggestions and opinions on the matter.

We periodically close 'discussion' issues that have not been updated in a long period of time.

We apologize if this causes any inconvenience. We ask that if you are still encountering an issue, please log a new issue with updated information and we will investigate.