Рецепты RabbitMQ

Preview:

Citation preview

Готовим кролика

10 рецептов

Календарев А.М.

Пару слов об pipeline архитектуреhttps://habrahabr.ru/company/oleg-bunin/blog/310418/

Pipe-line архитектура

Pipe-line архитектура

ApplicationApplication Application

Пример: аналог Yandex.market

Пример: аналог Yandex.market

ЗагрузкаYML

Сведениев pricelist

ПарсингYML

Загрузкаimg

Задачи за кадром

Пример: аналог Yandex.market

ЗагрузкаYML

Сведениев pricelist

ПарсингYML

Загрузкаimg

Задачи за кадром

Паттерны сообщений

Cообщения

● Позволяют асинхронно взаимодействоавть между элементами архитектуры

● Сохраняют слабую связанность между элементами архитектуры

● Позволяют взаимодействоавть с разными

частями, PHP – Phython – Java - Go ...

Паттерны сообщений

Pipeline & Filter

Не совсем pipeline

ЗагрузкаYML

ПарсингYML

Загрузкакартинок

Publish-Subscriber Channel

Routers

AdvancedMessageQueueProtocol

Exchange

● Принимает сообщения

● Имеет имя

● Имеет тип:- fanout- direct- topic - headers

AMQP : Exchange (обмен)

Exchange

AMQP : Exchange (обмен)● Принимает сообщения

● Имеет имя

● Имеет тип

Имеет свойства:- autodelete- transit- durable

Exchange

AMQP : Exchange (обмен)

$exchange = new AMQPExchange($channel);$exchange->setName('MyExchange';)$exchange->declare();

AMQP : Queue (очередь)

Queue

● Отдает сообщения адресату по принципу FIFO

● Имеет имя● Имеет свойства:

- autodelete- durable- exclusive

AMQP : Queue (очередь)

Queue

$queue = new AMQPQueue($channel);$queue->setName('MyQueue');$queue->declare();

AMQP : Bind (связь)

● Между Exchange и Queue определяем связь (или маршрут): Bind

● Имеет ключ RoutingKey, в соответствии с которым определяется маршрут сообщения

QueueExchangeBind

AMQP : Bind (связь)

QueueExchangeBind

$queue = new AMQPQueue($channel);$queue->setName('MyQueue');$queue->bind('MyExchange', $key);

AMQP : Bind (связь)

QueueExchangeBind

$exchange = new AMQPExchange($channel);$exchange->setName('MyExchange');$exchange->bind('MyQueue', $key);

AMQP : Bind (связь)

QueueExchangeBind

$exchange = new AMQPExchange($channel);$exchange->setName('MyExchange');$exchange->bind('MyQueue', $key);

Объявляется один раз

AMQP : Internals

AMQP : Message

Exchange

Состоит:

● тела

● routing key

● заголовков

● имеет аттрибуты

AMQP : Message

● Expiration period

● Message publishing timeshamp

Exchange

Аттрибуты:

● Content-type

● Content-encoding

● Delivery-mode

● Message priority

● Application id

AMQP : Message

Exchange

AMQP : Message

В зависимости от типа Exchange и routingKey сообщения определяется маршрут сообщения

Queue 1

Queue 2

Exchange

AMQP : Message

Fanout – ключ не учитываем

Direct – полное совпадение

Topic – совпадение по маске

Queue 1

Queue 2

Exchange

AMQP : Message

Fanout – самый быстрый

Direct – середина на половине

Topic – сомый медленный

Queue 1

Queue 2

Exchange

Отправить сообщение

$exchange = new AMQPExchange($channel);$exchange->setName('MyExchange';)$exchange->publish($message, $key);

AMQP : ACK

QueueExchangeBind

На каждое принятое сообщение должна быть отослана “квитанция” ACK (Acknowledgements).

AMQP : ACK

QueueExchangeBind

На каждое принятое сообщение должна быть отослана “квитанция” ACK (Acknowledgements).

Если Очередь имеет св-во AUTOACK то подтверждение специально отправлять не нужно

ACK

Guaranteed Delivery

AMQP : ACK

workerWEB

Заказ

AMQP : ACK

workerWEB

Заказ

ACK

Удачное соединение

AMQP : ACK

workerWEB

