11 способов отменить заказы после таймаута (очень подробно и понятно)
11 способов отменить заказы после таймаута (очень подробно и понятно)

Поскольку в Redis есть функция мониторинга срока действия, некоторые используют ее для закрытия просроченных ордеров, но это решение не идеально. Сегодня поговорим о 11 способах добиться закрытия ордеров по расписанию. Всегда найдется тот, который подойдет именно вам!

В электронной коммерции, платежных и других системах обычно сначала создается заказ (платежное поручение), а затем пользователю дается определенное количество времени на оплату. Если оплата не произведена вовремя, предыдущий заказ (платежное поручение). ) необходимо отменить.

Существует множество подобных сценариев, таких как автоматическое получение товара по истечении срока годности, автоматический возврат денег по истечении времени ожидания, автоматическая отправка текстовых сообщений после оформления заказа и т. д., и все это схожие бизнес-задачи.

Эта статья начинается с таких бизнес-вопросов и обсуждает, какие технические решения доступны, детали реализации этих решений, а также каковы связанные с ними преимущества и недостатки?

Потому что в этой статье есть о чем поговорить,Участие в 11 конкретных планах,Ограничено пространством,В этой статье в основном рассказывается о плане и не будет включаться конкретная реализация кода.  Потому что, пока план ясен, реализация кода не составит труда.

1. Пассивное отключение

При решении такого типа проблем существует относительно простой способ — закрытие заказов с помощью пассивного бизнес-подхода.

Проще говоря, это после создания заказа. Наша система не закрывает ордера активно. Когда пользователь получает доступ к ордеру, мы проверяем, превысило ли время срок действия. Если время прошло, мы закроем ордер и затем сообщим пользователю.

Этот метод является самым простым, и в нем принципиально нет необходимости разрабатывать функцию планового отключения. Однако его недостатки также очевидны, то есть, если пользователь никогда не придет проверить заказ, в нем будет много грязной избыточности данных. базу данных заказал.

Есть еще один недостаток: операцию записи необходимо выполнять во время процесса запроса пользователя. Как правило, операция записи занимает больше времени, чем операция чтения, и существует вероятность сбоя в случае сбоя заказа. система будет обрабатывать его медленнее.

так,Данное решение подходит только для собственного изучения. Не рекомендуется использовать данное решение для реализации функции закрытия заказа на каком-либо коммерческом сайте.

2. Запланированные задачи

Порядок закрытия задач по времени — это простое решение.

Конкретные детали реализации заключаются в том, что мы используем некоторые платформы планирования для реализации запланированных задач выполнения. Задача состоит в том, чтобы сканировать все просроченные ордера, а затем выполнить действие по закрытию ордера.

Преимущество этого решения в том, что оно относительно простое и легко реализуемое. Его можно реализовать на основе Timer, ScheduledThreadPoolExecutor или платформы планирования, такой как xxl-job. Однако есть несколько проблем:

1. Время указано неточно.  Как правило, запланированные задачи выполняются с фиксированной частотой и в соответствии со временем, поэтому может случиться так, что многие заказы достигли периода тайм-аута, но время планирования запланированных задач еще не наступило, что приведет к фактическому времени закрытия этих задач. приказы быть длиннее, чем должны быть. Время позднее.

2. Невозможно обработать большие объемы заказов.  Метод запланированных задач заключается в том, чтобы сконцентрировать разрозненное время простоя в периоде планирования задач. Если объем заказов относительно велик, это может привести к тому, что время выполнения задачи будет очень долгим. Чем дольше занимает вся задача, тем больше заказов будет. время может быть очень позднее, что приведет к еще более позднему закрытию.

3. Оказать давление на базу данных.  Запланированные задачи сосредоточены на сканировании таблиц, что приведет к тому, что большой объем операций ввода-вывода базы данных будет занят и использован за короткий период времени. Если изоляция не будет выполнена должным образом, а объем бизнеса относительно велик, это может повлиять на обычный онлайн-бизнес.

