Как реализовать очередь сообщений через Redis?

29

Почему Redis для очередей?

У меня сложилось впечатление, что Redis может стать хорошим кандидатом для внедрения системы массового обслуживания. До этого момента мы использовали нашу базу данных MySQL с опросом или RabbitMQ. С RabbitMQ у нас было много проблем - клиентские библиотеки очень плохие и глючные, и мы хотели бы не тратить слишком много времени на их исправление, несколько проблем с консолью управления сервером и т. Д. И на время По крайней мере, мы не стремимся к миллисекундам или серьезному увеличению производительности, поэтому, пока система имеет архитектуру, которая интеллектуально поддерживает очередь, мы, вероятно, в хорошей форме.

Хорошо, так что это фон. По сути, у меня есть очень классическая, простая модель очереди - несколько производителей, производящих работу, и несколько потребителей, потребляющих работу, и как производители, так и потребители должны иметь возможность разумного масштабирования. Оказывается, наивный PUBSUBне работает, так как я не хочу, чтобы все подписчики потребляли работу, я просто хочу, чтобы один подписчик получил работу. На первый взгляд, это выглядит как BRPOPLPUSHинтеллектуальный дизайн.

Можем ли мы использовать BRPOPLPUSH?

Базовый дизайн BRPOPLPUSH- у вас есть одна рабочая очередь и очередь выполнения. Когда потребитель получает работу, он атомарно помещает элемент в очередь выполнения, а когда он завершает работу, то это LREMон. Это предотвращает черную работу, если клиенты умирают, и делает мониторинг довольно легким - например, мы можем сказать, есть ли проблема, заставляющая потребителей занимать много времени для выполнения задач, в дополнение к сообщению, если существует большой объем задач.

Это обеспечивает

  • работа доставляется ровно одному потребителю
  • работа попадает в очередь выполнения, поэтому она не может быть черной дырой, если потребитель

Недостатки

  • Мне кажется довольно странным, что лучший дизайн, который я нашел, на самом деле не использует, PUBSUBтак как именно на этом и сосредоточено большинство постов в блогах об организации очереди над Redis. Поэтому я чувствую, что упускаю что-то очевидное. Единственный способ, который я использую, PUBSUBне выполняя задачи дважды, - это просто отправить уведомление о том, что работа пришла, что потребители могут затем неблокировать RPOPLPUSH.
  • Невозможно запросить более одного рабочего элемента за раз, что является проблемой производительности. Не очень большой для нашей ситуации, но довольно очевидно, что эта операция не была рассчитана на высокую пропускную способность или эта ситуация
  • Короче говоря: я что-то глупо пропускаю?

Также добавляем тег node.js, потому что это язык, с которым я в основном имею дело. Узел может предложить некоторые упрощения в реализации, учитывая его однопоточный и неблокирующий характер, но, кроме того, я использую библиотеку node-redis, и решения должны или могут быть чувствительны к ее сильным и слабым сторонам.

djechlin
источник

Ответы:

5

Если вы хотите использовать Redis для очереди сообщений в Node.js и не возражаете против использования модуля для этого, вы можете попробовать RSMQ - Redis Simple Message Queue для Node. В то время, когда этот вопрос задавался, он был недоступен, но сегодня это приемлемый вариант.

Если вы действительно хотите реализовать очередь самостоятельно, как вы указали в своем вопросе, вы можете прочитать исходный код RSMQ, потому что это всего лишь 20 экранов кода, которые выполняют именно то, что вы просите.

Видеть:

RSP
источник
Я приму это, если позже не узнаю, что это действительно испорчено или сломано или что-то в этом роде.
Джечлин
22

До сих пор я сталкивался с некоторыми трудностями, я хотел бы документировать здесь.

Как вы справляетесь с логикой переподключения?

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

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

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

Сейчас я предпочитаю решение Redis PUBSUB + RPOPLPUSH. Это отделяет уведомление о работе от потребления работы, что позволяет нам выделить чистое решение для прослушивания. PUBSUB несет ответственность только за уведомление о работе. Атомная природа RPOPLPUSH отвечает за потребление и делегирование работы только одному потребителю. Сначала это решение казалось излишне сложным по сравнению с блокировкой, но теперь я вижу, что осложнение вовсе не было ненужным; это было решение сложной проблемы.

Однако это решение не совсем тривиально:

  • потребители также должны проверить работу по переподключению.
  • в любом случае потребители могут захотеть провести опрос на предмет новой работы, на предмет избыточности. Если опрос действительно прошел, должно быть выдано предупреждение, поскольку это должно происходить только между потреблением на PUBSUB и опросом на RPOPLPUSH. Поэтому многие успехи в опросах указывают на сломанную систему подписки.

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

djechlin
источник
Не уверен, что я понимаю проблему с блокировкой потребителей. Мне кажется, что если нет работы по обработке, потребители должны блокировать ее до тех пор, пока она не появится, хотя я полагаю, что потребитель также занимается другими вещами, которые могут быть другой историей, но не является ли это большей проблемой в приложении и не так много для очереди? IE не будет блокировать поток в более крупном приложении, что будет более элегантным решением, когда поток сможет уведомить приложение, когда оно получит задание из очереди. Возможно, это просто использование узла, который создает осложнения.
AaronM
9
Мне любопытно, как далеко вы продвинулись с августа прошлого года. Удалось ли вам решить ваши проблемы, чтобы вы остались довольны? Как ты их решил?
AaronM
3
AAA: так же, как @AaronM, я хотел бы услышать, как ты продвинулся.
Bjornl
Согласовано. Как это прогрессировало? Мне нравится идея удалить RabbitMQ из стека и использовать Redis, который есть в любом случае. Моя проблема заключается в том, как зарегистрировать потребителя с помощью RSMQ (узел lib).
ra9r
@raiglstorfer не работал там в течение двух лет: P не стесняйтесь исследовать и публиковать ...
djechlin
0

Поэтому основной причиной выбора использования RabbitMQ вместо Redis являются сценарии сбоев и кластеризация.

Эта статья действительно объясняет это лучше всего, поэтому я просто предоставлю ссылку:

https://aphyr.com/posts/283-jepsen-redis

Redis Sentinel и совсем недавно Redis кластеризация не в состоянии обработать ряд очень простых сценариев сбоя, которые сделали его плохим выбором для очереди.

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

Вот пост для кролика:

https://aphyr.com/posts/315-jepsen-rabbitmq

Когда вы смотрите на теорию CAP (согласованность, доступность и обработка разделов), вы можете выбрать только 2 из 3. Мы используем RMQ для CP (согласованность и обработка разделов) с нашей загрузкой сообщений, если мы недоступны, это не так. конец света. Чтобы не потерять сообщения, мы используем ignore для обработки разделов, чтобы не потерять сообщения. Дубликаты могут быть обработаны, так как источник управляет UUID.

ra9r
источник