Освоение Redis GET и SET: Основные операции с данными
Освойте основы управления данными в Redis с помощью этого подробного руководства по командам `GET` и `SET`. Изучите базовое сохранение и извлечение строк, а также важные расширенные опции, такие как атомарная установка (`NX`/`XX`) и встроенное истечение срока действия ключа (`EX`/`PX`). Узнайте, как эти фундаментальные команды необходимы для создания высокопроизводительных кэширующих слоев.
Освоение Redis GET и SET: Основные операции с данными
Redis GET и SET выглядят почти слишком простыми. Записать значение. Прочитать значение. В реальных приложениях эти две команды лежат в основе сессий входа, функциональных флагов, ограничений скорости, записей кэша, кратковременных блокировок и сокращений "пожалуйста, не запрашивайте базу данных снова".
Детали имеют значение, потому что Redis делает именно то, что вы просите. Если вы случайно перезапишете ключ, он не спросит, имели ли вы это в виду. Если вы забудете установить срок действия для кэшированных данных, они могут жить дольше, чем источник данных. Если вы будете обрабатывать отсутствующий ключ так же, как пустую строку, ваше приложение может принять неверное решение.
Модель "ключ-значение" Redis
Прежде чем углубляться в команды, важно помнить, что Redis работает по простой модели хранилища ключ-значение. Каждый фрагмент данных (значение) доступен с помощью уникального идентификатора (ключа). Ключи — это строки, а значения могут быть различных типов данных (строки, списки, множества, хэши и т.д.). SET и GET в первую очередь работают с типом данных String, который является самым базовым и часто используемым типом в Redis.
1. Установка данных: Команда SET
Команда SET используется для присвоения значения ключу. Если ключ уже содержит данные, команда SET перезапишет существующее значение. Ее базовый синтаксис прост.
Базовый синтаксис и использование
Самая простая форма требует только ключ и значение:
SET key value
Пример: сохранение отображаемого имени пользователя:
127.0.0.1:6379> SET user:100:name "Alice Johnson"
OK
127.0.0.1:6379> GET user:100:name
"Alice Johnson"
Расширенные опции SET: NX, XX и срок действия
Мощь SET проявляется в его необязательных аргументах, которые позволяют выполнять атомарную условную установку и управление временем жизни (TTL). Эти опции жизненно важны для правильной реализации блокировок и кэшей.
Условная установка: NX и XX
Эти опции контролируют, когда происходит операция установки, предотвращая случайные перезаписи или гарантируя, что перезапись произойдет только в том случае, если ключ существует.
NX(Not Exists - Не существует): Устанавливает ключ только в том случае, если он не существует. Полезно для операций "только создание" и простых шаблонов блокировок.SET my_lock_key some_unique_value NXXX(Exists - Существует): Устанавливает ключ только в том случае, если он уже существует. Полезно, когда вы хотите обновить известный ключ, случайно не создав новый.SET session:token:456 new_value XX
B. Установка времени истечения (TTL)
Для управления памятью и реализации временного кэширования вы можете установить время истечения непосредственно в команде SET. Это гораздо эффективнее, чем устанавливать ключ, а затем вызывать EXPIRE отдельно.
EX секунды: Устанавливает время истечения в секундах.PX миллисекунды: Устанавливает время истечения в миллисекундах.EXAT временная_метка: Устанавливает истечение на определенную временную метку Unix (секунды).PXAT временная_метка: Устанавливает истечение на определенную временную метку Unix (миллисекунды).
Пример: установка ключа с истечением через один час:
127.0.0.1:6379> SET cache:product:500 "Product Details" EX 3600
OK
127.0.0.1:6379> TTL cache:product:500
(integer) 3598
Используйте SET key value EX N или PX N для записей кэша. Это делает запись и истечение частью одной команды, что позволяет избежать распространенной ошибки, когда приложение записывает ключ кэша и вылетает до вызова EXPIRE.
Комбинирование опций
Все опции часто можно комбинировать для сложных атомарных операций:
# Установить ключ только если он не существует, и сделать так, чтобы он истек через 60 секунд
SET my_config_setting "active" NX EX 60
2. Извлечение данных: Команда GET
Команда GET извлекает строковое значение, связанное с заданным ключом. Это одна из самых быстрых операций, выполняемых Redis, часто завершающаяся за микросекунды.
Базовый синтаксис и использование
GET key
Пример: Извлечение сохраненного имени пользователя
127.0.0.1:6379> GET user:100:name
"Alice Johnson"
Обработка несуществующих ключей
Если ключ не существует, GET возвращает специальный ответ, указывающий, что ничего не найдено:
127.0.0.1:6379> GET non_existent_key
(nil)
В коде приложения получение (nil) является стандартным способом определить, что данные отсутствуют, что обычно вызывает промах кэша, при котором приложение должно получить данные из первичного источника (например, базы данных) и затем записать их обратно в Redis.
Получение значения с изменением срока действия: GETEX
Базовая команда GET возвращает только значение. Она не возвращает оставшийся TTL. Если вам нужен TTL, используйте TTL key или PTTL key как отдельную команду.
GETEX отличается: он возвращает значение и одновременно изменяет срок действия ключа. Это полезно для поведения скользящей сессии, когда каждое чтение продлевает время жизни сессии.
GETEX session:abc123 EX 1800
Это читает значение сессии и сбрасывает срок действия на 30 минут. Не используйте это casually для обычного чтения кэша, потому что каждое чтение становится операцией, подобной записи, которая изменяет метаданные ключа.
3. Практическое применение: Кэширование с помощью GET и SET
Основной вариант использования GET и SET — реализация простого шаблона cache-aside.
Шаги в логике приложения:
- Попробовать
GET product:500. - Если Redis возвращает значение, декодировать его и вернуть.
- Если Redis возвращает nil, получить продукт из первичной базы данных.
- Сохранить сериализованный результат с помощью
SET product:500 <json> EX 300. - Вернуть результат вызывающему коду.
Этот шаблон может снизить нагрузку на базу данных, но также создает окно устаревших данных. Если продукт изменится в базе данных, Redis может продолжать выдавать старое значение до истечения TTL или пока ваше приложение не инвалидирует ключ. Выбирайте TTL на основе того, насколько устаревшие данные допустимы, а не только того, сколько трафика вы хотите сэкономить.
Именование ключей без создания беспорядка
Redis не требует соглашения об именовании, но ваш будущий "я" будет вам благодарен. Читаемый шаблон, такой как user:100:name, product:500:summary или rate:user:100:login, значительно упрощает отладку с помощью redis-cli.
Делайте ключи понятными и достаточно короткими. Экономия нескольких байт за счет именования ключа u:100:n редко оправдывает путаницу, если только вы не работаете в очень большом масштабе и не измерили накладные расходы на ключи. Для большинства команд согласованность важнее, чем чрезвычайная краткость.
Будьте осторожны с предоставленными пользователем значениями в ключах. Если адрес электронной почты, URL или имя арендатора становятся частью ключа, сначала нормализуйте его. В противном случае небольшие различия в форматировании могут создать дублирующиеся записи кэша:
[email protected]
[email protected]
[email protected]
Все они могут представлять одного и того же пользователя для вашего приложения, но разные ключи для Redis.
Перезаписи, пустые значения и Nil
SET перезаписывает по умолчанию:
SET config:mode "safe"
SET config:mode "fast"
GET config:mode
Конечное значение — "fast". Если перезапись может быть опасной, используйте NX или XX.
Также различайте отсутствующий ключ и пустое значение. Nil в Redis означает, что ключ отсутствует. Пустая строка — это реальное сохраненное значение:
SET user:100:nickname ""
GET user:100:nickname
Ваша клиентская библиотека может представлять их по-разному: null, None, nil, пустая байтовая строка или пустая строка. Проверьте поведение клиента, а не гадайте.
Безопасный шаблон блокировки с предупреждением
Вы часто будете видеть этот шаблон:
SET lock:invoice:123 "worker-7:1700000000" NX EX 30
Это означает "создать эту блокировку, только если она не существует, и сделать так, чтобы она истекла через 30 секунд". Срок действия не является необязательным. Без него упавший воркер может оставить блокировку навсегда.
Для простых одноэкземплярных установок Redis этого шаблона часто достаточно для низкорисковой координации. Для критически важной распределенной блокировки при сбоях, рассинхронизации часов и нескольких узлах Redis используйте хорошо протестированную библиотеку и понимайте ее компромиссы. Ошибка в блокировке может превратиться в ошибку повреждения данных.
Отладка с помощью redis-cli
Когда путь GET или SET ведет себя странно, проверьте ключ напрямую:
redis-cli GET product:500
redis-cli TTL product:500
redis-cli TYPE product:500
TYPE полезен, потому что GET работает только со строковыми значениями. Если ключ содержит хэш, список, множество или сортированное множество, Redis возвращает ошибку неверного типа. Обычно это означает, что две части приложения используют одно и то же имя ключа для разных целей.
Если вам нужно проверить несколько связанных ключей во время разработки, SCAN безопаснее, чем KEYS на загруженном production-сервере:
redis-cli SCAN 0 MATCH 'product:500:*' COUNT 100
KEYS * может заблокировать Redis во время сканирования пространства ключей. Это нормально для крошечного локального экземпляра. Это плохая привычка на production.
Выбор TTL в реальных системах
Выбор TTL — это решение, касающееся продукта и операций, а не трюк Redis. Кэш профиля пользователя может терпеть пять минут устаревания. Проверка разрешений может потребовать гораздо более короткого TTL или явной инвалидации. Функциональный флаг может нуждаться в почти мгновенных обновлениях, если он контролирует рискованный запуск.
Вот три распространенных шаблона:
SET cache:product:500 "<json>" EX 300
SET session:abc123 "<json>" EX 1800
SET rate:user:100:login "1" EX 60 NX
Кэш продукта может быть немного устаревшим. Сессия имеет четкое время жизни. Ключ ограничения скорости использует NX, чтобы первая попытка создала окно, а последующие попытки могли увеличивать или проверять связанные ключи в зависимости от дизайна.
Избегайте ключей "вечного кэша", если у вас нет четкого пути инвалидации. Вечный кэш со временем становится второй базой данных, обычно без операционной дисциплины, которую вы применяете к реальной базе данных.
Детали сериализации
Строки Redis являются бинарно-безопасными. Они могут содержать JSON, MessagePack, сжатые данные, счетчики или обычный текст. Команде все равно. Вашему приложению — нет.
JSON легко проверять:
SET product:500 "{\"id\":500,\"name\":\"Desk Lamp\"}" EX 300
Бинарные форматы могут сэкономить место или CPU в некоторых приложениях, но они усложняют отладку в терминале. Сжатие может помочь для больших повторяющихся данных, но также добавляет затраты CPU и может скрыть тот факт, что вы кэшируете слишком большие объекты.
Для счетчиков не читайте с помощью GET, не добавляйте в приложении и не записывайте с помощью SET, если несколько клиентов могут обновлять один и тот же ключ. Вместо этого используйте атомарные команды счетчиков Redis:
INCR page:view:500
EXPIRE page:view:500 86400
Для счетчиков с первой записью и сроком действия используйте транзакцию или небольшой Lua-скрипт, если вам нужно строгое поведение. В противном случае четко осознавайте, какое состояние гонки вы принимаете.
Избегание коллизий ключей
Две команды, использующие одну и ту же базу данных Redis, могут случайно повторно использовать ключ, например user:100. Одна команда сохраняет JSON с помощью SET; другая сохраняет поля с помощью HSET. Следующий GET вернет ошибку неверного типа, и обе команды потеряют время.
Пространства имен помогают:
shop:prod:user:100:profile
shop:prod:session:abc123
billing:prod:invoice:9001
Вам не нужны мучительно длинные ключи, но включите достаточно контекста, чтобы избежать коллизий между средами, сервисами и типами данных. Если вы используете общий Redis для нескольких приложений, соглашение об именовании является частью интерфейса.
Когда не использовать GET и SET
Строки — это отправная точка, а не вся модель Redis. Если вы часто обновляете одно поле внутри большого JSON-блобa, хэш может быть чище:
HSET user:100 name "Alice Johnson" email "[email protected]"
HGET user:100 email
Если вам нужны упорядоченные события, используйте потоки или списки. Если вам нужны проверки членства, используйте множества. Если вам нужен рейтинг, используйте сортированные множества. Перезапись всей сериализованной строки для каждого небольшого изменения проста на первый взгляд, но может стать дорогой и неудобной по мере роста объекта.
Небольшой контрольный список перед запуском
Прежде чем запустить новый путь GET и SET, задайте несколько простых вопросов.
- Каково точное имя ключа?
- Могут ли два сервиса случайно использовать один и тот же ключ?
- Должен ли ключ истекать?
- Что произойдет, когда Redis вернет nil?
- Допустима ли перезапись, или следует использовать
NXилиXX? - Достаточно ли мало значение, чтобы читать и записывать его как одну строку?
- Можете ли вы отладить значение из
redis-cli, если поведение на production выглядит неправильным?
Эти вопросы позволяют выявить большинство базовых ошибок со строками Redis до того, как они станут инцидентами. Синтаксис команд прост. Жизненный цикл ключа — вот где обычно прячутся ошибки.
GET и SET — это маленькие команды с большим операционным весом. Используйте срок действия для данных кэша, используйте NX или XX, когда перезаписи имеют значение, обрабатывайте nil как отдельное состояние и поддерживайте имена ключей достаточно согласованными, чтобы кто-то мог отладить их из терминала. Как только строки начинают казаться тесными, перемещайте связанные поля в хэши и используйте структуру данных, соответствующую шаблону доступа.