← Назад к вопросам

Какие типы данных поддерживает Redis?

1.2 Junior🔥 201 комментариев
#Базы данных (NoSQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Типы данных в Redis

Redis (Remote Dictionary Server) — это in-memory хранилище ключ-значение, которое поддерживает различные структуры данных. Это отличает его от обычных кэшей и делает мощным инструментом для различных задач.

1. String (Строка)

Самый простой тип — бинарные строки длиной до 512 MB.

import redis

red = redis.Redis(host='localhost', port=6379, db=0)

# Установка
red.set('user:1:name', 'Alice')

# Получение
name = red.get('user:1:name')  # b'Alice'
name_str = red.get('user:1:name').decode()  # 'Alice'

# Работа с числами
red.set('counter', 0)
red.incr('counter')  # 1
red.incr('counter')  # 2
red.incrby('counter', 5)  # 7
red.decr('counter')  # 6

# Работа со строками
red.append('message', ' World')  # добавить в конец
red.strlen('message')  # длина строки
red.getrange('message', 0, 4)  # подстрока
red.setrange('message', 6, 'Redis')  # заменить часть

# Bitwise операции (для флагов)
red.setbit('flags', 0, 1)  # установить бит 0
red.getbit('flags', 0)  # получить бит
red.bitcount('flags')  # количество установленных битов

2. List (Список)

Отсортированная коллекция строк. Может использоваться как очередь или стек.

# Добавление элементов
red.rpush('tasks', 'task1', 'task2', 'task3')  # в конец
red.lpush('tasks', 'task0')  # в начало

# Получение элементов
red.lrange('tasks', 0, -1)  # все элементы [b'task0', b'task1'...]
red.llen('tasks')  # 4
red.lindex('tasks', 0)  # b'task0' (первый элемент)

# Удаление элементов
red.lpop('tasks')  # удалить первый → b'task0'
red.rpop('tasks')  # удалить последний → b'task3'
red.lrem('tasks', 1, 'task1')  # удалить 1 вхождение

# Использование как очередь (FIFO)
def enqueue(queue_name, item):
    red.rpush(queue_name, item)

def dequeue(queue_name):
    return red.lpop(queue_name)

enqueue('job_queue', 'job1')
val = dequeue('job_queue')  # 'job1'

# Использование как стек (LIFO)
def push(stack_name, item):
    red.lpush(stack_name, item)

def pop(stack_name):
    return red.lpop(stack_name)

push('undo_stack', 'action1')
val = pop('undo_stack')  # 'action1'

# Блокирующие операции (для очереди)
def wait_for_job(queue_name, timeout=0):
    # Ждет элемент с timeout (0 = бесконечно)
    return red.blpop(queue_name, timeout)

item = wait_for_job('job_queue', timeout=5)
if item:
    queue_name, value = item
    print(f"Got job: {value}")

3. Set (Множество)

Неупорядоченная коллекция уникальных строк. Поддерживает операции множеств.

# Добавление элементов
red.sadd('users:online', 'alice', 'bob', 'charlie')
red.scard('users:online')  # 3 (размер)
red.smembers('users:online')  # {b'alice', b'bob', b'charlie'}

# Проверка принадлежности
red.sismember('users:online', 'alice')  # True
red.sismember('users:online', 'dave')  # False

# Удаление
red.srem('users:online', 'bob')  # удалить элемент
red.spop('users:online')  # удалить случайный элемент

# Операции множеств
red.sadd('users:premium', 'alice', 'eve')
red.sadd('users:free', 'bob', 'charlie')

# Пересечение
red.sinter('users:online', 'users:premium')  # {b'alice'}

# Объединение
red.sunion('users:premium', 'users:free')  # все пользователи

# Разность
red.sdiff('users:online', 'users:premium')  # {b'bob', b'charlie'}

# Хранение результата
red.sinterstore('result', 'users:online', 'users:premium')

# Использование: отслеживание онлайна
def user_came_online(user_id):
    red.sadd('users:online', user_id)

