Solidne kolejki
z RabbitMQ

  1. Witaj w świecie wiadomości
  2. RabbitMQ - Messaging that just works
  3. Dostępne liby 
  4. Jak sprawować władzę ?
  5. Królik na produkcji

Agenda:

Welcome to messaging

Why messaging ?

  • Get data from point A to point B 
  • Decouple publishers and consumers
  • Queueing for later delivery
  • Asynchronous
  • Load balancing and scalability

 MQTT, AMQP and STOMP

TCP/IP-based

 MQTT

Message Queue Telemetry Transport

  • Open : created by IBM & Eurotech and donated to Eclipse “Paho” M2M project (OASIS standard in 2014)
  • Lightweight : smallest packet size 2 bytes (header), reduced clients footprint (C# M2Mqtt library 30 KB)
  • Reliable : three QoS and patterns to avoid packet loss on client disconnection
  • Simple :
    • TCP based
    • Asynchronous
    • Publish/Subscribe
    • Few verbs
    • Payload agnostic

 MQTT

Message Queue Telemetry Transport

 MQTT

Message Queue Telemetry Transport

$ mosquitto -p 1884
1453924652: mosquitto version 1.4.3 (build date Wed, 19 Aug 2015 10:31:10 +0100) starting
1453924652: Using default config.
1453924652: Opening ipv4 listen socket on port 1884.
1453924652: Opening ipv6 listen socket on port 1884.
1453924675: New connection from 127.0.0.1 on port 1884.
1453924675: New client connected from 127.0.0.1 as mosqpub/14399-craftsbox (c1, k60)
mosquitto_sub -h 127.0.0.1 -p 1884 -t "server1/cpu/temperature"
mosquitto_pub -h 127.0.0.1 -p 1884 -t "server1/cpu/temperature" -m "Temp: 55C"
mosquitto_sub -h 127.0.0.1 -p 1884 -t "server1/cpu/temperature"
Temp: 55C
Temp: 53C
Temp: 54C
Temp: 55C
Temp: 55C

 AMQP

Advanced Message Queuing Protocol

  • Internet protocol - like HTTP, TCP - but ASYNCHRONOUS
  • Routing (where to send messages)
  • Delivery (how to get there)
  • Fidelity (what goes in must come out)
  • Wide range of features:
    •  queuing
    • topic-based publish-and-subscribe messaging
    • flexible routing
    • transactions
    • security

Standard port: 5672

 AMQP

Advanced Message Queuing Protocol

STOMP

Simple/Streaming Text Oriented Messaging Protocol

  •  text-based
  • more analogous to HTTP
  • possible to connect to a STOMP broker using something as simple as a telnet client
  • destination (instead of queue)
  • simple and lightweight (for humans)

STOMP

Simple/Streaming Text Oriented Messaging Protocol

MESSAGE
subscription:0
message-id:007
destination:/queue/a
content-type:text/plain

hello queue a^@
SUBSCRIBE
id:0
destination:/queue/foo
ack:client

^@
BEGIN
transaction:tx1

^@


COMMIT
transaction:tx1

^@


ABORT
transaction:tx1

^@

STOMP - Frames

CONNECT or STOMP
REQUIRED: accept-version, host
OPTIONAL: login, passcode, heart-beat

CONNECTED
REQUIRED: version
OPTIONAL: session, server, heart-beat

SEND
REQUIRED: destination
OPTIONAL: transaction

SUBSCRIBE
REQUIRED: destination, id
OPTIONAL: ack

UNSUBSCRIBE
REQUIRED: id
OPTIONAL: none

ACK or NACK
REQUIRED: id
OPTIONAL: transaction

BEGIN or COMMIT or ABORT
REQUIRED: transaction
OPTIONAL: none
DISCONNECT
REQUIRED: none
OPTIONAL: receipt

MESSAGE
REQUIRED: destination, message-id, subscription
OPTIONAL: ack

RECEIPT
REQUIRED: receipt-id
OPTIONAL: none

ERROR
REQUIRED: none
OPTIONAL: message

RabbitMQ: The Polyglot Broker

RabbitMQ - Messaging that just works

RabbitMQ

  • RabbitMQ is an AMQP messaging broker written in Erlang
  • RabbitMQ 3.0 supports MQTT, AMQP and STOMP
  • Core development team in London, UK
  • Rabbit is a part of AMQP Working Group

Virtual Hosts

  • Created for administrative purposes
  • Access control
  • Each connection (and all channels inside) must be associated with a single virtual host
  • Each virtual host comprises its own name space, a set of exchanges, message queues and all associated objects 

 

Hello World

 

 $ python send.py
 [x] Sent 'Hello World!'


 $ python receive.py
 [*] Waiting for messages. To exit press CTRL+C
 [x] Received 'Hello World!

Queue

  • named "weak FIFO" buffer
     
  • FIFO is guaranteed only with 1 consumer
     
  • Can be durable, temporary (private to 1 consumer) or auto-deleted
     
  • A message routed to a queue is never sent to more than one client unless it is being resent after failure or rejection
     
  • You can get server to auto generate and assign queue name for your queue — this is usually done for private queues 

Messages

  • Messages carry content (header + body)
     
  • Content body is opaque block of binary data
     
  • Broker never modifies content body
     
  • AMQP defines several "content classes," each with specific syntax (which headers can be used) and semantics (which methods are available for such messages) 

 

Workers

distribute time-consuming tasks among multiple workers

Round-robin dispatching

$ python new_task.py First message.
$ python new_task.py Second message..
$ python new_task.py Third message...
$ python new_task.py Fourth message....
$ python new_task.py Fifth message.....
// shell 1
$ python worker.py
 [*] Waiting for messages. To exit press CTRL+C
 [x] Received 'First message.'
 [x] Received 'Third message...'
 [x] Received 'Fifth message.....'

// shell 2
$ python worker.py
 [*] Waiting for messages. To exit press CTRL+C
 [x] Received 'Second message..'
 [x] Received 'Fourth message....'

Workers

  • Message acknowledgment

     
  • Forgotten acknowledgment
     

 

  • Message durability
$ sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged
Listing queues ...
hello    0       0
...done.
channel.queue_declare(queue='hello', durable=True)

channel.basic_publish(exchange='',
      routing_key="task_queue",
      body=message,
      properties=pika.BasicProperties(
         delivery_mode = 2, # make message persistent
      ))
channel.basic_consume(callback,
                      queue='hello',
                      no_ack=True)

Workers

  • Fair dispatch
     
  • RabbitMQ doesn't allow you to redefine an existing queue with different parameters
channel.basic_qos(prefetch_count=1)

Workers

  • Marking messages as persistent doesn't fully guarantee that a message won't be lost. 
    • Transactions: x 250 slower !!!
    • Confirm mode

       
    •  
  • Queue Length Limit
$conn = new AMQPConnection('192.168.1.1', 5672, 'user', 'pass');
$ch = $conn->channel();
$ch->set_ack_handler(function($message){});
$ch->set_nack_handler(function($message){});
$ch->confirm_select();
$ch->wait_for_pending_acks();
$conn = new AMQPConnection('192.168.1.1', 5672, 'user', 'pass');
$ch = $conn->channel();
$arguments = [,
    "x-max-length" => 10000,
    "x-max-length-bytes" => 102400000,
];
$ch->queue_declare(
    $name, $passive, $durable, $exclusive, 
    $autoDelete, $nowait, new AMQPTable($arguments)
);

Publish/Subscribe

  • Exchanges *(default exchange)
    •  direct, topic, headers, fanout
  • Bindings
<?php

list($queue_name, ,) = $channel->queue_declare("");

$channel->queue_bind($queue_name, 'logs');

Publish/Subscribe

sudo rabbitmqctl list_exchanges
Listing exchanges ...

amq.direct	direct
amq.fanout	fanout
amq.headers	headers
amq.match	headers
amq.rabbitmq.log	topic
amq.rabbitmq.trace	topic
amq.topic	topic
bench_exchange	direct
router	direct
someExchange	fanout
$ sudo rabbitmqctl list_bindings
Listing bindings ...
logs    exchange        amq.gen-JzTY20BRgKO-HjmUJj0wLg  queue           []
logs    exchange        amq.gen-vso0PVvyiRIL2WoV3i48Yg  queue           []
...done.

Exchanges

  • A message routing agent
  • Can be durable — lasts till explicitly deleted
  • Can be temporary — lasts till server shuts down
  • Can be auto-deleted — lasts till no longer used
  • There are several types of exchanges, each implements a particular algorithm
  • Each message is delivered to each qualifying queue
  • "Binding" - a link between queue and exchange 

 

Routing

  • Routing key
  • Direct exchange
  • Multiple bindings
$binding_key = 'black';

$channel->queue_bind($queue_name, $exchange_name, $binding_key);

$channel->basic_publish($msg, $exchange_name, $binding_key);

Fanout Exchange

  • routes messages to all of the queues that are bound to it
  • copy of the message is delivered to all N queues

When to use ?

  • MMO games
  • sport news
  • group chats

Fanout Exchange

conn.start
ch   = conn.create_channel
x    = ch.fanout("examples.pings")

10.times do |i|
  q = ch.queue("", :auto_delete => true).bind(x)
  q.subscribe do |delivery_info, properties, payload|
    puts "[consumer] #{q.name} received a message: #{payload}"
  end
end

x.publish("Ping")
[consumer] amq.gen-A8z-tj-n_0U39GdPGncV-A received a message: Ping
[consumer] amq.gen-jht-OtRwdD8LuHMxrA5SNQ received a message: Ping
[consumer] amq.gen-LQTh8IdojOCrvOnEuFog8w received a message: Ping
[consumer] amq.gen-PV-Dg8_gSvLO9eK6le6wwQ received a message: Ping
[consumer] amq.gen-ofAMc3FXRZIj3O55fXDSwA received a message: Ping
[consumer] amq.gen-TXJiZEjwZ0squ12_Z9mP0A received a message: Ping
[consumer] amq.gen-XQjh2xrC9khbMZMg_0Zzfw received a message: Ping
[consumer] amq.gen-XVSKsdWwhyxRiJn-jAFEGg received a message: Ping
[consumer] amq.gen-ZaY2pD_9NaOICxAMWPoIYw received a message: Ping
[consumer] amq.gen-oElfvP_crgASWkk6EhrJLA received a message: Ping

Direct Exchange

  • delivers messages to queues based on the message routing key

used to distribute tasks between multiple workers in a round robin manner

Direct Exchange

conn.start

ch   = conn.create_channel
x    = ch.direct("examples.imaging")

q1 = ch.queue("", :auto_delete => true).bind(x, :routing_key => "resize")
q1.subscribe do |delivery_info, properties, payload|
  puts "[consumer] #{q1.name} received a 'resize' message"
end

q2 = ch.queue("", :auto_delete => true).bind(x, :routing_key => "watermark")
q2.subscribe do |delivery_info, properties, payload|
  puts "[consumer] #{q2.name} received a 'watermark' message"
end

Headers Exchange

conn.start

ch   = conn.create_channel
x    = ch.headers("headers")

q1   = ch.queue("").bind(x, :arguments => 
    {"os" => "linux", "cores" => 8, "x-match" => "all"})

q2   = ch.queue("").bind(x, :arguments => 
    {"os" => "osx",   "cores" => 4, "x-match" => "any"})

q3   = ch.queue("").bind(x, :arguments => 
    {"os" => "windows"})

Routing on multiple attributes that are more easily expressed as message headers than a routing key

Topic Exchange

Route messages to one or many queues based on matching between a message routing key and the pattern that was used to bind a queue to an exchange

Topic Exchange

x    = ch.topic("weathr", :auto_delete => true)

q = ch.queue("americas.south", :auto_delete => true)
    .bind(x, :routing_key => "americas.south.#")

q.subscribe do |delivery_info, properties, payload|
  puts "An update for South America: #{payload}, r
    outing key is #{delivery_info.routing_key}"
end
americas.south.# match:

americas.south
americas.south.brazil
americas.south.brazil.saopaolo
americas.south.chile.santiago

RPC

Remote procedure call

  • RPC over RabbitMQ is easy
  • Client send request message
  • Server replies response message
  • correlation_id

RPC - Server

$channel->queue_declare('rpc_queue', false, false, false, false);

function fib($n) {
    if ($n == 0)
        return 0;
    if ($n == 1)
        return 1;
    return fib($n-1) + fib($n-2);
}

echo " [x] Awaiting RPC requests\n";
$callback = function($req) {
    $n = intval($req->body);
    echo " [.] fib(", $n, ")\n";

    $msg = new AMQPMessage(
        (string) fib($n),
        array('correlation_id' => $req->get('correlation_id'))
        );

    $req->delivery_info['channel']->basic_publish(
        $msg, '', $req->get('reply_to'));
    $req->delivery_info['channel']->basic_ack(
        $req->delivery_info['delivery_tag']);
};

$channel->basic_qos(null, 1, null);
$channel->basic_consume('rpc_queue', '', false, false, false, false, $callback);

RPC - Client

class FibonacciRpcClient {
    /* attributes */

    public function __construct() {
        $this->connection = new AMQPStreamConnection(
            'localhost', 5672, 'guest', 'guest');
        $this->channel = $this->connection->channel();
        list($this->callback_queue, ,) = $this->channel->queue_declare(
            "", false, false, true, false);
        $this->channel->basic_consume(
            $this->callback_queue, '', false, false, false, false,
            array($this, 'on_response'));
    }
    public function on_response($rep) {
        if($rep->get('correlation_id') == $this->corr_id) {
            $this->response = $rep->body;
        }
    }

    public function call($n) {
        $this->response = null;
        $this->corr_id = uniqid();

        $msg = new AMQPMessage(
            (string) $n,
            array('correlation_id' => $this->corr_id,
                  'reply_to' => $this->callback_queue)
            );
        $this->channel->basic_publish($msg, '', 'rpc_queue');
        while(!$this->response) {
            $this->channel->wait();
        }
        return intval($this->response);
    }
};

Homework

  • Echanges/queues options
    • x-message-ttl
       
  • Dead Letter Exchanges
     
  • Clustering
    • Replication with full ACID properties
       
  • Community
     
  • Performance
    • Achieved throughput of 1.3 million msg/sec
    • XMPP + RabbitMQ = Twitter That Doesn't Go Down 

RabbitMQ + PHP = ?

videlalvaro/php-amqplib

  • PHP 5.3 
  • AMQP 0.9.1 
  • RabbitMQ 2.0
{
  "require": {
      "videlalvaro/php-amqplib": "2.5.*"
  }
}
  • Exchange to Exchange Bindings
  • Basic Nack
  • Publisher Confirms
  • Consumer Cancel Notify

 

Supported RabbitMQ Extensions

Publisher

<?php
$exchange = 'router';
$queue = 'msgs';
$conn = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST);
$ch = $conn->channel();

