本文主要演示Windows下的,CentOS也提一下安装。
简介
RabbitMQ
是一个异步的消息队列服务器程序,基于AMQP
协议实现。客户端Client
逻辑上分为消息生产者Producer
和消费者Consumer
,Producer
生产消息Message
到服务器Server
,排成消息队列Queue
,Consumer
消费Message
,一些细节策略都是可以控制的。
安装
Windows下安装
首先去RabbitMQ官网下载并安装服务器,不过这之前先去Erlang官网安装Erlang/OTP支持。本文选择了otp_win64_22.0.exe
和rabbitmq-server-3.7.17.exe
。安装完毕,可以直接从开始菜单启动服务,一个简单的消息服务器Node
就启动了。
如图所示,开始菜单有很多链接,命令提示符、启动、关闭等。通过命令提示符下输入命令,可以进行很多操作,如查看状态:
rabbitmqctl.bat status
以及关机:
rabbitmqctl.bat stop
CentOS下安装
这个很烦人。官网绕来绕去真让人头大。它先说有两种方法可以安装RabbitMQ
:
- 第一种,通过
Yum
安装(推荐)。这种方法又分两小种,一种使用PackageCloud,一种使用Bintray。先看第一小种,噩梦的开始,我就没见过比这还垃圾的安装说明,这个脚本那个指示的,绕来绕去的啥也没干成。再看第二小种,链接打开就很缓慢。算了,或者这就是大佬吧。这种简单的方法,我放弃! - 第二种,下载
rpm
安装包,但是需要手动安装一些支持包,比如erlang
,socat
,logrotate
。先装erlang
,一开始就懵逼了:
下面明明4个选项,为啥是3个?不管了,试试第一个。他先说风凉话:RabbitMQ团队搞了个包,只包含RabbitMQ需要的组件,如果按照Erlang依赖被证明比较困难,这可能是最简单的方式。行吧,点进去一个erlang的github,一点指示都没有,怎么简单了?我只看到一个命令yum install erlang
,难道是它?(读者先别装!)这么简单,那让我点进来干什么?直接告诉我不就完了。不管了,装完了,erl
测试没问题,应该是装上了吧,只不过版本是R16B03-1
,版本很旧,这是后话。
[root@master ~]# erl
Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.4 (abort with ^G)
1>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
继续,到哪来着?还要装socat
,简单。
yum -y install socat
还有logrotate
,发现已经装了。
好了,所谓的手动依赖都装完了,该是下载安装
rpm
了,点击跳转到下载处,发现这个。
它说某些情况,下载安装包手动安装可能更简单。吐血三升!先推荐第一种,这会儿又说第二种可能还行,行了,所有的安装方法都比较简单,听你的。不管了,下载吧。
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.18/rabbitmq-server-3.7.18-1.el7.noarch.rpm
耐心下载完毕。结果安装失败,说erlang的版本不对。
奇怪,按照github的说明,应该默认就是最新版本的。没办法,于是去github的release里下载了一个版本:
继续安装:
yum -y install erlang-22.1-1.el7.x86_64.rpm
报错冲突,也算是意料之中。
搜了下,最方便的方法就是指定卸载老版本,必须特别精准,否则删不干净。至于怎么找到这个名称,我也没想出来,多组合试试吧。
yum remove erlang-erts-R16B-03.18.el7.x86_64
然后重新安装新版本。
yum -y install erlang-22.1-1.el7.x86_64.rpm
继续安装rabbitMQ:
yum -y install rabbitmq-server-3.7.18-1.el7.noarch.rpm
搞定!添加开机启动、启动、查看状态,素质三连。
systemctl enable rabbitmq-server.service
systemctl start rabbitmq-server.service
systemctl status rabbitmq-server.service
查看下当前用户:
[root@master ~]# rabbitmqctl list_users
Listing users ...
user tags
guest [administrator]
添加个用户,并设为管理员(添加标签即可)。
[root@master ~]# rabbitmqctl add_user admin admin
Adding user "admin" ...
[root@master ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator] ...
[root@master ~]# rabbitmqctl list_users
Listing users ...
user tags
admin [administrator]
guest [administrator]
配置vhost '/'下的权限,并查看权限:
rabbitmqctl set_permissions -p '/' admin '.*' '.*' '.*'
rabbitmqctl list_permissions
其实这些,都可以去后台管理配置。打开后台管理:
rabbitmq-plugins enable rabbitmq_management
然后就可以去ip:15672
访问管理,记住把云服务的安全组规则配置好,如果有iptables
这样的防火墙,也要把端口打开。
好了,CentOS就说这么多吧,总结就是:
- 去github下载新版本的erlang,yum安装
- 安装socat,logrotate
- 下载RabbitMQ并安装。
差评官网安装指南。
管理
在命令提示符下,启用管理插件:
rabbitmq-plugins enable rabbitmq_management
浏览器输入http://localhost:15672/
即可访问后台管理页面,默认可以使用guest/guest
登录(guest
只能在localhost
登录),这是管理员权限,建议删掉这个用户或者至少在管理页面改个密码。具体步骤是在Admin
分页添加一个新的用户,输入信息,赋予admin
权限标签,然后点击这个用户,在permission
栏把访问虚拟主机/
的权限给加上,然后就可以删除掉原先的guest
了。
如下命令可查看用户列表及权限:
rabbitmqctl.bat list_users
试用
服务器可以只有一个节点Node
(或叫代理Broker
),也可以是集群,本文使用单节点。另外,服务器至少有一个虚拟主机Virtual Host
,这是一个逻辑概念,可以添加Virtual Host
用于不同后台用户的权限控制(待研究),本文仅使用/
这一个Virtual Host
,跟服务器概念基本等价。
Virtual Host
下可以有多个交换机Exchange
和消息队列Queue
,每个Queue
可以添加一个或多个Binding
路由规则将其绑定到Exchange
上。Binding
根据Exchange
的Type
,以及路由键Routing Key
来决定消息从Exchange
传到哪个Queue
。
概念有点多,试一下流程:
- 在
Exchanges
分页新建交换机test_ex
,类型Type
是direct
,意思是路由键必须完全相同,才会将消息转到符合规则的Queue
。另外还有比如分发fanout
类型,忽视路由键,只要绑定就转发到队列;主题topic
模型,支持通配符(#、*)匹配路由键,很方便。可以使用如下命令查看交换机:
rabbitmqctl.bat list_exchanges
- 在
Queues
分页新建一个队列test_queue
,建完后点击该队列,继续添加一条binding
规则,与test_ex
以路由键test.msg
绑定在一起。注意:建立交换机或队列的时候,都有个Durability
选项,这个是选择是否持久化,也就是重启后还在不在,binding
只能在持久化属性相同的通道和队列之间绑定。可以使用如下命令查看绑定规则:
rabbitmqctl.bat list_bindings
-
回到
Exchanges
分页,点击test_ex
在Publish message
栏输入并发布一条消息Hello World!
。Deliver mode
用来控制消息是否持久化,为了速度,一般不持久化消息。
-
回到
Queues
分页,点击test_queue
,然后获取消息,成功!
Python
首先安装pika
模块:
pip install pika
写一个消息生产客户端producer.py
,代码如下:
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
'localhost',
credentials=pika.credentials.PlainCredentials('admin', 'yourpassword'))) # 建立连接,默认是guest:guest可省略,由于之前guest被删掉了,所以必须给出参数
channel = connection.channel() # 初始化通道
channel.exchange_declare(
'test_ex',
durable=True) # 如果没有,则新建交换机;如果已有,则忽略,但参数要一致
channel.basic_publish(
exchange='test_ex',
routing_key='test.msg',
body='Hello World from Python!') # 发布消息,如果不指定交换机,就会使用默认交换机,不建议这样
channel.close() # 好像可以省略
connection.close()
这时已经可以再管理后台获取消息了,如图:
当然也可以写一个消息接收端consumer.py
,代码如下:
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
'localhost',
credentials=pika.credentials.PlainCredentials('admin', 'admin'))) # 建立连接,默认是guest:guest可省略,由于之前guest被删掉了,所以必须给出参数
channel = connection.channel() # 初始化通道
# 以下可在管理后台操作
channel.exchange_declare(
'test_ex',
durable=True)
channel.queue_declare(
'test_queue',
durable=True)
channel.queue_bind(
queue='test_queue',
exchange='test_ex',
routing_key='test.msg')
# 接受消息回调函数
def callback(ch, method, properties, body):
print(f'Received {body}')
channel.basic_consume(queue='test_queue', on_message_callback=callback)
print('Consuming...')
channel.start_consuming()
确认消息
发现上述代码在收到消息后,并不会删除消息,类似管理后台的requeue true
,也就是消息在接收后,又原路放回去了。
注意,
requeue
的消息在下次被接受,会有一个redelivered
标志位值为真,在管理后台也能看出来:
那怎么在接受消息就删除呢?修改参数
auto_ack
即可:
channel.basic_consume(
queue='test_queue',
on_message_callback=callback,
auto_ack=True)
还使用basic_get()
主动获取排在第一的消息,并自动或手动发送ack
确认消息收到。
# 有消息就返回(method, properties, body),否则(None, None, None)
# 自动发送ack
msg = channel.basic_get('test_queue', True)
# 手动发送ack,从msg的method获取delivery_tag
msg = channel.basic_get('test_queue')
channel.basic_ack(msg[0].delivery_tag)
另外,可以通过设置服务质量QoS
来防止接收端积压消息,代码如下:
channel.basic_qos(prefetch_count=1)
channel.basic_consume(
queue='test_queue',
on_message_callback=callback)
这样,客户端每次只预取1个消息,如果不发送ack
,服务端是不会继续派发消息的。
够用了。