def user_went_offline(user_id):
    red.srem('users:online', user_id)

def get_online_users():
    return red.smembers('users:online')

4. Hash (Хеш)

Мапа поля-значение. Идеален для хранения объектов.

# Установка полей
red.hset('user:1', mapping={
    'name': 'Alice',
    'email': 'alice@example.com',
    'age': '30'
})

# Получение
red.hget('user:1', 'name')  # b'Alice'
red.hgetall('user:1')  # {b'name': b'Alice', ...}
red.hmget('user:1', 'name', 'email')  # [b'Alice', b'alice@...']  

# Проверка
red.hexists('user:1', 'name')  # True
red.hlen('user:1')  # 3 полей

# Получение ключей и значений
red.hkeys('user:1')  # [b'name', b'email', b'age']
red.hvals('user:1')  # [b'Alice', b'alice@...', b'30']

# Удаление
red.hdel('user:1', 'age')

# Инкремент числового поля
red.hincrbyfloat('user:1', 'rating', 0.5)

# Использование: кэш пользователя
class UserCache:
    def save_user(self, user_id, user_data):
        red.hset(f'user:{user_id}', mapping=user_data)
    
    def get_user(self, user_id):
        user_data = red.hgetall(f'user:{user_id}')
        return {k.decode(): v.decode() for k, v in user_data.items()}
    
    def update_field(self, user_id, field, value):
        red.hset(f'user:{user_id}', field, value)

cache = UserCache()
cache.save_user(1, {'name': 'Alice', 'email': 'alice@example.com'})
user = cache.get_user(1)  # {'name': 'Alice', 'email': 'alice@example.com'}

5. Sorted Set (Отсортированное множество)

Множество с оценкой (score) для каждого элемента. Сортируется по score.

# Добавление с score
red.zadd('leaderboard', {'alice': 100, 'bob': 85, 'charlie': 95})

# Получение
red.zscore('leaderboard', 'alice')  # 100.0
red.zrank('leaderboard', 'alice')  # позиция (0-based)
red.zrevrank('leaderboard', 'alice')  # позиция в обратном порядке

# Диапазоны
red.zrange('leaderboard', 0, -1)  # все, отсортированные
red.zrange('leaderboard', 0, -1, withscores=True)  # с очками
red.zrevrange('leaderboard', 0, -1, withscores=True)  # в обратном порядке

# По score
red.zrangebyscore('leaderboard', 85, 100)  # элементы с score от 85 до 100
red.zcount('leaderboard', 85, 100)  # количество

# Инкремент score
red.zincrby('leaderboard', 5, 'bob')  # bob теперь 90

# Удаление
red.zrem('leaderboard', 'charlie')
red.zremrangebyrank('leaderboard', 0, 0)  # удалить первого

# Использование: лидерборд
def add_score(user_id, score):
    red.zadd('leaderboard', {user_id: score})

def increment_score(user_id, points):
    red.zincrby('leaderboard', points, user_id)

def get_top_10():
    return red.zrevrange('leaderboard', 0, 9, withscores=True)

def get_user_rank(user_id):
    rank = red.zrevrank('leaderboard', user_id)
    return rank + 1 if rank is not None else None

add_score('alice', 100)
add_score('bob', 85)
increment_score('bob', 10)  # bob = 95
print(get_top_10())  # [(b'alice', 100), (b'bob', 95)]
print(get_user_rank('alice'))  # 1

6. Stream (Поток)

Последовательность событий. Как лог с автоматическими ID.

# Добавление события
red.xadd('events', {'user_id': '1', 'action': 'login'})
red.xadd('events', {'user_id': '2', 'action': 'upload'})

# Получение события
red.xlen('events')  # количество
red.xrange('events')  # все события

# Групповое чтение (для обработки очереди)
red.xgroup_create('events', 'event_processors', id='0')
event = red.xreadgroup({'events': '>'}, 'event_processors', count=1)

