Очереди / Брокеры сообщений
Термины
- Гарантия доставки - дошло ли сообщение до получателя
- Надежность - сохранность данных/конфига после падения- Обычно подразумевается сохранение на диск и репликация
 
- Сообщение - байты (строка/json/что угодно) + метадата (заголовки/приоритет)
Модели Брокеров
- Push-модель - сообщения отправляются получателю
- Pull-модель - получатель сам ходит за сообщениями
Гарантии доставки
- At-most-once delivery - 0-1- Отравили и забыли - нет гарантии успешной обработки
- Быстрее, больше пропускная способность
 
- At-least-once delivery - 1+- Отправили сообщение, но подтверждение не получили, значит отправляем еще раз
- Важно обрабатывать такой кейс, напр. с помощью идемпотентности
 
- Exactly-once delivery - 1- Аналог транзакций
 
Rabbit MQ
Архитектура
- Паблишер > Exchange > Очередь > Консумер- Паблишер - отравляет/создает сообщения
- Exchange - роутер сообщений от паблишеров в очереди
- Очередь - хранит сообщения + отправляет Консумерам
- Консумер - обрабатывает сообщение
 
- Очередность - FIFO - для 1 паблишера - 1 консумера
Exchange
- Сущности роутинга- Routing Key - ключик (просто строка), на основе которой роутим
- Binding - связь между Exchange и Exchange/Queue
 
- Виды Exchange роутинга- Fanout - во все Очереди и Exchangeи по биндингу- Механизм Pub/Sub
- Routing Key игнорируется
 
- Direct - полное совпадение Routing Key
- Topic - direct + wildcard
- Header - по заголовкам
- Consistent Hashing - хеширует ключ и отправляет только в одну очередь
 
- Fanout - во все Очереди и Exchangeи по биндингу
- Dead letter exchange - Exchange с недоставленными сообщениями- Если сообщение не доставлено / очередь переполнена, то можно вернуть сообщение из очереди обратно в спец эксченж
 
Доставка / гарантии / надежность
- At-least-once, At-most-once
- Паблишер отправляет сообщение > rabbit что-то поделал с сообщением > отправляет паблишеру команду ack
- Если паблишер не получил ack(кейс 500), сообщение отправляется еще раз, предварительно возвращая сообщение в очередь
- Очередь >-сообщение-> Консумер ⇒- Консумер >-ack-> Очередь ⇒- Сообщение удаляется из очереди
- Иначе повторная доставка / доставка другому консумеру
 
 
- Консумер >-ack-> Очередь ⇒
- Можно из паблишера сразу в очередь - дефолтный эксченж
- Надежность: Можно включить флаг durable, тогда конфиг будет сохраняться
Масштабирование
- 1 очередь - несколько консумеров ⇒- 1 сообщение - 1 консумеру
- несколько сообщений равномерно распределяется по всем консумерам
 
- При добавлении новых консумеров никаких пауз нет
- Можно ждать ack, тогда будет медленее, можно не ждать, тогда будет быстро- QoS - лимит на кол-во неподтвержденных сообщений
 
Kafka
Архитектура
- Распределенный реплицируемый лог- Распределенный - на разных машинах - партиции
- Реплицируемый - копирует сообщения - реплики
- Лог - упорядоченный журнал событий = файл со строками
 
- 
Продусер > Топик / Партиция <-Оффсет-< Consumer (Group) 
- 
Продусер всегда пишет в конец партишена 
Топик / Партиция
- Топик - набор событий одного или нескольких типов- Важно не делать много топиков
 
- Топик - набор партиций- Важно писать равномерно по всем партициям
 
- Партиционирование - выбор партиции- key > hash > %len(partitions) > partition
- Это происходит на стороне producer ⇒ можно свой алго написать
 
- Важно определить сколько партиций надо
Consumer / Offset
- Consumer Group = логический Consumer
- Консумер читает партицию с последнего места чтения
- Можно читать, то что уже прочитано - тайм-тревел
- Оффсет может храниться у консумера и у Кафки (если консумер не хранит оффсет)
- key - аналог routing-key в rabbit
- 1 партиция = 1 логический консумер- Т.е можно 2 партиции - 1 консумер, нельзя - 1 партиция - 2 консумера
- Важно что логический - если консумеры будут разными приложениями, то чтение из одной парции это ок
- Group Coordinator - kafka-брокер, который следит за группой
- Group Leader - консумер, который распределяет консумеров по партициям- Можно управлять алго
 
 
- commit offset - команда фиксации нового оффсета- Консумер > Kafka > _consumer_offsetsTopic
- Нужно для уведомления kafka
- Иначе, если консумер сдох, то kafka будет отдавать сообщения с послндего сохраненного оффсета
 
- Консумер > Kafka > 
Масштабирование / Перебалансировка
- При добавлении нового консумера чтение сообщений приостанавливается до конца обработки текущих сообщений, а затем партиции распределяются заново
Репликация
- Тупа копирование партиций на несколько нод
- Параметр - factor - желательно 3+
Доставка и Гарантии
- Последовательность: Если сообщение B пришло после А, значит Offset B > Offset A
- Сообщение закоммичено, когда доставлено во все реплики = sync replica- Можно отключить
 
- Сообщения не будут потеряны если жива хотя бы одна реплика
- Параметр acks- acks = 0 - “выстрелил и забыл”
- acks = 1 - хотя бы одна реплика (лидер) сохранила на диск
- acks = all - все реплики получили сообщение
 
Pull-модель
- консумеры сами запрашивают сообщения у Kafka
- Kafka отдает сообщения батчами (пачками)
- latency хуже, потому что Kafka ждет мб еще сообщения придут
- Добавление новых партиций ломает очередность
Хранение
- Если хранить вечно не надо (место на диске не резиновое), то можно настроить время жизни / макс. размер
Обработка ошибок
- Ждем- Но это плохо
 
- Таймауты / Ретраи / Алертинг
- Заглушка- Сохранение частичной инфы в бд, обработаем потом, в другом событии
 
- Переместиться во времени
- Переложить сообщение
- Идемпотентность
Что выбирать?
Kafka
- Высокая пропускная способность, но хуже latency
- Хранение сообщений + возможность перечитать сообщения
- Репликация, но и сложнее настройка
Rabbit
- Лучше latency
- Роутинг
Redis
- Скорость, простота
- Нет гарантий доставки
- Нет роутинга