4. Проблема подбазы данных и подтаблицы.  В системе заказов, если объем заказа велик, она может учитывать подбазы данных и таблицы и выполнять полное сканирование таблиц в подбазах данных и таблицах. Это настоятельно рекомендуемое решение.

так,запланированные план задачи,Он подходит для сценариев, где точность времени не требуется, а объем бизнеса не очень велик. Если требования к точности времени относительно высоки,И если объем бизнеса большой,,Этот сценарий не применяется.

3. Собственная очередь задержки JDK

Есть такое решение, которое можно реализовать непосредственно на базе самого приложения, не прибегая к каким-либо внешним ресурсам, и оно основано на DelayQueue, идущем в комплекте с JDK.

DelayQueue — это неограниченная BlockingQueue, используемая для размещения объектов, реализующих интерфейс Delayed. Объекты в ней могут быть удалены из очереди только по истечении срока их действия.

На основе очереди задержки можно реализовать отложенное закрытие ордеров. Сначала, когда пользователь создает заказ, он добавляется в DelayQueue. Затем требуется резидентная задача для непрерывного удаления ордеров, достигших таймаута. время из очереди. Затем закройте для них заказ, а затем удалите их из очереди.

Это решение требует, чтобы поток постоянно удалял из очереди заказы, которые необходимо закрыть. Как правило, в этот поток необходимо добавить цикл while (true), чтобы гарантировать непрерывное выполнение задачи и возможность своевременного удаления порядка тайм-аута.

Решение с использованием DelayQueue для реализации закрытия таймаута просто в реализации. Нет необходимости полагаться на сторонние платформы и библиотеки классов, которые поддерживают его изначально.

Конечно, это решение не лишено недостатков. Прежде всего, если оно основано на DelayQueue, необходимо размещать заказы. Если объем заказа слишком велик, это может вызвать проблемы с OOM, кроме того, DelayQueue основан на; Память JVM. После перезапуска машины все данные внутри исчезают. Хотя мы можем использовать его с сохранением базы данных. Более того, многие приложения сейчас развертываются в кластерах, поэтому взаимодействие нескольких DelayQueue на нескольких экземплярах кластера является большой проблемой.

так,Решение DelayQueue на основе JDK подходит только для использования в автономных сценариях и сценариях с небольшим объемом данных. Если задействованы распределенные сценарии, это не рекомендуется.

4. Колесо времени Нетти

Существует еще один способ, похожий на DelayQueue, поставляемый с упомянутым выше JDK, и основанный на реализации временного колеса.

Зачем существует колесо времени? Главным образом потому, что средняя временная сложность операций вставки и удаления DelayQueue равна O(nlog(n)). Хотя это уже довольно хорошо, схема временного колеса может снизить временную сложность операций вставки и удаления до O(1).

Колесо времени можно понимать как кольцевую структуру, разделенную на несколько слотов, как часы. Каждый слот представляет собой период времени, и в каждом слоте может храниться несколько задач. Структура связанного списка используется для хранения всех задач, срок действия которых истекает в этот период времени. Колесо времени вращается слот за слотом по часовой стрелке и выполняет все поставленные задачи в слоте.

HashedWheelTimer на основе Netty может помочь нам быстро реализовать колесо времени. Этот метод похож на DelayQueue. Недостатки связаны с памятью, проблемами расширения кластера, ограничениями памяти и т. д.

Но по сравнению с DelayQueue он более эффективен и имеет меньшую задержку при запуске задач. Реализация кода также стала более оптимизированной.

так,Решение на основе Колесо времени Нетти более эффективно, чем DelayQueue на основе JDK.,Легче реализовать,Но то же самое,Он подходит только для использования в автономных сценариях и сценариях, где объем данных невелик.,Если речь идет о распределенных сценариях,Это по-прежнему не рекомендуется.

5. Колесо времени Кафки

