TCP/IP-based
$ 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
Standard port: 5672
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
^@
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
$ python send.py
[x] Sent 'Hello World!'
$ python receive.py
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'Hello World!
distribute time-consuming tasks among multiple workers
$ 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....'
$ 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)
channel.basic_qos(prefetch_count=1)
$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)
);
<?php
list($queue_name, ,) = $channel->queue_declare("");
$channel->queue_bind($queue_name, 'logs');
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.
$binding_key = 'black';
$channel->queue_bind($queue_name, $exchange_name, $binding_key);
$channel->basic_publish($msg, $exchange_name, $binding_key);
When to use ?
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
used to distribute tasks between multiple workers in a round robin manner
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
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
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
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
$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);
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);
}
};
{
"require": {
"videlalvaro/php-amqplib": "2.5.*"
}
}
Supported RabbitMQ Extensions
<?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();
<?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']);
}
}
<?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();
}
<?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();
<?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);
}
<?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']);
<?php
define('AMQP_DEBUG', true);
... more code
?>
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
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
{
"require": {
"oldsound/rabbitmq-bundle": "1.8.*"
}
}
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
//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;
}
}
}
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));
}
$ ./app/console rabbitmq:consumer -w upload_picture
rabbitmq-plugins enable rabbitmq_management
The web UI is located at: http://server-name:15672/
/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_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
[
{
"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
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
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.
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.
@ ArkadiuszKondas
itcraftsman.pl