Привет всем, я Сяо ❤, 985-ненаучный программист, который много лет скитается по миру. Я работал в сфере backend-разработки государственных предприятий, интернет-гигантов и стартап-компаний.
В этот день, когда маленький ❤ покупал билеты на поезд, он обнаружил, что при наличии неоплаченного заказа он уже не сможет приобрести билеты. Если заказы, подлежащие оплате, помещены в очередь, длина очереди может быть только 1.
В последнее время я часто использую Redis, поэтому внезапно задумался о том, как использовать собственную структуру данных Redis для реализации простой версии очереди с отложенным потреблением?
Диаграмма статуса бизнеса выглядит следующим образом:
Кроме того, необходимо обеспечить контролируемую длину очереди. Например, мы разрешаем пользователям иметь только 3 неоплаченных заказа.
Redis, как высокопроизводительная база данных кэша и хранения данных, всегда была мощным помощником для серверных разработчиков.
Если используется Redis В качестве очереди потребления мы можем использовать следующие структуры данных: List, Hash. и Набор. В приведенном выше бизнес-сценарии, поскольку нам нужно сосредоточиться только на orderId
(Заказ ID), поэтому доступны все три структуры данных.
Например, используйте hash
При хранении мы можем хранить key установлен на UnpaidOrder-{userId}
,каждый field Это все приказ.
но,Теперь мы столкнулись с проблемой: время выживания каждого Заказа разное.,Оно разделено на ручное потребление, обычное удаление и логическое.
Поэтому в структуре List, Set или Hash для каждого поля необходимо установить отдельный срок действия.
Это распространенная и сложная проблема. Эта статья начнется с распространенных решений в интернет-бизнесе и глубокого изучения базовой реализации Redis.
В реальном бизнесе мы часто сталкиваемся с такими сценариями: нам нужно посчитать количество определенных полей, и сроки действия этих полей в порядке.
Для приведенного выше сценария нам необходимо посчитать количество неоплаченных заказов пользователей, но срок действия каждого заказа разный.
В этом случае нам необходимо вручную удалить поля с истекшим сроком действия в бизнесе или позволить им автоматически истечь.
Мы знаем, что в настоящее время в Redis нет интерфейса для установки времени истечения срока действия индивидуально для полей List, Set или Hash. Время истечения срока действия можно установить только для всего списка, набора или Hash.
так,когда List/Set/Hash Когда он истечет, все field Срок действия всех элементов истек。
Но это не отвечает потребностям.
Маленькая ❤ попыталась найти в Интернете несколько известных решений, одно из которых Stack Overflow
из проблемного поста, с которым я столкнулся, очень похоже:
Источник рисунка: StackOverflow, как установить срок действия дочернего ключа (поля) HSET в Redis?
Затем я случайно увидел ответ автора Redis в ответе под постом:
Китайский перевод выглядит следующим образом:
Привет, это невозможно: либо используйте другой ключ верхнего уровня для этого конкретного поля, либо сохраните другое поле со сроком действия вместе с отправленным полем, а затем получите оба поля одновременно и сообщите приложению, действительно ли оно все еще (на основе в текущее время).
Срок годности сохраняется, а затем программа определяет, истек ли он.
Это действительно огонь в мешке, очень жгучий!
теперь это Redis Так сказали основатели Redis невозможно быть одному field Чтобы установить время истечения срока действия, первое, что мы рассматриваем, это дать всю List/Set/Hash
Установите срок годности.
Этот подход прост и груб, но с ним сложно удовлетворить необходимость устанавливать срок действия индивидуально для каждого поля.
затем,Я думаю об этом,теперь это Срок годности каждого Заказа разный,Так можем ли мы создавать разные изоляторы в зависимости от времени?,Поместите из Заказ, срок действия которого истекает в то же время, в ту же сборку:
Затем,соответственно разныеизсобиратьнастраивать TTL, когда срок действия заказа истекает без оплаты, заказ будет удален в течение той же минуты, когда истечет срок сбора.
Но проблема в том, что каждый раз при добавлении нового заказа приходится просматривать всю коллекцию за последние 30 минут, проверять, есть ли заказы от пользователя, а затем определять, превысило ли количество неоплаченных заказов пользователя заданное количество. предел.
Более того, может возникнуть проблема при создании коллекции за считанные минуты: срок действия заказа пользователя изначально истекал в 01 секунде, но был удален через 59 секунд.
Если вы создаете коллекции за секунды, 1800 коллекций необходимо создать за 30 минут, что сложнее в управлении, поэтому установка общего срока действия коллекций невозможна.
Есть ли более элегантный способ реализовать это?
Конечно, есть!
Помимо часто используемых структур List/Set/Hash, Redis также имеет структуру данных, специально используемую для сортировки, zset (т. е. Sorted Set, отсортированный набор).
Основываясь на структуре Zset Redis, время истечения срока действия может быть представлено в виде Score, и мы можем легко реализовать отдельный срок действия каждого поля.
Конкретная реализация:
Unix timestamp
плюс срок годности 30min как score
установить этот элемент,так,sorted set
Элементы будут отсортированы и сохранены на основе этой отметки времени истечения срока действия;С одной стороны, с помощью zset Redis можно легко добиться индивидуального срока действия каждого поля, который больше не ограничивается сроком действия всего ключа, что повышает гибкость.
С другой стороны, операция zset в Redis очень эффективна и не оказывает существенного давления на производительность системы.
Это связано с zset Базовая структура данных Zset Базовая реализация использует ZipList (Почтовый список) и SkipList (список пропуска)Два видавыполнить Способ,когдаудовлетворить:
При наличии двух условий Zset использовать Реализация ZipList; в противном случае,использовать Реализация списка пропуска。
ZipList
это массив формы,Время хранения данныхЧасть заголовка списка и часть данных,Заголовок списка имеет 3 элемента:
Часть данных организована в виде пар ключ-значение, и ключ хранит фактическое значение. member
,хранение ценностейизда member переписыватьсяиз Очки(score
)。
SkipList разделен на две части:
Как видно из рисунка, dict и zset Все данные магазина.
Но на самом деле dict и zset Последние используемые указатели указывают на одни и те же данные элемента, то есть данные являются общими для двух частей. Для удобства выражения одни и те же данные отображаются в двух местах.
Когда мы вставляем срок действия в zset Когда, Редис Он автоматически отсортирует его для нас.,Нам нужно только добавить запланированное задание в программу середина,Например: выполнять задачу удаления каждую секунду.,Удалить временную метку из 0 к текущей временной метке score Просто цените。
Псевдокод выглядит следующим образом:
# 1. При создании нового Заказа к оплате запросите количество zsets.
count = zcard UnpaidOrder-{userId}
# 2. Определить количество неоплаченного Заказа
if count >= 3:
return
# 3. Добавлен заказ
zadd UnpaidOrder-{userId} redis.Z{Score: {timestamp1}, Member: {order1}}
# 4.1 Заказ После оплаты от set середина Удалить неоплаченный заказ
zrem UnpaidOrder-{userId} order1
# 4.2 Срок годности истек, от set середина Удалить неоплаченный заказ
zremrange UnpaidOrder-{userId} 0 {current_timestamp}
Благодаря разумному выбору структуры данных и умному применению мы успешно решили проблему списков, наборов и хешей. поля в поездке.
Это решение было проверено на реальных проектах и дало замечательные результаты. Сравните с другими очередями задержки или etcd из field Срок действия плана истек,Redis извыполнить относительно удобнее.,Это также проще понять.
Я надеюсь, что это решение можно использовать в вашем проекте.,Повышение эффективности разработки,Лучше реагировать на реальные потребности. Если у вас есть дополнительные вопросы об использовании Redisuseiz,Также вы можете общаться и обсуждать в комментариях.
Redis становится все более комфортным в этом мире и добивается новых прорывов в технологиях.
Я маленькая ❤, увидимся в следующий раз!