Поскольку существуют некоторые проблемы с колесом времени на основе Netty, существуют ли другие реализации колеса времени?

Он действительно существует, и это колесо времени Kafka. Внутри Kafka есть множество отложенных операций, таких как отложенное производство, отложенное извлечение, отложенное удаление данных и т. д. Эти отложенные функции обрабатываются внутренним менеджером отложенных операций для выполнения специализированной обработки. , нижний слой реализован с помощью колеса времени.

#Кроме того, для решения некоторых отложенных задач с большими промежутками времени Kafka также вводит иерархическое колесо времени, которое может лучше контролировать степень детализации времени и справляться с более сложными сценариями обработки временных задач;

Реализация колеса синхронизации в Kafka — это класс TimingWheel, расположенный в пакете kafka.utils.timer. Временное колесо, основанное на Kafka, также может достигать временной сложности O(1), при этом производительность по-прежнему остается хорошей.

Реализация колеса времени на основе Кафки.,существуют Реализация немного сложна,Нужно полагаться на Кафку,Но его стабильность и производительность выше.,И это подходит для распределенных сценариевсередина。

6. Задержанные сообщения RocketMQ

По сравнению с Kafka, RocketMQ имеет мощную функцию, заключающуюся в поддержке отложенных сообщений.

Отложенные сообщения. Когда сообщение записывается брокеру, оно не будет немедленно использовано потребителем. Сообщения, которым необходимо подождать определенный период времени, прежде чем быть обработанными, называются отложенными сообщениями.

С отложенными сообщениями мы можем отправить отложенное сообщение после создания заказа. Например, если заказ отменен через 20 минут, то будет отправлено отложенное сообщение с задержкой 20 минут. Затем через 20 минут сообщение будет отправлено. быть использован потребителем. После получения сообщения потребитель может просто закрыть заказ.

Однако задержанное сообщение RocketMQ не поддерживает задержки любой длины. Оно поддерживает только: 1 с 5 с 10 с 30 с 1 м 2 м 3 м 4 м 5 м 6 м 7 м 8 м 9 м 10 м 20 м 30 м 1 час 2 часа. (Коммерческая версия поддерживает любой период времени)

Видно, что с отложенными сообщениями RocketMQ наша обработка намного проще. Нам нужно только отправлять и получать сообщения. Системы полностью разделены. Однако, поскольку длина задержанных сообщений ограничена, он не очень гибок.

Если время закрытия заказа в нашем бизнесе совпадает со временем, поддерживаемым отложенными сообщениями RocketMQ, то это можно реализовать на основе отложенных сообщений RocketMQ. В противном случае этот подход не является оптимальным.

7. Очередь недоставленных писем RabbitMQ

Отложенные сообщения поддерживаются не только в RocketMQ, но также могут быть реализованы в RabbitMQ, но нижний уровень основан на очереди недоставленных писем.

Когда обычное сообщение в RabbitMQ не может быть использовано по таким причинам, как прохождение времени выживания (истечение срока жизни TTL), превышение длины очереди, отклонение потребителем и т. д., оно становится мертвым сообщением, то есть мертвым сообщением. письмо.

Когда сообщение становится недоставленным, его можно повторно отправить в очередь недоставленных писем (фактически в обмен).

Затем на основе такого механизма можно реализовать отложенные сообщения. То есть мы устанавливаем TTL для сообщения, но не потребляем сообщение. По истечении срока его действия оно попадает в очередь недоставленных писем, и тогда мы можем отслеживать потребление сообщений в очереди недоставленных писем.

Более того, TTL в RabbitMQ может быть установлен на любой промежуток времени, что решает проблему негибкости RocketMQ.

Однако в реализации очереди недоставленных писем существует проблема, заключающаяся в том, что это может привести к блокировке начала очереди, поскольку очередь поступает первым, первым уходит, и только сообщение в начале очереди каждый раз оценивается, истекло ли время. Затем, если время сообщения главы очереди очень велико, если оно длинное и никогда не истекает, в это время будет заблокирована вся очередь, даже если сообщение за ним. истекает, он всегда будет заблокирован.

