Что происходит при запросе с использованием звездочки в Redis
Что проверяют
Понимаете ли вы, что Redis выполняет команды в один поток, и что стоит за удобной звёздочкой в KEYS user:*. Вопрос обычно задают после рассказа про кэш в сервисе на Python: смотрят, знаете ли вы цену команды и умеете ли перебирать ключи безопасно.
Как отвечать
Звёздочка это glob-шаблон, его понимают KEYS, SCAN ... MATCH и подписка PSUBSCRIBE. Символ * заменяет любое число символов, ? ровно один, в квадратных скобках задаётся набор.
KEYS pattern обходит всё пространство ключей текущей базы: индекса по именам нет, поэтому стоимость линейна по числу ключей. Пока команда работает, Redis не обслуживает никого: команды выполняются по одной в одном потоке, и на базе в миллионы ключей это заметная пауза сразу для всех клиентов. Клиентский таймаут тут не спасает, сервер всё равно доведёт команду до конца.
Рабочий вариант это курсорный обход:
for key in r.scan_iter(match="user:*", count=1000):
...SCAN возвращает пачку и курсор, между вызовами сервер свободен. Гарантии слабее: ключ, живший всю итерацию, будет отдан хотя бы раз, но может прийти дважды, а появившиеся и удалённые по ходу могут не прийти вовсе. Для полей и элементов есть HSCAN, SSCAN, ZSCAN.
Сильный ответ заканчивается тем, что перебор ключей вообще не способ искать данные: нужен свой индекс, отдельное множество идентификаторов или ключ, который вычисляется по известному шаблону.
Где спотыкаются
Говорят, что KEYS медленный на больших базах, и меряют на дев-стенде с тысячей ключей. Проблема не в размере ответа, а в блокировке: одна такая команда в фоновом скрипте поднимает задержку всему сервису, включая запросы, которые к этим ключам отношения не имеют.
Второе: меняют KEYS на SCAN и пишут цикл, который прерывается на пустой пачке. MATCH фильтрует уже выбранную порцию, поэтому пустые пачки это норма, а признак конца обхода только курсор, равный нулю.
Третье: забывают про дубликаты и про кластер. Один ключ может прийти в нескольких пачках, так что результат складывают в множество, а KEYS и SCAN работают в пределах одного узла, и в кластере обход надо повторить для каждого мастера.