RabbitMQ tutorial - "Hello world!"
本例
- 阻塞執行緒方式
- 一生產者一消費者
依賴項
- abbitMQ is installed
- running on localhost on the standard port (5672).
理解
RabbitMQ is a message broker: it accepts and forwards messages. You can think about it as a post office: when you put the mail that you want posting in a post box, you can be sure that the letter carrier will eventually deliver the mail to your recipient. In this analogy, RabbitMQ is a post box, a post office, and a letter carrier.
The major difference between RabbitMQ and the post office is that it doesn't deal with paper, instead it accepts, stores, and forwards binary blobs of data ‒ messages.
RabbitMQ 術語(用於節點描述)
- producer / Producing
Producing means nothing more than sending. A program that sends messages is a producer :
(P)
- queue
A queue is the name for the post box in RabbitMQ. Although messages flow through RabbitMQ and your applications, they can only be stored inside a queue. A queue is only bound by the host's memory & disk limits, it's essentially a large message buffer.
Many producers can send messages that go to one queue, and many consumers can try to receive data from one queue.
This is how we represent a queue:
||queue_name||
- consumer / Consuming
Consuming has a similar meaning to receiving. A consumer is a program that mostly waits to receive messages:
(C)
producer, consumer, broker 和 application, host
Note that the producer, consumer, and broker do not have to reside on the same host; indeed in most applications they don't. An application can be both a producer and consumer, too.
Hello World! 示例(Pika庫)
一個producer (sender)發,一個consumer (receiver)收,收了之後列印。
節點說明
In the diagram below, "P" is our producer and "C" is our consumer. The box in the middle is a queue - a message buffer that RabbitMQ keeps on behalf of the consumer.
完整設計如下:
(P) -> ||hello|| -> (C)
Producer sends messages to the "hello" queue. The consumer receives messages from that queue.
協議
RabbitMQ speaks multiple protocols. This tutorial uses AMQP 0-9-1, which is an open, general-purpose protocol for messaging.
安裝pika
程式碼(命令列)
python -m pip install pika --upgrade
程式碼說明
傳送
P -> ||hello||
傳送程式碼(send.py)傳送一個簡單訊息到佇列中。
首先是連上伺服器
The first thing we need to do is to establish a connection with RabbitMQ server.
程式碼(py)
!/usr/bin/env python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
如果不是本地機器
We're connected now, to a broker on the local machine - hence the localhost. If we wanted to connect to a broker on a different machine we'd simply specify its name or IP address here.
建立名為hello的佇列
Next, before sending we need to make sure the recipient queue exists. If we send a message to non-existing location, RabbitMQ will just drop the message. Let's create a hello queue to which the message will be delivered:
程式碼(py)
channel.queue_declare(queue='hello')
傳送訊息
At this point we're ready to send a message. Our first message will just contain a string Hello World! and we want to send it to our hello queue.
In RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange. But let's not get dragged down by the details ‒ you can read more about exchanges in the third part of this tutorial. All we need to know now is how to use a default exchange identified by an empty string. This exchange is special ‒ it allows us to specify exactly to which queue the message should go. The queue name needs to be specified in the routing_key parameter:
程式碼(py)
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
Before exiting the program we need to make sure the network buffers were flushed and our message was actually delivered to RabbitMQ. We can do it by gently closing the connection.
程式碼(py)
connection.close()
如果傳送不成功
If this is your first time using RabbitMQ and you don't see the "Sent" message then you may be left scratching your head wondering what could be wrong. Maybe the broker was started without enough free disk space (by default it needs at least 200 MB free) and is therefore refusing to accept messages. Check the broker logfile to confirm and reduce the limit if necessary. The configuration file documentation will show you how to set disk_free_limit.
接收
||hello|| -> (C)
接收程式碼(receive.py)從佇列中接收訊息,輸出到螢幕。
連線到伺服器的程式碼和傳送程式碼相同。
queue_declare 對於同一個名稱的佇列可以呼叫多次,只有第一次呼叫執行建立佇列的操作。
程式碼(py)
channel.queue_declare(queue='hello')
You may ask why we declare the queue again ‒ we have already declared it in our previous code. We could avoid that if we were sure that the queue already exists. For example if send.py program was run before. But we're not yet sure which program to run first. In such cases it's a good practice to repeat declaring the queue in both programs.
檢視所有佇列(以及多少訊息在裡面)
linux系統(as a privileged user)
程式碼(命令列)
sudo rabbitmqctl list_queues
Windows系統
程式碼(命令列)
rabbitmqctl.bat list_queues
接收訊息需要用到回撥函式
程式碼(py)
def callback(ch, method, properties, body):
print(f" [x] Received {body}")
回撥函式指定處理佇列
程式碼(py)
channel.basic_consume(queue='hello',
auto_ack=True, #
on_message_callback=callback)
上面程式碼執行成功的前提是'hello'佇列已經建立。
新增按鍵(Ctrl+C)捕捉
And finally, we enter a never-ending loop that waits for data and runs callbacks whenever necessary, and catch KeyboardInterrupt during program shutdown.
程式碼(py)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
if name == 'main':
try:
main()
except KeyboardInterrupt:
print('Interrupted')
try:
sys.exit(0)
except SystemExit:
os._exit(0)
py檔案方式的程式碼
send.py (source)
程式碼(py)
!/usr/bin/env python
import pika
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='', routing_key='hello', body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()
receive.py (source)
程式碼(py)
!/usr/bin/env python
import pika, sys, os
def main():
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
print(f" [x] Received {body}")
channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
if name == 'main':
try:
main()
except KeyboardInterrupt:
print('Interrupted')
try:
sys.exit(0)
except SystemExit:
os._exit(0)
先執行接收程式然後執行傳送程式
Now we can try out our programs in a terminal. First, let's start a consumer, which will run continuously waiting for deliveries:
執行接收程式(會一直執行,可按Ctrl+C退出執行)
python receive.py
接收端輸出
=> [*] Waiting for messages. To exit press CTRL+C
執行傳送程式(每執行一次僅傳送一條訊息後退出)
python send.py
傳送端輸出
=> [x] Sent 'Hello World!'
接收端輸出
=> [*] Waiting for messages. To exit press CTRL+C
=> [x] Received 'Hello World!'
動手:多執行幾次傳送程式,觀察接收端的輸出。
命令列方式的程式碼:Producer + Consumer
接收訊息的示例(Consumer)
程式碼(py)
import pika
連線到RabbitMQ伺服器
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
宣告佇列
channel.queue_declare(queue='hello')
定義回撥函式處理接收到的訊息
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
設定消費者
channel.basic_consume(queue='hello',
on_message_callback=callback,
auto_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
傳送訊息的示例(Producer)
程式碼(py)
import pika
連線到RabbitMQ伺服器
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
宣告一個佇列
channel.queue_declare(queue='hello')
傳送訊息
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()
來源
來自系列
https://www.rabbitmq.com/tutorials
中的下文刪減
https://www.rabbitmq.com/tutorials/tutorial-one-python
其他參考
https://www.rabbitmq.com/
https://www.rabbitmq.com/tutorials
獲取幫助
GitHub Discussions or RabbitMQ community Discord.
安裝說明和下載地址
https://www.rabbitmq.com/docs/install-windows
https://www.erlang.org/downloads
https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.13.3