Очередь недоставленных писем, основанная на RabbitMQ, может задерживать сообщения и очень гибко реализовывать закрытие заказов по времени. Благодаря масштабируемости кластера RabbitMQ она может достигать высокой доступности и обрабатывать большой параллелизм. Первый недостаток заключается в том, что могут возникнуть проблемы с блокировкой сообщений, и решение относительно сложное. Оно не только опирается на RabbitMQ, но также требует объявления множества очередей (обменов), что увеличивает сложность системы.

8. Плагин RabbitMQ

Фактически, на основе RabbitMQ отложенные сообщения могут быть реализованы без очереди недоставленных писем. Это основано на подключаемом модуле Rabbitmq_delayed_message_exchange. Это решение может решить проблему блокировки сообщений, которая возникает, когда задержанные сообщения реализуются через очередь недоставленных писем. Однако этот плагин поддерживается, начиная с RabbitMQ 3.6.12, поэтому существуют требования к версии.

Этот плагин является официальным и его можно смело использовать. После установки и включения этого плагина вы можете создать очередь типа x-delayed-message.

Метод, основанный на очереди личных сообщений, о котором мы упоминали ранее, заключается в том, что сообщение сначала будет доставлено в обычную очередь, а затем попадет в очередь недоставленных писем после истечения срока жизни. Однако, согласно методу плагина, сообщения не будут сразу попадать в очередь. Вместо этого они будут сохранены в базе данных Mnesia, разработанной на основе Erlang, а затем будет использоваться таймер для запроса сообщений, которые необходимо доставить. , а затем они будут доставлены в очередь x-delayed-message.

Метод, основанный на плагине RabbitMQ, может задерживать сообщения без проблем с блокировкой сообщений, но поскольку он основан на плагине, максимальное время расширения, поддерживаемое этим плагином, составляет (2^32)-1 миллисекунды. что составляет около 49 дней, превышение этого времени будет израсходовано немедленно. Но он реализован на основе RabbitMQ, поэтому очень хорош с точки зрения удобства использования и удобства работы.

9. Мониторинг срока действия Redis

Многие люди, которые использовали Redis, знают, что Redis имеет функцию мониторинга срока действия.

В redis.conf добавьте конфигурацию notify-keyspace-events Ex, чтобы включить мониторинг истечения срока действия, а затем реализуйте в коде KeyExpirationEventMessageListener для отслеживания сообщений об истечении срока действия ключа.

Таким образом, заказ можно закрыть при получении сообщения с истекшим сроком действия.

Это решение не рекомендуется всем, поскольку на официальном сайте Redis четко указано, что Redis не гарантирует, что ключ будет удален немедленно по истечении срока его действия, а также не гарантирует, что сообщение может быть отправлено немедленно. Таким образом, задержка сообщения неизбежна. По мере увеличения объема данных задержка становится более продолжительной. Задержки в несколько минут являются обычным явлением.

Более того, в Редисе До версии 5.0,Это сообщение отправляется через режим PUB/SUB. Оно не сохраняется. Неважно, получите ли вы его или успешно ли будет использовано. Другими словами, если ваш клиент зависнет при отправке сообщения, а затем восстановится, вы полностью потеряете сообщение. (В Редисе После версии 5.0, благодаря появлению Stream, его можно использовать как очередь отложенных сообщений. )

10. Zset Redis

Хотя решение, основанное на мониторинге срока действия Redis, не является идеальным, это не означает, что функция закрытия ордеров Redis не идеальна. Существуют и другие решения.

Добиться этой функции мы можем с помощью упорядоченного набора в Redis — zset.

Zset — это упорядоченный набор, и каждому элементу (члену) присвоен балл. Значения в наборе можно получить путем сортировки по баллам.