# Использование: логирование событий
def log_event(event_type, data):
    red.xadd('event_log', {'type': event_type, **data})

def get_recent_events(count=100):
    events = red.xrevrange('event_log', count=count)
    return [(e_id, {k.decode(): v.decode() for k, v in data.items()}) 
            for e_id, data in events]

log_event('user_signup', {'user_id': '1', 'email': 'alice@example.com'})
log_event('order_created', {'order_id': '123', 'amount': '99.99'})

7. HyperLogLog

Структура для подсчета уникальных элементов с минимальной памятью (вероятностный).

# Добавление элементов
red.pfadd('unique_visitors', 'user1', 'user2', 'user3')
red.pfadd('unique_visitors', 'user1', 'user4')  # user1 уже был

# Подсчет (приблизительный)
red.pfcount('unique_visitors')  # ≈ 4

# Объединение HyperLogLogs
red.pfadd('visitors_today', 'alice', 'bob')
red.pfadd('visitors_yesterday', 'bob', 'charlie')
red.pfmerge('all_visitors', 'visitors_today', 'visitors_yesterday')
red.pfcount('all_visitors')  # ≈ 3

# Использование: уникальные пользователи
def track_visitor(page, user_id):
    red.pfadd(f'unique_visitors:{page}', user_id)

def get_unique_count(page):
    return red.pfcount(f'unique_visitors:{page}')

8. Bitmap (через String)

Эффективное хранение флагов в битах.

# Установка и получение битов
red.setbit('user:online', 0, 1)  # пользователь 0 онлайн
red.setbit('user:online', 1, 0)  # пользователь 1 оффлайн
red.getbit('user:online', 0)  # 1

# Подсчет установленных битов
red.bitcount('user:online')  # 1 пользователь онлайн

# Использование: отслеживание дней активности
def mark_user_active(user_id, day):
    red.setbit(f'user:{user_id}:active_days', day, 1)

def get_active_days(user_id, start, end):
    # Подсчет активных дней
    return red.bitcount(f'user:{user_id}:active_days', start, end)

Сравнение и выбор типа

ТипИспользованиеПример
StringПростой кэш, счетчикиuser:1:name, views:article:1
ListОчередь, стек, историяjob_queue, undo_stack
SetТеги, уникальные элементыusers:online, article:tags
HashОбъект, кэш с полямиuser:1, product:123
Sorted SetРейтинг, лидербордleaderboard, trending:posts
StreamСобытия, логиevent_log, notifications
HyperLogLogУникальные подсчетыunique_visitors
BitmapФлаги, битовые операцииuser:online, active_days

Практические паттерны

# Session хранилище
class SessionStore:
    def save_session(self, session_id, data, ttl=3600):
        red.hset(f'session:{session_id}', mapping=data)
        red.expire(f'session:{session_id}', ttl)
    
    def get_session(self, session_id):
        return red.hgetall(f'session:{session_id}')

# Очередь задач
class JobQueue:
    def enqueue(self, job_type, payload):
        red.rpush('job_queue', json.dumps({'type': job_type, 'payload': payload}))
    
    def dequeue(self):
        job = red.lpop('job_queue')
        return json.loads(job) if job else None

# Рейтинг
class RatingService:
    def add_vote(self, item_id, user_id, vote):
        # Добавить голос
        red.zadd('rating', {item_id: vote})
        # Отследить кто голосовал
        red.sadd(f'voters:{item_id}', user_id)
    
    def get_rating(self, item_id):
        return red.zscore('rating', item_id) or 0

Выводы

  • String: для простого кэша и счетчиков
  • List: для очередей и истории
  • Set: для уникальных элементов и членства
  • Hash: для объектов с несколькими полями
  • Sorted Set: для рейтингов и лидербордов
  • Stream: для логирования событий
  • HyperLogLog: для больших наборов уникальных элементов
  • Bitmap: для флагов и битовых операций
Какие типы данных поддерживает Redis? | PrepBro