$ch->queue_declare($queue, $passive = false, $durable = true,
    $exclusive = false, $auto_delete = false);

$ch->exchange_declare($exchange, $type = 'direct', $passive = false,
    $durable = true, $auto_delete = false);

$ch->queue_bind($queue, $exchange);

$msg = new AMQPMessage('message', ['content_type' => 'text/plain', 
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);

$ch->basic_publish($msg, $exchange);

$ch->close();
$conn->close();

videlalvaro/php-amqplib

Consumer

<?php
$exchange = 'router';
$queue = 'msgs';
$consumer_tag = 'consumer';
$conn = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST);
$ch = $conn->channel();
$ch->queue_declare($queue, $passive = false, $durable = true, $exclusive = false, $auto_delete = false);
$ch->exchange_declare($exchange, $type = 'direct', $passive = false, $durable = true, $auto_delete = false);
$ch->queue_bind($queue, $exchange);

/**
 * @param \PhpAmqpLib\Message\AMQPMessage $msg
 */
function process_message($msg)
{
    echo $msg->body;
    $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
    // Send a message with the string "quit" to cancel the consumer.
    if ($msg->body === 'quit') {
        $msg->delivery_info['channel']->basic_cancel($msg->delivery_info['consumer_tag']);
    }
}

videlalvaro/php-amqplib

Consumer

<?php
// ...

$ch->basic_consume($queue, $consumer_tag, $no_local = false, $no_ack = false, 
    $exclusive = false, $nowait = false, 'process_message');

/**
 * @param \PhpAmqpLib\Channel\AMQPChannel $ch
 * @param \PhpAmqpLib\Connection\AbstractConnection $conn
 */
function shutdown($ch, $conn)
{
    $ch->close();
    $conn->close();
}
register_shutdown_function('shutdown', $ch, $conn);

// Loop as long as the channel has callbacks registered
while (count($ch->callbacks)) {
    $ch->wait();
}

videlalvaro/php-amqplib

Batch Publishing

<?php

$msg = new AMQPMessage($msg_body);
$ch->batch_basic_publish($msg, $exchange);

$msg2 = new AMQPMessage($msg_body);
$ch->batch_basic_publish($msg2, $exchange);

$ch->publish_batch();

videlalvaro/php-amqplib

Optimized Message Publishing

<?php

$properties = [
    'content_type' => 'text/plain',
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
];
$msg = new AMQPMessage($body, $properties);

// ...

for($i=0; $i<$limit; $i++)
{
    $msg->setBody($body2);
    $ch->basic_publish($msg, $exchange);
}

videlalvaro/php-amqplib

Truncating Large Messages

<?php

$channel->setBodySizeLimit(int $bytes);

/**
 * @var AMQPMessage
 */
$message->is_truncated; // true

$message->body_size > strlen($message->getBody());

// ...

$ch->basic_reject($message->delivery_info['delivery_tag']);
$ch->basic_nak($message->delivery_info['delivery_tag']);

videlalvaro/php-amqplib

Debugging

<?php
define('AMQP_DEBUG', true);

... more code

?>

videlalvaro/php-amqplib

Publishing 4000 msgs with 1KB of content:
php benchmark/producer.php 4000
0.1589469909668
Consuming 4000:
php benchmark/consumer.php
Pid: 10166, Count: 4000, Time: 0.5788
Stream produce 100:
php benchmark/stream_tmp_produce.php 100
4.3202359676361
Socket produce 100:
php benchmark/socket_tmp_produce.php 100
0.16255402565002

Benchmark

More examples

videlalvaro/php-amqplib

https://github.com/videlalvaro/php-amqplib/tree/master/demo
amqp_consumer_exclusive.php
amqp_consumer_fanout_1.php
amqp_consumer_fanout_2.php
amqp_consumer_non_blocking.php
amqp_consumer.php
amqp_consumer_signals.php
amqp_ha_consumer.php
amqp_message_headers_recv.php
amqp_message_headers_snd.php
amqp_publisher_exclusive.php
amqp_publisher_fanout.php
amqp_publisher.php
amqp_publisher_with_confirms_mandatory.php
amqp_publisher_with_confirms.php
basic_cancel.php
basic_get.php
basic_nack.php
basic_qos.php
basic_return.php
batch_publish.php
config.php
delayed_message.php
e2e_bindings.php
queue_arguments.php
ssl_connection.php