Мы устанавливаем временную метку тайм-аута заказа (время заказа + продолжительность тайм-аута) и номер заказа как score и член. Таким образом, Redis отсортирует zset в соответствии с временем задержки оценки. Затем запускаем задачу сканирования redis и получаем «текущее время» > «Оценить» отложенную задачу: после сканирования выньте номер заказа, а затем запросите заказ, чтобы закрыть заказ.

Преимущество использования redis zset для реализации функции закрытия ордеров заключается в том, что он может полагаться на механизм постоянства и высокой доступности redis. Избегайте потери данных. Однако у этого решения есть и недостатки: в сценариях с высоким уровнем параллелизма несколько потребителей могут одновременно получить один и тот же номер заказа. Обычно это решается добавлением распределенных блокировок, но это также снижает пропускную способность.

Однако в большинстве бизнес-сценариев, если идемпотентность реализована правильно, несколько потребителей могут получить один и тот же номер заказа.

11. Редиссон

Приведенное выше решение выглядит хорошо, но нам нужно написать собственный код на основе структуры данных zset. Есть ли более удобный способ?

Да, он основан на Redisson.

Redisson — это фреймворк, реализованный на основе Redis. Он не только предоставляет ряд распределенных общих объектов Java, но также предоставляет множество распределенных сервисов.

Redission определяет распределенную очередь задержки RDelayedQueue, которая представляет собой очередь задержки, реализованную на основе структуры zset, которую мы представили ранее. Она позволяет помещать элементы в целевую очередь с указанной длиной задержки.

Фактически, очередь задержки на основе памяти добавляется на основе zset. Когда мы хотим добавить часть данных в очередь задержки, redission поместит данные + время ожидания в zset и запустит задачу задержки. Когда срок действия задачи истечет, он извлечет данные из zset и вернет их клиенту. конечное использование.

Общая идея такова. Любой, кому интересно, может взглянуть на конкретную реализацию RDelayedQueue.

Реализация на основе Redisson может решить проблему параллельного дублирования в решении на основе zset, а метод реализации является относительно простым, с относительно высокой стабильностью и производительностью.

Подвести итог

Мы внедрили 11 решений для достижения планового закрытия заказов.,Каждый из различных вариантов имеет преимущества и недостатки,Каждый подходит для разных сценариевсередина。Тогда давай попробуем Подвести Итог:

По сложности реализации(Содержит зависимости и развертывание используемых платформ.):

Redission > Плагин RabbitMQ > Очередь недоставленных писем RabbitMQ > Задержанные сообщения RocketMQ ≈ Redis zset > Мониторинг срока действия Redis ≈ колесо времени Кафки > запланированные задачи > Колесо времени Нетти > DelayQueue, поставляемый с JDK > Пассивное отключение

Полнота программы:

Redission ≈ Плагин RabbitMQ > колесо времени Кафки > Redis zset ≈ Задержанные сообщения RocketMQ ≈ Очередь недоставленных писем RabbitMQ > Мониторинг срока действия Redis > запланированные задачи > Колесо времени Нетти > DelayQueue, поставляемый с JDK > Пассивное отключение

Для разных сценариев подходят разные решения:

  • Сыграй сам: Пассивное отключение
  • Одно приложение,Объем бизнеса небольшой: Колесо времени Нетти、DelayQueue, поставляемый с JDK、запланированные задачи
  • Распределенное приложение,Объем бизнеса не большой:Мониторинг срока действия Redis、Очередь недоставленных писем RabbitMQ、Redis zset、запланированные задачи
  • Распределенное приложение,Большой объем бизнеса、Высокий параллелизм: Redisson、Плагин RabbitMQ、колесо времени Кафки、Задержанные сообщения RocketMQ

Общее рассмотрение,с учетом стоимости,Полнота и сложность решения,Что касается популярности используемых сторонних фреймворков,,Личное сравнение рекомендует отдать приоритет Redission+Redis, Плагин RabbitMQ、Redis zset、Задержанные сообщения RocketMQ и другие решения.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose