cent6.6安装rabbitmq
如果对运维课程感兴趣,可以在b站上、A站或csdn上搜索我的账号: 运维实战课程,可以关注我,学习更多免费的运维实战技术视频
1.在服务器192.168.231.128上安装rabbitmq
1)安装编译工具
[root@localhost ~]# yum -y install make gcc gcc-c++
2)安装相关依赖包
[root@localhost ~]# yum -y install kernel-devel m4 ncurses-devel openssl-devel
3)源码安装erlang(rabbimq依赖该包,rabbitmq是erlang语言开发的)
[root@localhost ~]# ls /erlang/
otp_src_R16B02.tar.gz
[root@localhost ~]# cd /erlang/
[root@localhost erlang]# ls
otp_src_R16B02.tar.gz
[root@localhost erlang]# tar -zxf otp_src_R16B02.tar.gz
[root@localhost erlang]# ls
otp_src_R16B02 otp_src_R16B02.tar.gz
[root@localhost erlang]# cd otp_src_R16B02
[root@localhost otp_src_R16B02]# ls
aclocal.m4 bootstrap EPLICENCE HOWTO Makefile.in plt system
AUTHORS configure erl-build-tool-vars.sh lib otp_build prebuilt.files TAR.include
bin configure.in erts make otp_client_build.temp_stderr.10373 README.md xcomp
[root@localhost otp_src_R16B02]# ./configure --prefix=/usr/local/erlang --with-ssl --enable-threads --enable-smp-support --enable-kernel-poll --enable-hipe --without-javac
#不用java编译,故去掉java避免错误
[root@localhost otp_src_R16B02]# make && make install
4)配置环境变量,让rabbitmq能找到安装的erlang软件
[root@localhost otp_src_R16B02]# vim /etc/profile
ERL_HOME=/usr/local/erlang
export PATH=$PATH:$ERL_HOME/bin
wq
[root@localhost otp_src_R16B02]# source /etc/profile
[root@localhost otp_src_R16B02]# cd
5)源码安装rabbitmq
[root@localhost ~]# yum -y install xmlto #安装rabbitmq的依赖包,否则编译不通过,报下面错误:
/bin/sh: line 1: xmlto: command not found
[root@localhost ~]# yum -y install zip unzip #安装zip和unzip命令,否则编译时候会报zip和unzip命令找不到,可能内部需要该命令解压.
[root@localhost ~]# ls /rabbitmq/
rabbitmq-server-3.1.5.tar.gz
[root@localhost ~]# cd /rabbitmq/
[root@localhost rabbitmq]# ls
rabbitmq-server-3.1.5.tar.gz
[root@localhost rabbitmq]# tar -zxf rabbitmq-server-3.1.5.tar.gz
[root@localhost rabbitmq]# ls
rabbitmq-server-3.1.5 rabbitmq-server-3.1.5.tar.gz
[root@localhost rabbitmq]# cd rabbitmq-server-3.1.5
[root@localhost rabbitmq-server-3.1.5]# ls
calculate-relative generate_app LICENSE-APACHE2-ExplorerCanvas LICENSE-MIT-EJS10 LICENSE-MIT-Sammy060 scripts
codegen generate_deps LICENSE-Apache-Basho LICENSE-MIT-eldap LICENSE-MPL-RabbitMQ src
codegen.py include LICENSE-APL2-Stomp-Websocket LICENSE-MIT-Flot Makefile version.mk
docs INSTALL LICENSE-BSD-base64js LICENSE-MIT-jQuery164 plugins-src
ebin LICENSE LICENSE-BSD-glMatrix LICENSE-MIT-Mochi README
[root@localhost rabbitmq-server-3.1.5]# make #直接编译
[root@localhost rabbitmq-server-3.1.5]# make install TARGET_DIR=/usr/local/rabbitmq SBIN_DIR=/usr/local/rabbitmq/sbin MAN_DIR=/usr/local/rabbitmq/man #安装rabbitmq
6) 安装web插件管理界面
[root@localhost rabbitmq-server-3.1.5]# cd /usr/local/rabbitmq/sbin/
[root@localhost sbin]# ls
rabbitmqctl rabbitmq-defaults rabbitmq-env rabbitmq-plugins rabbitmq-server
[root@localhost sbin]# mkdir /etc/rabbitmq #创建一个目录,管理界面软件默认会安装在此目录下,不创建则安装不了
[root@localhost sbin]# ./rabbitmq-plugins enable rabbitmq_management
The following plugins have been enabled:
mochiweb
webmachine
rabbitmq_web_dispatch
amqp_client
rabbitmq_management_agent
rabbitmq_management
Plugin configuration has changed. Restart RabbitMQ for changes to take effect.
查看插件列表:
[root@localhost sbin]# ./rabbitmq-plugins list
[e] amqp_client 3.1.5
[ ] cowboy 0.5.0-rmq3.1.5-git4b93c2d
[ ] eldap 3.1.5-gite309de4
[e] mochiweb 2.7.0-rmq3.1.5-git680dba8
[ ] rabbitmq_amqp1_0 3.1.5
……
7)启动rabbitmq (后台启动运行)
[root@localhost sbin]# ./rabbitmq-server --detached &
[1] 60071
[root@localhost sbin]#
RabbitMQ 3.1.5. Copyright (C) 2007-2013 GoPivotal, Inc.
## ## Licensed under the MPL. See http://www.rabbitmq.com/
## ##
########## Logs: /var/log/rabbitmq/[email protected]
###### ## /var/log/rabbitmq/[email protected]
##########
Starting broker... completed with 6 plugins.
[root@localhost sbin]# netstat -anput |grep 15672
tcp 0 0 0.0.0.0:15672 0.0.0.0:* LISTEN 60071/beam
注意:如果要用python操作rabbitmq,需要安装Python连接rabbitmq的模块:pika
用python3自带的pip3命令安装即可,安装过程如下:
[root@localhost sbin]# cd /usr/local/python3.5/bin
[root@localhost bin]# ./pip3 install pika
Collecting pika
Downloading pika-0.11.2-py2.py3-none-any.whl (107kB)
100% |████████████████████████████████| 110kB 931kB/s
Installing collected packages: pika
Successfully installed pika-0.11.2
You are using pip version 7.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
[root@localhost bin]# python3
>>> import pika 能导入即可
>>> quit()
客户端浏览器访问rabbitmq的管理页面:
使用登录的名户名和密码默认都算guest,登录管理页面,如图:
点击login,如图:
8)停止rabbitmq
[root@localhost sbin]# ./rabbitmqctl stop
Stopping and halting node rabbit@localhost ...
...done.
2.在服务器192.168.231.128上用python操作rabbitmq,实现一个简单的队列通信(生产者生产消息,消费者消费消息)
1)安装python3.5.0
[root@localhost ~]# python3 -V
Python 3.5.0
2)安装rabbitmq并运行,如上面
[root@localhost ~]# netstat -anput |grep 15672
tcp 0 0 0.0.0.0:15672 0.0.0.0:* LISTEN 60179/beam
3)安装python连接rabbitmq的模块pika (用python3自带的pip3命令安装)
[root@localhost ~]# cd /usr/local/python3.5/bin
[root@localhost bin]# ./pip3 install pika
Collecting pika
Downloading pika-0.11.2-py2.py3-none-any.whl (107kB)
100% |████████████████████████████████| 110kB 931kB/s
Installing collected packages: pika
Successfully installed pika-0.11.2
You are using pip version 7.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
[root@localhost bin]# python3
>>> import pika 能导入即可
>>> quit()
4)python连接rabbitmq并建立生产者生产消息,消费者消费消息的队列通信(队列和消息未持久化)
#当rabbitmq服务重启后,队列和消息会丢失
[root@localhost ~]# cat producer.py #生产者生产消息
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection( #通过创建一个实例建立一个socket
pika.ConnectionParameters('localhost') #python连接到本机的rabbitmq
)
channel = connection.channel() #声明一个管道,在管道里发消息
channel.queue_declare(queue='hello') #在管道里声明一个queue队列,队列名叫hello,也可其他的,生产消费两者都声明,避免不知哪个先启动时未声明 在hello后没加参数durable=True,队列不会持久化,重启会队列丢失
channel.basic_publish(exchange='', #通过管道的basic_publish命令向队列里发消息,exchange先不管
routing_key='hello', #要给哪个队列发消息,hello就是要给队列发消息的队列名
body='hello world!') #要给队列发送的消息内容,里面没加参数 properties=pika.BasicProperties(delivery_mode=2),消息也不持久化
print ("[x] send 'hello world!'")
connection.close() #发完消息后关闭队列,不用关闭管道
[root@localhost ~]# cat consumer.py #消费者消费消息
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.queue_declare(queue='hello') #从管道里,声明从哪个队列里收消息,hello是队列名,生产消费两者都声明,避免不知哪个先启动时未声明,在hello没加参数durable=True,队列不会持久化
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,不常用
print ('-->',ch,method,properties)
#ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动去跟服务器确认消息
print ('[x] Received %r' % body)
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue='hello', #从哪个队列里消费消息,hello是队列名
no_ack=True) #不确认,True时,消费者无论是否消费完消息,都不给服务器发确认.False是确认
#上面是声明开始消费消息,还没消费消息,一般不加no_ack=True,默认要确认,这样消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
print ('[*] waiting for messages, To exit press CTRL+C')
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
消费者消费消息先运行等待消费消息,如下:
[root@localhost ~]# python3 consumer.py
[*] waiting for messages, To exit press CTRL+C
……
生产者生产消息,运行,生产2条消息
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
查看消费者消费的消息
[root@localhost ~]# python3 consumer.py
[*] waiting for messages, To exit press CTRL+C
--> <BlockingChannel impl=<Channel number=1 OPEN conn=<SelectConnection OPEN socket=('::1', 48464, 0, 0)->('::1', 5672, 0, 0) params=<ConnectionParameters host=localhost port=5672 virtual_host=/ ssl=False>>>> <Basic.Deliver(['consumer_tag=ctag1.26fecdba11ed4c6e9b7089eeee1548ed', 'delivery_tag=1', 'exchange=', 'redelivered=False', 'routing_key=hello'])> <BasicProperties>
[x] Received b'hello world!'
--> <BlockingChannel impl=<Channel number=1 OPEN conn=<SelectConnection OPEN socket=('::1', 48464, 0, 0)->('::1', 5672, 0, 0) params=<ConnectionParameters host=localhost port=5672 virtual_host=/ ssl=False>>>> <Basic.Deliver(['consumer_tag=ctag1.26fecdba11ed4c6e9b7089eeee1548ed', 'delivery_tag=2', 'exchange=', 'redelivered=False', 'routing_key=hello'])> <BasicProperties>
[x] Received b'hello world!'
查看队列里的消息: #因为消费者消费完了,所以队列里无消息
root@localhost ~]# cd /usr/local/rabbitmq/sbin/
[root@localhost sbin]# ./rabbitmqctl list_queues
Listing queues ...
hello 0
...done.
消费者ctrl+c停止消费消息,让生产者生产3条消息,测试rabbitmq服务重启后,队列丢失(未持久化)
生产者生产3条消息:
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
查看队列里的消息,有几条(3条)
[root@localhost ~]# cd /usr/local/rabbitmq/sbin/
[root@localhost sbin]# ./rabbitmqctl list_queues
Listing queues ...
hello 3 #有3条未消费的消息
...done.
重启rabbitmq服务
[root@localhost sbin]# ./rabbitmqctl stop
[root@localhost sbin]# ./rabbitmq-server --detached &
[root@localhost sbin]# ./rabbitmqctl list_queues
Listing queues ...
...done. #发现队列名都丢失了,消息更丢失了,未持久化。
注意:上面是生产者和消费者是一对一关系,一个生产者对应一个消费者。
当一个生产者对应多个消费者时: 生产者和消费者代码都不变,消费者用多个终端执行,就表示了启动了多个消费者。
5)python连接rabbitmq并建立生成者生产消息,消费者消费消息和(队列和消息持久化)
两个步骤: #当rabbitmq服务重启后,队列和消息不丢失
1)在每个声明队列里都要加参数durable=True,但只是队列是持久化不能消息持久化。如:channel.queue_declare(queue='hello2',durable=True)
2)在生产者代码里的channel.basic_publish()中加下面参数:
properties=pika.BasicProperties(
delivery_mode=2) #消息持久化
例子演示:
[root@localhost ~]# cat producer.py #生产者生产消息
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection( #通过创建一个实例建立一个socket
pika.ConnectionParameters('localhost') #python连接到本机的rabbitmq
)
channel = connection.channel() #声明一个管道,在管道里发消息
channel.queue_declare(queue='hello2',durable=True) #在管道里声明一个queue队列,队列名叫hello,也可其他,生产消费两者都声明,避免不知哪个先启动时未声明,在hello后再加参数durable=True是队列持久化,消息不持久化
channel.basic_publish(exchange='', #通过管道的basic_publish命令向队列里发消息,exchange先不管
routing_key='hello2', #要给哪个队列发消息,hello就是要给队列发消息的队列名
body='hello world!', #要给队列发送的消息内容
properties=pika.BasicProperties(
delivery_mode=2 #消息持久化
)
)
print ("[x] send 'hello world!'")
connection.close() #发完消息后关闭队列,不用关闭管道
[root@localhost ~]# cat consumer.py #消费者消费消息
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.queue_declare(queue='hello2',durable=True) #从管道里,声明从哪个队列里收消息,hello是队列名,生产消费两者都声明,避免不知哪个先启动时未声明,在hello后再加参数durable=True是持久化,不加不会持久化
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,不常用
print ('-->',ch,method,properties)
ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动去跟服务器确认消息
print ('[x] Received %r' % body)
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue='hello2' #从哪个队列里消费消息,hello是队列名
) #一般不加no_ack=True,默认要确认,这样消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
print ('[*] waiting for messages, To exit press CTRL+C')
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
消费者先不启动,不消费消息,启动生产者生产2条消息:
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
[root@localhost ~]# python3 producer.py
[x] send 'hello world!'
[root@localhost sbin]# ./rabbitmqctl list_queues #查看各队列里有多少条消息
[root@localhost sbin]# ./rabbitmqctl list_queues
Listing queues ...
hello2 2 #队列里有两条消息
...done.
[root@localhost sbin]# ./rabbitmqctl stop #停止rabbitmq
[root@localhost sbin]# ./rabbitmq-server --detached & #启动rabbitmq
[root@localhost sbin]# ./rabbitmqctl list_queues #查看各队列里数据,队列不会消失,但消息是丢失了
Listing queues ...
hello2 2 #重启后队列和消息仍然存在
...done.
[root@localhost sbin]# cd
启动消费者消费消息:消费了这2条消息
[root@localhost sbin]# cd
[root@localhost ~]# python3 consumer.py
[*] waiting for messages, To exit press CTRL+C
--> <BlockingChannel impl=<Channel number=1 OPEN conn=<SelectConnection OPEN socket=('::1', 48460, 0, 0)->('::1', 5672, 0, 0) params=<ConnectionParameters host=localhost port=5672 virtual_host=/ ssl=False>>>> <Basic.Deliver(['consumer_tag=ctag1.939e6959a2594d29a1f5365ff2fba76a', 'delivery_tag=1', 'exchange=', 'redelivered=False', 'routing_key=hello2'])> <BasicProperties(['delivery_mode=2'])>
[x] Received b'hello world!'
--> <BlockingChannel impl=<Channel number=1 OPEN conn=<SelectConnection OPEN socket=('::1', 48460, 0, 0)->('::1', 5672, 0, 0) params=<ConnectionParameters host=localhost port=5672 virtual_host=/ ssl=False>>>> <Basic.Deliver(['consumer_tag=ctag1.939e6959a2594d29a1f5365ff2fba76a', 'delivery_tag=2', 'exchange=', 'redelivered=False', 'routing_key=hello2'])> <BasicProperties(['delivery_mode=2'])>
[x] Received b'hello world!'
再启动一个终端查看队列里的消息
[root@localhost ~]# cd /usr/local/rabbitmq/sbin/
[root@localhost sbin]# ./rabbitmqctl list_queues
Listing queues ...
hello2 0
...done.
注意:上面是生产者和消费者是一对一关系,一个生产者对应一个消费者。
当一个生产者对应多个消费者时: 生产者和消费者代码都不变,消费者用多个终端执行,就表示了启动了多个消费者。
3.rabbitmq的生产者自动根据消费者消息快慢(处理能力)自动分配不同量的任务(上面的4)和5)都适用)(持久性)
上面4)或5)的生产者代码都不用变,只需在4)或5)的消费者代码channel.basic_consume(…)的上边添加一条:
channel.basic_qos(prefetch_count=1)即可,表示:让生产者知道,你等我消费完这一条再给我发下一条,相当于权重设置。
例子:
[root@localhost ~]# cat producer.py #生产者生产消息
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection( #通过创建一个实例建立一个socket
pika.ConnectionParameters('localhost') #python连接到本机的rabbitmq
)
channel = connection.channel() #声明一个管道,在管道里发消息
channel.queue_declare(queue='hello2',durable=True) #在管道里声明一个queue队列,队列名叫hello,也可其他,生产消费两者都声明,避免不知哪个先启动时未声明,在hello后再加参数durable=True是队列持久化,消息不持久化
channel.basic_publish(exchange='', #通过管道的basic_publish命令向队列里发消息,exchange先不管
routing_key='hello2', #要给哪个队列发消息,hello就是要给队列发消息的队列名
body='hello world!', #要给队列发送的消息内容
properties=pika.BasicProperties(
delivery_mode=2 #消息持久化
)
)
print ("[x] send 'hello world!'")
connection.close() #发完消息后关闭队列,不用关闭管道
[root@localhost ~]# cat consumer.py #消费者消费消息(处理快的,没加sleep)
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.queue_declare(queue='hello2',durable=True) #从管道里,声明从哪个队列里收消息,hello是队列名,生产消费两者都声明,避免不知哪个先启动时未声明,在hello后再加参数durable=True是持久化,不加不会持久化
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,不常用
print ('-->',ch,method,properties)
ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动跟服务器确认消息
print ('[x] Received %r' % body)
channel.basic_qos(prefetch_count=1) #添加此内容是:让生产者知道,你等我消费完这一条再给我发下一条,相当于权重设置
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue='hello2' #从哪个队列里消费消息,hello是队列名
) #一般不加no_ack=True,默认确认,消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
print ('[*] waiting for messages, To exit press CTRL+C')
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
[root@localhost ~]# cat consumer2.py #消费者消费消息(处理慢的,加了sleep)
#!/usr/bin/env python3
import pika
import time
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.queue_declare(queue='hello2',durable=True) #从管道里,声明从哪个队列里收消息,hello是队列名,生产消费两者都声明,避免不知哪个先启动时未声明,在hello后再加参数durable=True是持久化,不加不会持久化
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,不常用
print ('-->',ch,method,properties)
time.sleep(50) #睡觉50s,模拟处理消息慢,机器老
ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动跟服务器确认消息
print ('[x] Received %r' % body)
channel.basic_qos(prefetch_count=1) #添加此内容是:让生产者知道,你等我消费完这一条再给我发下一条,相当于权重设置
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue='hello2' #从哪个队列里消费消息,hello是队列名
) #一般不加no_ack=True,默认确认,消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
print ('[*] waiting for messages, To exit press CTRL+C')
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
[root@localhost ~]# python3 consumer.py #启动消费者1消费消息(消费快的)
[*] waiting for messages, To exit press CTRL+C
……
[root@localhost ~]# python3 consumer2.py #启动消费者2消费消息(消费慢的)
[*] waiting for messages, To exit press CTRL+C
……
[root@localhost ~]# python3 producer.py #生产者生产消息
[x] send 'hello world!'
此处说明一下:生产者先生产消息,默认会轮询给两个消费者发消息,让消费者消费消息,但是,消费者的处理能力不同,消费者快的就多处理几条,消费者处理慢的,还没有处理完成时候,生产者就不会给该消费者发。
4.rabbitmq中生产者和消费者的队列两个机制:
1)生产者和消费者的队列轮询机制:
当生产者生产了数据时,发给多个消费者时候,默认是轮询的,发第一条数据会给第一个最先启动的消费者,生成第2条消息时候,会轮询到下一个消费者消费,依次类推。
2)生产者和消费者队列的确认机制:
默认情况下,生产者给消费者发消息,消费者消费消息后,会跟服务器确认是否消费了消息,消费者代码中一般不加参数:no_ack=True(表示不确认),即使加参数也是为False,表示:消费者只有消费完消息后跟服务器缺认后,才让服务器从队列里删除该消息,否则如果没有确认已经消费了消息就删除消息,可能会丢失消息,这样的机制能保证消息不丢失。
5.rabbitmq中消息队列的持久化设置 (在每次声明消息队列时候(每个队列都要加),加参数:durable=True)
两个步骤:
1)在每个声明队列里都要加参数durable=True,但只是队列是持久化不能消息持久化。如:channel.queue_declare(queue='hello2',durable=True)
2)在生产者代码里的channel.basic_publish()括号中除了之前的参数,再添加下面参数:
properties=pika.BasicProperties(
delivery_mode=2) #消息持久化
6.rabbitmq的广播方式发消息(fanout模式)
场景:类似于收音机收听广播,一个广播,多个接收.
[root@localhost ~]# cat producer.py #生产者生产消息
#!/usr/bin/env python3
import pika
import sys
connection = pika.BlockingConnection( #通过创建一个实例建立一个socket
pika.ConnectionParameters('localhost') #python连接到本机的rabbitmq
)
channel = connection.channel() #声明一个管道,在管道里发消息
channel.exchange_declare('logs','fanout') #logs是随便起的一个名字,后面定义广播类型
message = ''.join(sys.argv[1:]) or 'info: hello world'
channel.basic_publish(exchange='logs', #通过管道的basic_publish命令向队列里发消息,exchange先不管
routing_key='', #不写队列名,前面也没声明队列,因为是广播,是给所有队列发
body=message #要给队列发送的消息内容
)
print ("[x] send %r" % message)
connection.close() #发完消息后关闭队列,不用关闭管道
[root@localhost ~]# cat consumer.py #消费者消费消息
#!/usr/bin/env python3
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.exchange_declare('logs','fanout') #定义广播类型
result = channel.queue_declare(exclusive=True) #不指定队列名字,rabbit会随机分配一个名字,exclusive=True会在使用此队列的消费者断开后,自动将队列删除
queue_name = result.method.queue #获取随机分配的队列名
print ('random queuename',queue_name)
channel.queue_bind(exchange='logs',queue=queue_name) #绑定到转发器上,只收该转发器消息:logs,转发器会转到相应队列里,所以还需绑定队列名
print ('[*] waiting for messages, To exit press CTRL+C')
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,收到消息后通过该函数处理
ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动去跟服务器确认消息
print ('[x] %r' % body)
channel.basic_qos(prefetch_count=1) #添加此内容是:让生产者知道,你等我消费完这一条再给我发下一条,相当于权重设置
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue=queue_name #从哪个队列里消费消息,是随机分配的队列名
) #一般不加no_ack=True,默认要确认,这样消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
开启3个终端运行消费者代码,让消费者消费消息:
[root@localhost ~]# python3 consumer.py
random queuename amq.gen-q2upwaJLwMtxNEqD7iZ_eQ
[*] waiting for messages, To exit press CTRL+C
……
[root@localhost ~]# python3 consumer.py
random queuename amq.gen-519fqCe-Tx9sU--xTss5xw
[*] waiting for messages, To exit press CTRL+C
……
[root@localhost ~]# python3 consumer.py
random queuename amq.gen-BjmlqcjlG5vxEZMzuNxckQ
[*] waiting for messages, To exit press CTRL+C
……
运行生产者代码,生产者生产2条消息:(广播方式)
[root@localhost ~]# python3 producer.py
[x] send 'info: hello world'
[root@localhost ~]# python3 producer.py
[x] send 'info: hello world'
查看3个终端各个消费者消费的消息,3个终端都接收了2条消息消费了
[root@localhost ~]# python3 consumer.py
random queuename amq.gen-q2upwaJLwMtxNEqD7iZ_eQ
[*] waiting for messages, To exit press CTRL+C
[x] b'info: hello world'
[x] b'info: hello world'
[root@localhost ~]# python3 consumer.py
random queuename amq.gen-519fqCe-Tx9sU--xTss5xw
[*] waiting for messages, To exit press CTRL+C
[x] b'info: hello world'
[x] b'info: hello world'
[root@localhost ~]# python3 consumer.py
random queuename amq.gen-BjmlqcjlG5vxEZMzuNxckQ
[*] waiting for messages, To exit press CTRL+C
[x] b'info: hello world'
[x] b'info: hello world'
7.rabbitmq的广播过滤方式发消息(direct模式)
生产者生产各种类型的消息和内容,消费者根据类型进行收取消息(过滤不细致)
[root@localhost ~]# cat producer.py #生产者生产消息
#!/usr/bin/env python3
import pika
import sys
connection = pika.BlockingConnection( #通过创建一个实例建立一个socket
pika.ConnectionParameters('localhost') #python连接到本机的rabbitmq
)
channel = connection.channel() #声明一个管道,在管道里发消息
channel.exchange_declare('direct_logs','direct') #direct_logs是随便起的一个名字,定义广播类型,带过滤的广播
severity = sys.argv[1] if len(sys.argv) > 1 else 'info' #位置1自定义要过滤消息的类型,手动传递参数,若没传,就是只接收info类型的消息
message = ' '.join(sys.argv[2:]) or 'hello world' #位置2定义该消息类型下的消息内容
channel.basic_publish(exchange='direct_logs', #通过管道的basic_publish命令向队列里发消息,exchange先不管
routing_key=severity, #不写队列名,前面也没声明队列,因为是广播的过滤,是给所有队列发
body=message #要给队列发送的消息内容
)
print ("[x] send %r:%r" % (severity,message))
connection.close() #发完消息后关闭队列,不用关闭管道
[root@localhost ~]# cat consumer.py #消费者消费消息
#!/usr/bin/env python3
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.exchange_declare('direct_logs','direct') #定义广播类型,是广播的过滤
result = channel.queue_declare(exclusive=True) #不指定队列名字,rabbit会随机分配一个名字,exclusive=True会在使用此队列的消费者断开后,自动将队列删除
queue_name = result.method.queue #获取随机分配的队列名
print ('random queuename',queue_name)
severities = sys.argv[1:] #获取用户位置参数传递的要过滤的条件,收什么类型的消息
if not severities: #若用户没有在位置参数设置过滤条件,就报错并退出
sys.stderr.write('Usage: %s [info] [warning] [error]\n' % sys.argv[0])
sys.exit(1)
for severity in severities: #循环绑定用户设置的过滤条件参数,所有发到severity参数的消息我都接收,实现过滤
channel.queue_bind(exchange='direct_logs',queue=queue_name,routing_key=severity) #绑定到转发器上,只收过滤条件消息
print ('[*] waiting for messages, To exit press CTRL+C')
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,不常用
ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动去跟服务器确认消息
print ('[x] %r:%r' % (method.routing_key,body))
channel.basic_qos(prefetch_count=1) #添加此内容是:让生产者知道,你等我消费完这一条再给我发下一条,相当于权重设置
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue=queue_name #从哪个队列里消费消息,随机获取的队列名
) #一般不加no_ack=True,默认要确认,这样消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
各类消费者根据消息类型,收取不同的消息内容:
[root@localhost ~]# python3 consumer.py info #消费者1仅收取info内容的消息
random queuename amq.gen-raLh9PEIVYaLGKYWLj8Tig
[*] waiting for messages, To exit press CTRL+C
[root@localhost ~]# python3 consumer.py error #消费者2仅收取error内容的消息
random queuename amq.gen-AnCJ50AX--AlmJnsqWzpvw
[*] waiting for messages, To exit press CTRL+C
[root@localhost ~]# python3 consumer.py info error #消费者3收取info和error内容的消息
random queuename amq.gen-kCyvuVapsjDIebC3nmd9eg
[*] waiting for messages, To exit press CTRL+C
[root@localhost ~]# python3 consumer.py warning #消费者4仅收取warning内容的消息
random queuename amq.gen-wTkdfpdv2VF1qBhXYOtaTA
[*] waiting for messages, To exit press CTRL+C
生产者发送各种类型的消息类型和消息内容:
[root@localhost ~]# python3 producer.py info content1 #发送info类型的消息,内容是:content1
[x] send 'info':'content1'
[root@localhost ~]# python3 producer.py error content_2 #发送error类型的消息,内容是:content_2
[x] send 'error':'content_2'
[root@localhost ~]# python3 producer.py warning content_3 #发送warning类型的消息,内容是:content_3
[x] send 'warning':'content_3'
各不同类型消费者的收取消费者情况:
[root@localhost ~]# python3 consumer.py info #消费者1仅收取info内容的消息
random queuename amq.gen-raLh9PEIVYaLGKYWLj8Tig
[*] waiting for messages, To exit press CTRL+C
[x] 'info':b'content1'
[root@localhost ~]# python3 consumer.py error #消费者2仅收取error内容的消息
random queuename amq.gen-AnCJ50AX--AlmJnsqWzpvw
[*] waiting for messages, To exit press CTRL+C
[x] 'error':b'content_2'
[root@localhost ~]# python3 consumer.py info error #消费者3收取info和error内容的消息
random queuename amq.gen-kCyvuVapsjDIebC3nmd9eg
[*] waiting for messages, To exit press CTRL+C
[x] 'info':b'content1'
[x] 'error':b'content_2'
[root@localhost ~]# python3 consumer.py warning #消费者4仅收取warning内容的消息
random queuename amq.gen-wTkdfpdv2VF1qBhXYOtaTA
[*] waiting for messages, To exit press CTRL+C
[x] 'warning':b'content_3'
7.rabbitmq的广播细致过滤方式发消息(topic模式)
生产者生产各种类型的消息和内容,消费者根据类型进行收取消息(过滤细致)
[root@localhost ~]# cat producer.py #生产者生产消息
#!/usr/bin/env python3
import pika
import sys
connection = pika.BlockingConnection( #通过创建一个实例建立一个socket
pika.ConnectionParameters('localhost') #python连接到本机的rabbitmq
)
channel = connection.channel() #声明一个管道,在管道里发消息
channel.exchange_declare('topic_logs','topic') #topic_logs是随便起的一个名字,定义广播类型,细致过滤
routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info' #位置1自定义要过滤消息的类型,手动传递参数,若没传,就是只接收anonymous.info类型的消息
message = ' '.join(sys.argv[2:]) or 'hello world' #位置2定义该消息类型下的消息内容
channel.basic_publish(exchange='topic_logs', #通过管道的basic_publish命令向队列里发消息,exchange先不管
routing_key=routing_key, #不写队列名,前面也没声明队列,因为是广播的过滤,是给所有队列发
body=message #要给队列发送的消息内容
)
print ("[x] send %r:%r" % (routing_key,message))
connection.close() #发完消息后关闭队列,不用关闭管道
[root@localhost ~]# cat consumer.py #消费者消费消息
#!/usr/bin/env python3
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) #创建一个实例建立一个socekt连接
channel = connection.channel() #建立一个管道
channel.exchange_declare('topic_logs','topic') #定义广播类型,是广播的细致过滤
result = channel.queue_declare(exclusive=True) #不指定队列名字,rabbit会随机分配一个名字,exclusive=True会在使用此队列的消费者断开后,自动将队列删除
queue_name = result.method.queue #获取随机分配的队列名
print ('random queuename',queue_name)
binding_keys = sys.argv[1:] #获取用户位置参数传递的要过滤的条件,过滤的消息类型
if not binding_keys: #若用户没有在位置参数设置过滤条件,就报错并退出
sys.stderr.write('Usage: %s [binding_key]...\n' % sys.argv[0])
sys.exit(1)
for binding_key in binding_keys: #循环绑定用户设置过滤条件参数,所有发到severity参数的消息我都接收,实现过滤
channel.queue_bind(exchange='topic_logs',queue=queue_name,routing_key=binding_key) #绑定到转发器上,只收过滤条件消息
print ('[*] waiting for messages, To exit press CTRL+C')
def callback(ch,method,properties,body): #ch指管道的内存对象,后面几个可以不知道,不常用
ch.basic_ack(delivery_tag=method.delivery_tag) #默认不加下面的no_ack=True,需释放这个,手动去跟服务器确认消息
print ('[x] %r:%r' % (method.routing_key,body))
channel.basic_qos(prefetch_count=1) #添加此内容是:让生产者知道,你等我消费完这一条再给我发下一条,相当于权重设置
channel.basic_consume( #通过管道的basic_consume方法消费消息
callback, #若果收到消息,就调用callback函数来处理消息
queue=queue_name #从哪个队列里消费消息,hello是队列名
) #一般不加no_ack=True,默认要确认,这样消费者只有消费完消息后跟服务器缺认后,保证消息不丢失
channel.start_consuming() #这里才是真正消费消息,只要启动就一直运行了,不只消费一条,一直在消费
各类消费者根据消息类型细致过滤,收取不同的消息内容:
[root@localhost ~]# python3 consumer.py *.info #消费者1仅收取以info结尾类型的消息
random queuename amq.gen-fbvaYf-zB0sQaU2_hflTfQ
[*] waiting for messages, To exit press CTRL+C
[root@localhost ~]# python3 consumer.py *.error mysql.* #消费者2收取以error结尾和以mysql开头类型的消息
random queuename amq.gen-6ivXWiP1DToTkh0KqxRGWg
[*] waiting for messages, To exit press CTRL+C
[root@localhost ~]# python3 producer.py
[x] send 'anonymous.info':'hello world'
生产者生产各类型的消息和内容:
[root@localhost ~]# python3 producer.py #生产的消息类型:info,内容是:hello world,不传参数时默认
[x] send 'anonymous.info':'hello world'
[root@localhost ~]# python3 producer.py *.error error_message #生产的消息类型:*.info,内容是: error_message
[x] send '*.error':'error_message'
[root@localhost ~]# python3 producer.py mysql.* mysql__message #生产的消息类型:mysql.*,内容是: mysql_message
[x] send 'mysql.*':'mysql__message'
查看各类消费者收到的消息:
[root@localhost ~]# python3 consumer.py *.info #消费者1仅收取以info结尾类型的消息
random queuename amq.gen-3KE-xS917CV-x1RhCVolMg
[*] waiting for messages, To exit press CTRL+C
[x] 'anonymous.info':b'hello world'
[root@localhost ~]# python3 consumer.py *.error mysql.* #消费者2收取以error结尾和以mysql开头类型的消息
random queuename amq.gen-bcW0w9u3ymGD8kQH-xyDDg
[*] waiting for messages, To exit press CTRL+C
[x] '*.error':b'error_message'
[x] 'mysql.*':b'mysql__message'
如果对运维课程感兴趣,可以在b站上、A站或csdn上搜索我的账号: 运维实战课程,可以关注我,学习更多免费的运维实战技术视频