videlalvaro/RabbitMqBundle

  • php-amqplib
{
  "require": {
      "oldsound/rabbitmq-bundle": "1.8.*"
  }
}

Symfony ?

videlalvaro/RabbitMqBundle

old_sound_rabbit_mq:
    connections:
        default:
            host:     'localhost'
            port:     5672
            user:     'guest'
            password: 'guest'
            vhost:    '/'
            lazy:     false
            connection_timeout: 3
            read_write_timeout: 3

            # requires php-amqplib v2.4.1+ and PHP5.4+
            keepalive: false

            # requires php-amqplib v2.4.1+
            heartbeat: 0
    producers:
        upload_picture:
            connection:       default
            exchange_options: {name: 'upload-picture', type: direct}
    consumers:
        upload_picture:
            connection:       default
            exchange_options: {name: 'upload-picture', type: direct}
            queue_options:    {name: 'upload-picture'}
            callback:         upload_picture_service

videlalvaro/RabbitMqBundle

//src/Acme/DemoBundle/Consumer/UploadPictureConsumer.php

namespace Acme\DemoBundle\Consumer;

use OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface;
use PhpAmqpLib\Message\AMQPMessage;

class UploadPictureConsumer implements ConsumerInterface
{
    public function execute(AMQPMessage $msg)
    {

        $isUploadSuccess = someUploadPictureMethod();
        if (!$isUploadSuccess) {
            return false;
        }
    }
}

Consumer

videlalvaro/RabbitMqBundle

public function indexAction($name)
{
    $msg = ['user_id' => 1235, 'image_path' => '/path/to/new/pic.png'];
    $this->get('old_sound_rabbit_mq.upload_picture_producer')
        ->publish(serialize($msg));
}

Producer

$ ./app/console rabbitmq:consumer -w upload_picture

Run consumer

Jak kontrolować ?

Management Plugin

  • Declare, list and delete exchanges, queues, bindings, users, virtual hosts and permissions.
     
  • Monitor queue length, message rates globally and per channel, data rates per connection, etc.
     
  • Send and receive messages.
     
  • Monitor Erlang processes, file descriptors, memory use.
     
  • Export / import object definitions to JSON.
     
  • Force close connections, purge queues.

Management Plugin

rabbitmq-plugins enable rabbitmq_management

The web UI is located at: http://server-name:15672/

Management Plugin

API

http://server-name:15672/api

