Удаление подстановочного знака Redis

Я использую поставщика redis stackexchange и пытаюсь удалить все ключи, начиная с определенного ключа.

private readonly Lazy<IEnumerable<IServer>> allServers = new Lazy<IEnumerable<IServer>>(() => Connection.GetEndPoints().Select(s => Connection.GetServer(s)));
private const int DbId = 1;
private const int ScanPageSize = 1 << 14;

public void RemoveByPattern(string pattern)
{
    var keys = this.AllServers.Value.SelectMany(x => x.Keys(DbId, pattern + "*", ScanPageSize)).Distinct().ToArray();
    if (!keys.Any())
        return;
    this.Database.KeyDelete(keys);
}

^^ Это метод, который я придумал, который отлично работает в большинстве случаев. Но как только я немного нагружаю систему, я получаю ошибки, которые выглядят так:

  System.TimeoutException: Timeout performing SCAN, inst: 0, mgr: Inactive, queue: 11, qu=11, qs=0, qc=0, wr=0/1, in=0/0
     at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl (StackExchange.Redis.StrongName, Version=1.0.316.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46)
     at StackExchange.Redis.RedisServer.ExecuteSync (StackExchange.Redis.StrongName, Version=1.0.316.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46)
     at StackExchange.Redis.RedisBase+CursorEnumerable`1.GetNextPageSync (StackExchange.Redis.StrongName, Version=1.0.316.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46)
     at StackExchange.Redis.RedisBase+CursorEnumerable`1+CursorEnumerator.MoveNext (StackExchange.Redis.StrongName, Version=1.0.316.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46)
     at System.Linq.Enumerable+<SelectManyIterator>d__1`2.MoveNext (System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
     at System.Linq.Enumerable+<DistinctIterator>d__1`1.MoveNext (System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
     at System.Linq.Buffer`1..ctor (System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
     at System.Linq.Enumerable.ToArray (System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
     at Test.RedisCacheManager.RemoveByPattern (TestApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null)

Есть ли лучший способ сделать это? Я знаю, что если бы я знал обо всех ключах на стороне .net, я мог бы избежать сканирования. Но, к сожалению, в моем случае это не так просто.


person Sam7    schedule 25.09.2015    source источник
comment
Также обратите внимание, что ваш код не совместим с кластером. Вам следует рассмотреть возможность использования механизма тегов для поддержания связи между ключами, как в CachingFramework.Redis.   -  person thepirat000    schedule 25.09.2015
comment
Пожалуйста, проверьте мой ответ здесь, чтобы удалить ключи по шаблону   -  person Kobynet    schedule 01.03.2016
comment
Возможный дубликат Redis Stack Exchange, как удалить или получить ключи по шаблону   -  person Paul Roub    schedule 14.04.2016


Ответы (3)


Я ответил на аналогичный вопрос здесь. Вы можете использовать следующее со StackExchange.Redis.StrongName v1.0.488.

        foreach (var ep in _muxer.GetEndPoints())
        {
            var server = _muxer.GetServer(ep);
            var keys = server.Keys(database: _redisDatabase, pattern: pattern + "*").ToArray();
            _db.KeyDeleteAsync(keys);
        }

_muxer является экземпляром ConnectionMultiplexer

person Kerem Demirer    schedule 14.04.2016

Вместо удаления по шаблону вы должны иметь возможность хранить частичные ключи или задействованные ключи в некотором наборе, а затем сканировать его (т. е. sscan) с помощью страниц. чтобы удалить глобальные ключи пространства ключей.

Не пытайтесь удалить тысячи ключей за один проход: помните, что Redis — это однопоточное решение, и ваше удаление заблокирует весь сервер Redis.

person Matías Fidemraizer    schedule 25.09.2015
comment
Есть идеи, как это сделать на С#? - person Sam7; 25.09.2015
comment
@Sam7 Всякий раз, когда вы добавляете ключ, который хотите удалить позже в глобальном пространстве, вы создаете набор, используя IDatabase.SetAdd или IDatabaseAsync.SetAddAsync - person Matías Fidemraizer; 25.09.2015

Есть несколько вариантов сделать то, что вы хотите, но я согласен с @Matías в том, что вам нужно сохранить ключи, которые вы хотите удалить позже, в SET.

Если вы используете автономный Redis, наиболее надежным способом будет выполнение операций добавления/удаления в сценарии Lua. Но если вы планируете иметь кластер Redis, вам придется делать это на стороне клиента.

Например:

public void SetValue(string key, string value)
{
    var batch = db.CreateBatch(); // You can use a transaction with CreateTransaction() if you are not in a cluster.
    batch.StringSetAsync(key, value);
    batch.SetAddAsync("to remove", key);
    batch.Execute();
}
public void RemoveAll()
{
    var item = db.SetPop("to remove");
    while (item.HasValue)
    {
        db.KeyDelete(item.ToString());
        item = db.SetPop("to remove");
    }
}
person thepirat000    schedule 25.09.2015