Строки: основной тип данных Redis
Строка — самый простой и самый используемый тип в Redis. Но «строка» здесь значит куда больше, чем текст.
В Redis строка — это просто последовательность байтов длиной до 512 МБ. Текст, число, картинка, сериализованный объект — всё это «строки».
Когда вы делаете SET key value, вы создаёте строку. Это базовый кирпич Redis. Но не дайте слову «строка» себя обмануть: внутри может лежать что угодно — текст, число, JSON, даже бинарные данные вроде картинки.
Базовые команды
127.0.0.1:6379> SET name "Анна"
OK
127.0.0.1:6379> GET name
"Анна"
127.0.0.1:6379> STRLEN name
(integer) 8
127.0.0.1:6379> APPEND name " Иванова"
(integer) 24
127.0.0.1:6379> GET name
"Анна Иванова"
127.0.0.1:6379> SET counter 10
OK
127.0.0.1:6379> GETSET counter 20
"10"
STRLEN — длина строки в байтах (кириллица в UTF-8 занимает 2 байта на символ). APPEND — дописать в конец. GETSET — атомарно вернуть старое значение и записать новое.
Опции SET
Команда SET гибкая и часто заменяет несколько команд сразу:
SET key val EX 60 # с TTL 60 секунд
SET key val NX # только если ключа НЕ было
SET key val XX # только если ключ УЖЕ был
SET key val KEEPTTL # сохранить существующий TTL
SET key val GET # вернуть старое значение
Особенно важна опция NX — «установить, только если не существует». Это атомарная операция, на которой строятся распределённые блокировки. Об этом будет урок в разделе про кэширование.
Хранение нескольких значений
127.0.0.1:6379> MSET k1 "a" k2 "b" k3 "c"
OK
127.0.0.1:6379> MGET k1 k2 k3
1) "a"
2) "b"
3) "c"
MSET и MGET работают с несколькими ключами за один запрос — это экономит сетевые круги (round-trips), что критично для производительности.
Один MGET вместо трёх GET
Плохо: App -> GET k1 -> ответ
App -> GET k2 -> ответ 3 круга по сети
App -> GET k3 -> ответ
Хорошо: App -> MGET k1 k2 k3 -> ответ 1 круг
Как работает под капотом
Redis хранит строки в структуре SDS (Simple Dynamic String). В отличие от си-строк, SDS хранит длину явно — поэтому STRLEN работает за O(1), а не сканирует строку. SDS также позволяет хранить бинарные данные с нулевыми байтами внутри. Короткие строки, похожие на числа, Redis хранит как целые числа (int encoding), экономя память и ускоряя инкременты.
Частые ошибки
- Хранить гигантские значения. Строка до 512 МБ, но огромные значения замедляют сеть и блокируют сервер при чтении/записи.
- Делать много отдельных GET вместо MGET. Сетевая задержка на каждый запрос убивает производительность.
- Путать
APPENDс перезаписью. APPEND дописывает, не заменяет.
Best practices
- Группируйте операции через
MSET/MGETи пайплайнинг, чтобы экономить круги по сети. - Для значений-флагов и блокировок используйте
SET key val NX EX. - Держите значения компактными; для структурированных данных рассмотрите хеши вместо одной большой JSON-строки.
Итог: Строка — универсальный тип Redis для байтов любого вида. SET с опциями заменяет множество команд. MSET/MGET экономят сеть. Внутри строки лежат в эффективной структуре SDS, а числовые строки оптимизируются отдельно.
Битовые операции и подстроки
Строка в Redis — не монолит: к ней есть команды для работы с частями и даже с отдельными битами. Это расширяет применение базового типа далеко за «положить текст»:
SETRANGE key 5 "XYZ" # переписать часть строки с позиции 5
GETRANGE key 0 4 # прочитать подстроку (байты 0..4)
SETBIT flags 7 1 # установить 7-й бит в 1
GETBIT flags 7 # прочитать бит
BITCOUNT flags # сколько единичных битов
Битовые операции превращают строку в компактный массив флагов: миллион булевых значений «да/нет» помещается всего в ~125 КБ. Это основа для bitmap-аналитики (кто заходил сегодня, кто прочитал уведомление) — подробнее в разделе про продакшен.
Ещё одна частая операция — атомарная замена с возвратом старого значения через SET key new GET (современная замена устаревшего GETSET). Она полезна, когда нужно «забрать и обнулить» счётчик или флаг за одну команду, не опасаясь, что между чтением и записью кто-то вклинится.
Строки как ячейки кэша
На практике строка чаще всего выступает именно как единица кэша: в неё кладут сериализованный объект (JSON, MessagePack) и снабжают его TTL. Это самый прямой способ закэшировать результат дорогого запроса:
SET cache:product:1001 "{...сериализованный товар...}" EX 600
GET cache:product:1001
Здесь работают все опции SET сразу: EX задаёт срок жизни кэша, а NX пригодится, если нужно «закэшировать только если ещё не закэшировано». Если же объект меняется по частям и важны частичные обновления — лучше хранить его не одной строкой, а хешем, о котором будет отдельный урок. Выбор между «строка с JSON» и «хеш» сводится к тому, читаете ли вы объект целиком (тогда строка проще и быстрее) или часто меняете отдельные поля (тогда хеш экономнее).