/api/cluster-name
/api/nodes
/api/nodes/name
/api/extensions
/api/definitions
/api/all-configuration (deprecated)
/api/connections
/api/connections/name
/api/connections/name/channels
/api/channels
/api/channels/channel
/api/consumers
/api/consumers/vhost
/api/exchanges
/api/exchanges/vhost
/api/exchanges/vhost/name
/api/exchanges/vhost/name/bindings/source
/api/exchanges/vhost/name/bindings/destination
/api/exchanges/vhost/name/publish
/api/queues
/api/queues/vhost
/api/queues/vhost/name
/api/queues/vhost/name/bindings
/api/queues/vhost/name/contents
/api/queues/vhost/name/actions
/api/queues/vhost/name/get
/api/bindings
/api/bindings/vhost
/api/bindings/vhost/e/exchange/q/queue
/api/bindings/vhost/e/exchange/q/queue/props
/api/bindings/vhost/e/source/e/destination
/api/bindings/vhost/e/source/e/destination/props
/api/vhosts
/api/vhosts/name
/api/vhosts/name/permissions
/api/users
/api/users/name
/api/users/user/permissions
/api/whoami
/api/permissions
/api/permissions/vhost/user
/api/parameters
/api/parameters/component
/api/parameters/component/vhost
/api/parameters/component/vhost/name
/api/policies
/api/policies/vhost
/api/policies/vhost/name
/api/aliveness-test/vhost

Management Plugin API

{
   "management_version":"3.2.4",
   "statistics_level":"fine",
   "exchange_types":[
      {
         "name":"fanout",
         "description":"AMQP fanout exchange, as per the AMQP specification",
         "enabled":true
      },
      /* ... */
   ],
   "rabbitmq_version":"3.2.4",
   "erlang_version":"R16B03",
   "erlang_full_version":"Erlang R16B03 (erts-5.10.4) [source] [64-bit] [smp:2:2] [async-threads:30] [kernel-poll:true]",
   "message_stats":{
      "publish":8402,
      "publish_details":{
         "rate":0.0
      },
      "deliver_get":8002,
      "deliver_get_details":{
         "rate":0.0
      },
      "deliver_no_ack":8002,
      "deliver_no_ack_details":{
         "rate":0.0
      }
   },
   "queue_totals":{
      "messages":0,
      "messages_details":{
         "rate":0.0
      },
      "messages_ready":0,
      "messages_ready_details":{
         "rate":0.0
      },
      "messages_unacknowledged":0,
      "messages_unacknowledged_details":{
         "rate":0.0
      }
   },
   "object_totals":{
      "consumers":0,
      "queues":14,
      "exchanges":9,
      "connections":0,
      "channels":0
   },
   "node":"rabbit@rb",
   "statistics_db_node":"rabbit@rb",
   "listeners":[
      {
         "node":"rabbit@rb",
         "protocol":"amqp",
         "ip_address":"::",
         "port":5672
      }
   ],
   "contexts":[
      {
         "node":"rabbit@rb",
         "description":"RabbitMQ Management",
         "path":"/",
         "port":15672
      },
      {
         "node":"rabbit@rb",
         "description":"Redirect to port 15672",
         "path":"/",
         "port":55672,
         "ignore_in_use":true
      }
   ]
}
GET http://localhost:15672/api/overview

Management Plugin API

[
   {
      "name":"guest",
      "password_hash":"u04SlVVRrn193HhxoDHglwSJ7xI=",
      "tags":"administrator"
   },
   {
      "name":"admin",
      "password_hash":"tqswe/1fX9+fPZddGGOkoET+1Wc=",
      "tags":""
   },
   {
      "name":"test",
      "password_hash":"NbMYANj9V3a6fRRDEbabeTGgfeI=",
      "tags":""
   }
]
GET http://localhost:15672/api/users

Management Plugin API

PUT /api/users/newadmin HTTP/1.1
Host: localhost:15672
Content-Type: application/json
Cache-Control: no-cache

{"password":"secret","tags":"administrator"}

------------

204 No Content

RabbitMQ na produkcji

RabbitMQ na produkcji

JPMorgan

Sends 1 billion AMQP messages per day; used in dozens of mission critical systems worldwide.

NASA

The control plane of the Nebula Cloud Computing.

RabbitMQ na produkcji

UIDAI, Government of India

UIDAI is the the largest online identity project in the world aiming to provide each of India's 1.2 billion residents with a unique identity number. UIDAI uses RabbitMQ to decouple sub-components of its application allowing it to scale.

RabbitMQ na produkcji

Pytania ?

Dziękuję za uwagę

@ ArkadiuszKondas

itcraftsman.pl

Solidne kolejki z RabbitMQ

By Arkadiusz Kondas

Solidne kolejki z RabbitMQ

Od początku czyli o MQTT, AMQP, STOMP, następnie dużo o RabbitMQ. Trochę przykładów w PHP i kilka ciekawostek.

  • 479
Loading comments...

More from Arkadiusz Kondas