Заказ

Удачное соединениеНе удачнонесоединение

Делаем повторный запрос

Объявление очереди и обмена

// создание очереди, обмена и их привязки друг к другу. $rabbit = new AMQPConnection();$res = $rabbit->connect();

$channel = new AMQPChannel($rabbit);$exchange = new AMQPExchange($channel);$exchange->setFlags(AMQP_DURABLE);$exchange->setName('to_worker');$exchange->setType('direct');$exchange->declare();

$queue = new AMQPQueue($channel);$queue->setFlags(AMQP_DURABLE);$queue->setName('worker');

Объявление очереди и обмена

// создание очереди, обмена и их привязки друг к другу. $rabbit = new AMQPConnection();$res = $rabbit->connect();

$channel = new AMQPChannel($rabbit);$exchange = new AMQPExchange($channel);$exchange->setFlags(AMQP_DURABLE);$exchange->setName('to_worker');$exchange->setType('direct');$exchange->declare();

$queue = new AMQPQueue($channel);$queue->setFlags(AMQP_DURABLE);$queue->setName('worker');

AMQP_DURABLEAMQP_AUTODELETEAMQP_EXCLUSIVEAMQP_INTERNALAMQP_IMMEDIATEAMQP_AUTOACK

Объявление очереди и обмена

// создание очереди, обмена и их привязки друг к другу. $rabbit = new AMQPConnection();$res = $rabbit->connect();

$channel = new AMQPChannel($rabbit);$exchange = new AMQPExchange($channel);$exchange->setFlags(AMQP_DURABLE);$exchange->setName('to_worker');$exchange->setType('direct');$exchange->declare();

$queue = new AMQPQueue($channel);$queue->setFlags(AMQP_DURABLE);$queue->setName('worker');

AMQP_DURABLEAMQP_AUTODELETEAMQP_EXCLUSIVEAMQP_INTERNALAMQP_IMMEDIATEAMQP_AUTOACK

Это можно сделатьодин раз

Привзка очереди к обмену

$rabbit = new AMQPConnection();$res = $rabbit->connect();$channel = new AMQPChannel($rabbit);$queue = new AMQPQueue($channel);$queue->setName('worker');// $queue->declare();

$queue->bind('to_worker', 'logs');$rabbit->disconnect();

Привзка очереди к обмену

$rabbit = new AMQPConnection();$res = $rabbit->connect();$channel = new AMQPChannel($rabbit);$queue = new AMQPQueue($channel);$queue->setName('worker');// $queue->declare();

$queue->bind('to_worker', 'logs');$rabbit->disconnect();

Routing key

Привзка очереди к обмену

Это можно сделатьодин раз

Привзка очереди к обмену

$rabbit = new AMQPConnection();$res = $rabbit->connect();$channel = new AMQPChannel($rabbit);$queue = new AMQPQueue($channel);$queue->setName('worker');// $queue->declare();

$queue->bind('to_worker', 'logs');$rabbit->disconnect();

Это можно вообще не делать

а использоватьHTTP интерфейс

Публикация сообщения

$rabbit = new AMQPConnection();$res = $rabbit->connect();

$channel = new AMQPChannel($rabbit);$exchange = new AMQPExchange($channel);$exchange->setName('to_worker');$i=0;

while ($i < 20) { $i++; $data = json_encode([1,2,3, rand(0, 1000)]); $exchange->publish($data, 'logs', 0, ['delivery_mode'=>2, 'content_type'=> 'text/json'] );}

Публикация сообщения

$rabbit = new AMQPConnection();$res = $rabbit->connect();

$channel = new AMQPChannel($rabbit);$exchange = new AMQPExchange($channel);$exchange->setName('to_worker');$i=0;

while ($i < 20) { $i++; $data = json_encode([1,2,3, rand(0, 1000)]); $exchange->publish($data, 'logs', 0, ['delivery_mode'=>2, 'content_type'=> 'text/json'] );}

Routing key Persisten

Синхронное / Асинхронное

Асинхронное GET

$rabbit = new AMQPConnection(); $rabbit->connect();

