Фильтрация записей хэша Redis - PullRequest
12 голосов
/ 15 апреля 2011

Я использую Redis для хранения хешей с ~ 100 тыс. Записей на хеш.Я хочу реализовать фильтрацию (огранку) записей в данном хеше.Обратите внимание, что запись хеша может принадлежать n фильтрам.

После прочтения this и this похоже, что я должен:

  1. Реализация aотсортировано SET на фильтр.Значения в SET соответствуют ключам в HASH.
  2. Извлечение ключей HASH из заданного SET фильтра.
  3. Как только у меня есть ключи HASH из SET, извлеките соответствующие записи изHASH.Это должно дать мне все записи, которые принадлежат фильтру.

Во-первых, корректен ли вышеуказанный подход на высоком уровне?

Предполагая, что подход в порядке, бит, который мне не хватает,Какова наиболее эффективная реализация для получения записей HASH?Правильно ли я думаю, что, получив ключи HASH, я должен использовать PIPELINE для постановки в очередь нескольких команд HGETALL, проходящих через каждый ключ HASH?Есть ли лучший подход?

Меня беспокоит использование PIPELINE, так как я считаю, что оно заблокирует всех других клиентов при обслуживании команды.Я буду пейджировать отфильтрованные результаты с 500 результатами на страницу.С несколькими клиентами на основе браузера, выполняющими фильтрацию, не говоря уже о внутренних процессах, которые заполняют SET и HASH, кажется, что существует вероятность большого количества конфликтов, если PIPELINE блокирует.Может ли кто-нибудь предоставить представление об этом?

Если это поможет, я использую 2.2.4 redis, предисловие для веб-клиентов и пакет служб для серверной части.

Спасибо, Пол

Ответы [ 3 ]

5 голосов
/ 18 апреля 2011

Отдельные операции блокируются, но это не имеет значения, так как они не должны выполняться долго.Похоже, вы извлекаете больше информации, чем вам действительно нужно - HGETALL вернет 100 000 элементов, когда вам нужно всего лишь 500.

Отправка 500 операций HGET может работать (при условии, что набор хранит как хэш, так и ключ), хотя возможно, чтоиспользование хешей вообще - это случай преждевременной оптимизации - вам лучше использовать обычные ключи и MGET.

4 голосов
/ 05 мая 2011

Redis - это неблокируемый неблокирующий асинхронный сервер, поэтому при использовании конвейеризации не добавляется конкуренция . Redis радостно обрабатывает каждую операцию, как только получает их, поэтому на практике может обрабатывать несколько конвейерных операций. По сути, Redis-серверу действительно все равно, конвейерная операция или нет, он просто обрабатывает каждую операцию по мере их получения.

Преимущество конвейеризации заключается в уменьшении задержки клиента, когда вместо ожидания ответа от redis-сервера для каждой операции перед отправкой следующей, клиент может просто закачать все операции за одну запись, а затем прочитать все ответы в одном чтении.

Примером этого в действии является мой Redis mini StackOverflow клон , каждый щелчок которого вызывает ToQuestionResults(), который, поскольку операции передаются по конвейеру, отправляет все операции при 1 вызове записи Socket и считывает результаты в 1 чтение блокировки сокета, которое более эффективно, чем чтение блокировки на вызов:

https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/RedisStackOverflow/RedisStackOverflow.ServiceInterface/IRepository.cs#L180

Мое беспокойство по поводу использования ТРУБОПРОВОДА что я верю, что это заблокирует все остальные клиенты во время обслуживания команды.

Это недопустимая проблема, и я бы не стал задумываться о том, как Redis работает здесь, предположим, что он делает это наиболее эффективно, когда Pipelining не блокирует обработку команд других клиентов. Концептуально вы можете думать, что redis-сервер обрабатывает каждую команду (конвейерную или нет) в порядке FIFO (то есть не тратится время на ожидание / чтение всего конвейера).

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

Вот как redis достигает атомарности, обрабатывая каждую команду по одной, как только она их получает. Поскольку нет других потоков, нет переключения контекста потока, нет блокировок и нет проблем с многопоточностью. Он в основном достигает параллелизма, обрабатывая каждую команду очень быстро.

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

2 голосов
/ 15 июня 2011

Я думаю, вы неправильно понимаете, что делает конвейерная обработка. Он не блокируется во время отправки всех команд. Все, что он делает, это буферизует команды, затем выполняет их все сразу в конце, так что они выполняются так, как если бы они были одной командой. Ни в коем случае не происходит блокировка. То же самое относится и к Redis multi / exec. Ближайшая вещь, которую вы получаете к блокировке / блокировке в redis - это оптимистическая блокировка с использованием watch, которая приведет к сбою exec, если ключ redis был записан с тех пор, как вы вызвали watch.

Еще эффективнее, чем hget 500 раз в блоке конвейера, просто вызывать hmget('hash-key',*keys), где keys - это массив из 500 ключей хеша, которые вы ищете. Это приведет к одному вызову redis, который будет таким же, как если бы он был конвейерным, но должен выполняться быстрее, поскольку вы не выполняете цикл в ruby.

...