$channel = new AMQPChannel($rabbit$queue = new AMQPQueue($channel); $queue->setName('worker'); $msg = $queue->get();

Асинхронное GET

Синхронное CONSUMEfunction processMessage($envelope, $queue) { echo 'Message: [', $envelope->getDeliveryTag(), ']', $envelope->getBody(),PHP_EOL; $queue->ack( $envelope->getDeliveryTag() );}

$rabbit = new AMQPConnection();$res = $rabbit->connect(); $channel = new AMQPChannel($rabbit);

$queue = new AMQPQueue($channel); $queue->setName('worker');$queue->setFlags(AMQP_EXCLUSIVE);$queue->consume("processMessage");

Синхронное CONSUMEfunction processMessage($envelope, $queue) { echo 'Message: [', $envelope->getDeliveryTag(), ']', $envelope->getBody(),PHP_EOL; $queue->ack( $envelope->getDeliveryTag() );}

$rabbit = new AMQPConnection();$res = $rabbit->connect(); $channel = new AMQPChannel($rabbit);

$queue = new AMQPQueue($channel); $queue->setName('worker');$queue->setFlags(AMQP_EXCLUSIVE);$queue->consume("processMessage");

function processMessage($envelope, $queue) { echo 'Message: [', $envelope->getDeliveryTag(), ']', $envelope->getBody(),PHP_EOL; $queue->ack( $envelope->getDeliveryTag() );}

$rabbit = new AMQPConnection();$res = $rabbit->connect(); $channel = new AMQPChannel($rabbit);

$queue = new AMQPQueue($channel); $queue->setName('worker');$queue->setFlags(AMQP_EXCLUSIVE);$queue->consume("processMessage");

Синхронное CONSUME

Асинхронное GET

Publish/Consume

Publish/Consume

В RannitMQработает не так как ожидается

Publish/Consume

ЗагрузкаYML

ПарсингYML

Загрузкакартинок

Publish/Consume

ЗагрузкаYML

ПарсингYML

Загрузкакартинок

50%

50%

Publish/Consume

ЗагрузкаYML

ПарсингYML

Загрузкакартинок

50%

50%

Потеря 50% контента

Publish/Consume

ЗагрузкаYML

Загрузкакартинок

Загрузкакартинок

50%

50%

Publish/Consume

ЗагрузкаYML

Загрузкакартинок

Загрузкакартинок

33.3%

33.3%

33.3%Загрузкакартинок

Publish/Consume

ЗагрузкаYML

ПарсингYML

Загрузкакартинок

Channel -1

Channel -2

Несколько каналов

ПарсингYML

Загрузкакартинок

Channel -1

Channel -2

ЗагрузкаYML content

parsing

uploadingExchange: Content, funout, Bind: parsing durable Bind: uploading

Queue 1: parsing, durable

Queue 2: uploading, durable

Несколько каналов(вар 2)

ПарсингYML

Загрузкакартинок

Channel -1

Channel -2

ЗагрузкаYML content

parsing

uploadingExchange: Content, header, durable

Queue 1: parsing, durable

Queue 2: uploading, durable

Bind: operation:x-parsing Bind: operation:x-uploading

Несколько каналов(вар 2)

ПарсингYML

Загрузкакартинок

Channel -1

Channel -2

ЗагрузкаYML content

parsing

uploadingExchange: Content, header, durable

Queue 1: parsing, durable

Queue 2: uploading, durable

Bind: operation:x-parsing Bind: operation:x-uploading

Несколько каналов(вар 2)

ПарсингYML

Загрузкакартинок

Channel -1

Channel -2

ЗагрузкаYML content

parsing

uploadingExchange: Content, header, durable

Queue 1: parsing, durable

Queue 2: uploading, durable

Bind: operation:x-parsing Bind: operation:x-uploading

Несколько каналовimport pikaconnection = pika.BlockingConnection()ch = connection.channel()ch.queue_bind( exchange='content', queue='parser', arguments={'operation': 'parsing', 'x-match':'any'})

Несколько каналовimport pikaconnection = pika.BlockingConnection()ch = connection.channel()ch.queue_bind( exchange='content', queue='parser', arguments={'operation': 'parser', 'x-match':'any'})

в PHPНельзя задать

аргументы для Bind

Несколько каналов

$exchange = new AMQPExchange($channel);$exchange->setName('to_worker');$ex->setType(AMQP_EX_TYPE_HEADERS);

$data = json_encode([1,2,3]);$headers = ['operation' => 'parsing'];$args = [ 'content_type'=> 'text/json', 'headers' => $headers ];$exchange->publish($data,'work',0,$args);

Несколько каналов

$exchange = new AMQPExchange($channel);$exchange->setName('to_worker');$ex->setType(AMQP_EX_TYPE_HEADERS);

$data = json_encode([1,2,3]);$headers = ['operation' => 'parsing'];$args = [ 'content_type'=> 'text/json', 'headers' => $headers ];$exchange->publish($data,'work',0,$args);

Несколько каналов(вар 2)

Синхронное / Асинхронноеwhat is the question ?

WEB AJAX лучше асинхронное

WebSocket Синхронное

Синхронное / Асинхронное

WEB AJAX лучше асинхронное

AMQP REST https://github.com/akalend/amqp-rest

Синхронное / Асинхронное

WEB AJAX лучше асинхронное

AMQP REST https://github.com/akalend/amqp-rest

NGX-AMQP https://github.com/WPMedia/nginx-amqp

Синхронное / Асинхронное

WEB AJAX лучше асинхронное

AMQP REST https://github.com/akalend/amqp-rest

NGX-AMQP https://github.com/WPMedia/nginx-amqpНадо делать через Upstreem & subquery

Синхронное / Асинхронное

WEB AJAX лучше асинхронное

AMQP REST https://github.com/akalend/amqp-rest

NGX-AMQP https://github.com/WPMedia/nginx-amqp

NGX-RABBIT https://github.com/wingify/lua-resty-rabbitmqstomp

Синхронное / Асинхронное

WebSocket Синхронное

NGX-RABBIT https://github.com/wingify/lua-resty-rabbitmqstomp

Node.js

Routers

Exchange

Route Message

Direct – совпадение по ключу

● Bind Queue_1 logs

● Bind Queue_2 worker

Queue 1

Queue 2

Exchange

Route Message

Headers – совпадение по заголовку

● Bind Queue_1 {'operation' : 'logs', 'x-match':'any'}

● Bind Queue_2 {'operation' : 'worker' , 'x-match':'any'}

Queue 1

Queue 2

Messages

Варианты использования сообщений

Варианты использования сообщений

Паттерн: данные

workerWEB

Заказ

ПередачаЗаказа

Варианты использования сообщений

Загрузка видео с видео хостинга

LoadConvertWEB

Клиентскийскрипт

Получаем статусВыполнено

Curl

Channels

Poin-to-Point Channel

Poin-to-Point Channel

Exchange : durableQueue : durable, exclusive

Guaranteed Delivery

Guaranteed Delivery

Exchange : durable= 1Message : delivery-type = 2Queue : durable= 1, autodelete = 0, autoack = 1

Guaranteed Delivery

$delivery-tag = $message->delivery-tag;$queue->ack($delivery-tag);

Dead letter channel

Запасной канал

$exchange = new AMQPExchange($channel);$exchange->setFlags(AMQP_DURABLE);$exchange->setName('to_worker');$exchange->setType(AMQP_EX_TYPE_DIRECT);$exchange->declare();

$queue = new AMQPQueue($channel);$queue->setFlags(AMQP_AUTODELETE);$queue->setName('worker');$queue->declare();

$queue->bind('to_worker', 'work');$queue->setFlags(AMQP_DURABLE);$queue->setName('garbage');$queue->declare();$queue->bind('to_worker', 'work');

Запасной канал

Запасной канал

$queue->setName('worker');$queue->delete();$queue->setArgument('x-dead-letter-exchange','garbage');$queue->declare();$queue->bind('to_worker', 'work');

Request Reply

Correlation Identifier

Correlation Identifier

$cr_id = $message->getArgument('correlation_id');

$exchange->publish( $message, '', ['correlation_id=>$cr_id]);

Datatype channel

debugging

Debugging

Java -cp rabbitmq-client.jar:commons-io-1.2.jar:commons-cli-1.1.jar com.rabbitmq.tools.Tracer677

Rabbit MQ

2015 № 11

Кролик в песочнице

Rabbit MQ

2015 № 12

RabbitMQ. Вырастаем из штанишек.

книги

книги

книги

книги

Cпасибо за внимание