一、消息队列简介
1.主流的消息队列
目前主流的几大消息队列有:RabitMQ、ActiveMQ、RocketMQ、Kafka、ZeroMQ 等也有一些小众的比如 Beanstalk,当然我们之前学过的 Redis 也可以实现消息队列的功能
(1)ActiveMQ
基于 JAVA 语言开发,其社区算是比较成熟,但是目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用。
(2)RocketMQ
阿里出品,Java 系开源项目,源代码我们可以直接阅读,然后可以定制自己公司的 MO.并且 RocketMq 有阿里巴巴的实际业务场景的实战考验。RocketMQ 社区活跃度相对较为般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用 RocketMq 挺好的
(3)Kafka
由 Scala 和 Java 编写,其特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。Kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。
(4)RabbitMo
在吞吐量方面虽然稍逊于 Kafka 和 RocketMq ,但是由于它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。但是也因为RabbitMQ基于 erlang
开发,所以国内很少有公司有实力做erlang 源码级别的研究和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMo 一定是你的首选如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范
(5)ZeroMo
只是一个网络编程的 Pattern库,将常见的网络请求形式(分组管理,链接管理,发布订阅等)模式化、组件化,简而言之 socket 之上、MQ之下。对于 MQ 来说,网络传输只是它的一部分,更多需要处理的是消息存储、路由、Broker 服务发现和查找、事务、消费模式(ack、重投等)、集群服务等。
2.各种不同消息队列的对比
- (1)RabbitMQ/Kafka/zeroMo 都能提供消息队列服务,但有很大的区别。
- (2)在面向服务架构中通过消息代理(比如 RabbitMQ / Kafka 等),使用生产者/消费者模式在服务间进行异步通信是一种比较好的思想。
- (3)ZeroMo 和 RabbitMo/Kafka 不同,它只是一个异步消息库,在套接字的基础上提供了类似于消息代理的机制。使用 ZeroMQ 的话,需要对自己的业务代码进行改造,不利于服务解耦。
- (4)RabbitMQ 支持 AMQP(二进制),STOMP(文本),MOTT(二进制),HTTP(里面包装其他协议)等协议。而 Kafka 使用自己的协议。
- (5)Kafka 自身服务和消费者都需要依赖 Zookeeper。
- (6)RabbitMQ 在有大量消息堆积的情况下性能会下降,Kafka 不会,毕竟 AMQP 设计的初衷不是用来持久化海量消息的,而Kafka一开始是用来处理海量日志的。
总的来说,RabbitMQ 和 Kafka 都是十分优秀的分布式的消息代理服务,只要合理部署不作,基本上可以满足生产条件下的任何需求。
3.消息队列中角色/名词
(1)Broker:
消息服务器,作为server 提供消息核心服务
(2)Producer:
消息生产者,业务的发起方,负责生产消息传输给broker
(3)Consumer:
消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理
(4)Topic:
主题,发布订阅模式下的消息统一汇集地,不同生产者向 topic 发送消息,由 MO 服务器分发到不同的订阅者,实现消息的广播
(5)0ueue:
队列,PTP 模式下,特定生产者向特定 queue 发送消息,消费者订阅特定的 queue 完成指定消息的接收
(6)Message:
消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输
4.消息队列中两种工作模式
(1)Point-to-Point
其实就是点对点,其过程理解起来比较简单。它好比是两个人打电话,这两个人是独享
这一条通信链路的。一方发送消息,另外一方接收,就这么简单。在点对点模式下,消息被保留在队列中。-一个或多个消费者可以消耗队列中的消息,但是特定消息只能由最多一个消费者消费。 一旦消费者读取队列中的消息,它就从该队列中消失。 该模式的典型示例,如订单处理系统,其中每个订单将由一个订单处理器处理,但多个订单处理器也可以同时工作。
(2)Pub/sub
即发布/订阅模式,该模式有点类似于我们日常生活中订阅报纸。对于每一个订阅者来说,可以选择一份或者多份报纸。那么这些我们订阅的报纸,就相当于发布订阅模式里的topic。有很多个人订阅报纸,也有人可能和我订阅了相同的报纸。多人订阅了相同的报纸相当于多人在同一个 topic里注册了。对于一份报纸发行方来说,它和所有的订阅者就构成了一个1对多的关系。在这种模式下,消息被保留在主题中。 与点对点模式不同,消费者可以订阅一个或多个主题并使用该主题中的所有消息。该模式下消息生产者称为发布者,消息使用者称为订阅者。
5.消息队列缺点
由于消息队列的异步特性,直接提升了整个架构的处理效率,提升了用户体验。但凡事都有两面性,消息队列在带来性能提升的同时也伴随着缺陷。
(1)系统可用性降低
毕竟在整个架构中,我们单独加了一个消息队列中间件,所以增加了风险,如果消息队列服务挂掉,势必会影响到整个架构。
(2)系统复杂性提高
本来非常简单的一个逻辑设计,但偏偏要在中间插入一个消息队列,所以这增加了程序员的工作量,需要考虑如何保证消息没有被重复消费、消息有没有丢失、消息顺序等细节问题。
(3)数据一致性无法保证
消息如果没有正确写入到消息队列里,或者说读取消息的服务并没有正确读取到消息,这都会影响到数据的一致性。
二、RabbitMo 介绍
RabbitMq 是一款在全球范围内使用非常广泛的开源消息队列中间件。它轻量级、易部署、并支持多种协议。它基于 Erlang 开发,天生拥有高并发的能力。
1.RabbitMo 相关术语
(1)生产者
产生消息的进程或服务
(2)消费者
接收消息的进程或服务
(3)队列
RabbitMo 是消息队列中间件,而真正储存消息数据的就是队列,队列可以有很多。
(4)交换器
类似于网络设备交换机,它可以根据不同的关键字,将消息发送到不同的队列。
(5)虚拟主机
虚拟主机类似于 Apache 的虚拟主机,如果没有虚拟主机,当 RabbitMo 中的数据越来越庞大,队列越来越多,随之而来的是令人头痛的管理问题,比如队列、交换器命名冲突,它们相互影响等等。虚拟主机能够解决这些问题,而不需要我们部署多个 RabbitMQ 来负责不同的业务。
虚拟主机提供了资源的逻辑分组和分隔,每一个虚拟主机本质上是mini版的RabbitMQ服务器,他们有用自己的连接、队列、绑定、交换器,更重要的是有用自己的权限机制,这有点类似服务器和运行在服务器上的虚拟机一样。
三、CentOS7下安装RabbitMQ(单机)
1.安装erlang
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# setenforce 0
RabbitMQ服务器是用Erlang语言编写的
rm -rf /etc/yum.repos.d/*
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
yum clean all
yum install -y erlang
2.安装RabbitMQ
[root@localhost ~]# yum install -y rabbitmq-server
3.启动RabbitMQ
[root@localhost ~]# systemctl start rabbitmq-server
[root@localhost ~]# ps aux |grep rabbit ## 查看rabbit进程
[root@localhost ~]# netstat -lntp ## 查看监听端口
4.开启web管理控制台
[root@localhost ~]# rabbitmq-plugins enable rabbitmq_management
##激活插件
[root@localhost ~]# rabbitmq-plugins list
## 查看所有插件
此时可以通过 http://ip:15672 来访问rabbitmq的web管理控制台,用户名密码都是guest,但是有个限制,只允许127.0.0.1访问,所以还需在本机配置一个nginx代理
5.Nginx代理
[root@localhost ~]# yum install -y nginx ##安装nginx
vim /etc/nginx/conf.d/rabbitmq.conf
server {
listen 80;
server_name www.fllrabbit.com;
location /
{
proxy_pass http://127.0.0.1:15672;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
}
[root@localhost ~]# systemctl start nginx
[root@localhost ~]# systemctl start rabbitmq-server
现在可以通过浏览器访问rabbit,账号密码都是:guest
6.发送消息到rabbitmq
(1)打开另一台主机安装python3
[root@localhost ~]# yum -y install python3
[root@localhost ~]# pip3 install pika
(2)编辑测试程序
[root@localhost ~]# vim send_message.sh
import pika
# 连接到RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters('192.168.10.101'))
channel = connection.channel()
# 声明队列;如果队列不存在会被创建
channel.queue_declare(queue='test_queue', durable=True)
# 发送消息到队列中
channel.basic_publish(
exchange='',
routing_key='test_queue',
body='Hello, RabbitMQ!',
properties=pika.BasicProperties(
delivery_mode=2, # 使消息持久化
)
)
print("消息发送完毕")
# 关闭连接
connection.close()
(3)测试发送消息
[root@localhost ~]# python3 send_message.sh
(4)查看RabbitMQ
7.从RabbitMQ接收消息
(1)安装python3
打开第三台主机
[root@localhost ~]# yum -y install python3
[root@localhost ~]# pip3 install pika
(2)编写测试程序
[root@localhost ~]# vim receice_message.sh
import pika
# 连接到RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters('192.168.10.101'))
channel = connection.channel()
# 声明队列,确保RabbitMQ中有一个名为'test_queue'的队列
channel.queue_declare(queue='test_queue', durable=True)
# 定义回调函数来处理消息
def callback(ch, method, properties, body):
print(f"Received {body.decode()}")
# 消费队列中的消息,回调函数为callback
channel.basic_consume(queue='test_queue', on_message_callback=callback, auto_ack=True)
print("Waiting for messages. To exit press CTRL+C")
# 开始监听消息
channel.start_consuming()
(3)执行程序接收消息
[root@localhost ~]# python3 receice_message.sh
Waiting for messages. To exit press CTRL+C
Received Hello, RabbitMQ!
Received Hello, RabbitMQ!
Received Hello, RabbitMQ!
注意:
可以一边发送消息,一边观察接收到的消息。
四、rabbitmq常用命令
1.虚拟机管理
[root@localhost ~]# rabbitmqctl list_vhosts
##列出所有的虚拟主机
[root@localhost ~]# rabbitmqctl add_vhost fll
##创建名字叫fll的虚拟主机
[root@localhost ~]# rabbitmqctl delete_vhost fll
##删除名字叫fll的虚拟主机
2.用户管理
[root@localhost ~]# rabbitmqctl add_user user1 user1_passwd
##创建user1用户,密码为user1_passwd
[root@localhost ~]# rabbitmqctl list_users
##列出所有用户
[root@localhost ~]# rabbitmqctl change_password user1 new_passwd
##更改user1的密码为new_passwd
[root@localhost ~]# rabbitmqctl delete_user user1
#删除user1用户
备注:
语法汇总
- rabbitmqctl list_users #列出用户
- rabbitmqctl add_user <username> <password> #创建用户
- rabbitmqctl change_password <username> <password> ##更改用户密码
- rabbitmqctl delete_user <username> #删除用户
- rabbitmqctl clear_password <username> #清除用户密码
3.tags角色介绍
(1) 超级管理员(administrator):guest
可登陆管理控制台(启用management plugin的情况下),可查看所有的信息,并且可以对用户,策略(policy)进行操作。
(2) 监控者(monitoring)
可登陆管理控制台(启用management plugin的情况下),同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
(3) 策略制定者(policymaker)
可登陆管理控制台(启用management plugin的情况下), 同时可以对policy进行管理。但无法查看节点的相关信息。
(4) 普通管理者(management)
仅可登陆管理控制台(启用management plugin的情况下),无法看到节点信息,也无法对策略进行管理。
(5) 其他
无法登陆管理控制台,通常就是普通的生产者和消费者。
[root@localhost ~]# rabbitmqctl add_user user1 user1_passwd
[root@localhost ~]# rabbitmqctl set_user_tags user1 managemnet
##赋予user1用户management角色
[root@localhost ~]# rabbitmqctl add_vhost fll
[root@localhost ~]# rabbitmqctl set_permissions -p fll user1 '.*' '.*' '.*'
##针对fll虚拟主机给user1用户设置所有的配置、读写queue和exchange的权限。默认是没有任何权限的
说明:用户权限指的是用户对exchange(交换器),queue(队列)的操作权限,包括配置权限,读写权限。配置权限会影响到exchange,queue的声明和删除。读写权限影响到从queue里取消息,向exchange发送消息以及queue和exchange的绑定(bind)操作。例如: 将queue绑定到某exchange上,需要具有queue的可写权限,以及exchange的可读权限;向exchange发送消息需要具有exchange的可写权限;从queue里取数据需要具有queue的可读权限。
[root@localhost ~]# rabbitmqctl list_user_permissions user1
##列出user1的权限
[root@localhost ~]# rabbitmqctl list_permissions -p fll
##列出fll下的所有用户权限
备注:
如果需要清除user2在fll上的权限
[root@localhost ~]# rabbitmqctl clear_permissions -p fll user2
备注:
其他操作语法
rabbitmqctl list_user_permissions <username>
#列出某用户的权限,即该用户对哪个虚拟主机有权限
rabbitmqctl list_permissions -p <vhostname>
#列出指定虚拟主机下所有用户的权限,即哪些用户对该虚拟主机有权限
rabbitmqctl clear_permissions -p <vhostname> <user>
#清除某用户在指定虚拟机上的授权
4.插件管理
- rabbitmq-plugins list ##获取RabbitMQ插件列表
- rabbitmq-plugins enable <插件名字> ##安装RabbitMQ插件
- rabbitmq-plugins disable <插件名字> ##卸载某个插件
5.限制
rabbitmqctl set_vhost_limits -p vhost_name '{"max-connections": 256}'
#设置虚拟主机的最大连接数
rabbitmqctl set_vhost_limits -p vhost_name '{"max-connections": 0}'
#不允许客户端连接虚拟主机
rabbitmqctl set_vhost_limits -p vhost_name '{"max-connections": -1}'
#不限制连接数
rabbitmqctl set_vhost_limits -p vhost_name '{"max-queues": 1024}'
#限制虚拟主机里最大的队列数
rabbitmqctl set_vhost_limits -p vhost_name '{"max-queues": -1}'
#不限制队列数
6.其他
rabbitmqctl list_exchanges
#列出所有的交换器
rabbitmqctl list_bindings
#列出所有的绑定,即把exchange和queue按照路由规则绑定起来
rabbitmqctl list_queues
#分别查看当前系统种存在的Exchange和Exchange上绑定的Queue信息。
rabbitmqctl status
#查看运行信息
五、RabbitMQ集群
RabbitMQ本身是基于Erlang编写的,Erlang天生支持分布式(通过同步Erlang集群各节点的cookie来实现),因此不需要像Kafka那样通过ZooKeeper来实现分布式集群。
1.元数据
RabbitMQ内部有各种基础构件,包括队列、交换器、绑定、虚拟主机等,他们组成了AMQP协议消息通信的基础,而这些构件以元数据的形式存在
2.内存节点与磁盘节点
在集群中的每个节点,要么是内存节点,要么是磁盘节点,如果是内存节点,会将所有的元数据信息仅存储到内存中,而磁盘节点则不仅会将所有元数据存储到内存上, 还会将其持久化到磁盘。所以在搭建集群的时候,为了保证数据的安全性和性能,最好是两种节点都要有
3.规则
主机名 | Ip | 节点类型 |
centos01 | 192.168.10.101 | 磁盘节点 |
Centos02 | 192.168.10.102 | 内存节点 |
Centos03 | 192.168.10.103 | 内存节点 |
4.部署集群
(1)配置hosts以及hostname
三台机器设置hostname
hostnamectl set-hostname mq01
hostnamectl set-hostname mq02
hostnamectl set-hostname mq03
三台机器上都需要编辑如下hosts
192.168.10.101 mq01
192.168.10.102 mq02
192.168.10.103 mq03
(2)关闭selinux以及firewalld
三台机器都要执行
setenforce 0
systemctl stop firewalld
systemctl disable firewalld
(3)安装rabbitmq
RabbitMQ服务器是用Erlang语言编写的
rm -rf /etc/yum.repos.d/*
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
yum clean all
yum install -y erlang
[root@localhost ~]# yum install -y rabbitmq-server
(4)启动服务
三台机器都启动起来
[root@localhost ~]# systemctl start rabbitmq-server
[root@localhost ~]# systemctl enable rabbitmq-server
[root@localhost ~]# ps aux |grep rabbit ## 查看rabbit进程
[root@localhost ~]# netstat -lntp ## 查看监听端口
(5)安装management插件
三台机器都要开启
rabbitmq-plugins enable rabbitmq_management
(6)同步cookie
在mq01上将mq01的cookie文件同步到mq02和mq03
scp /var/lib/rabbitmq/.erlang.cookie root@mq02:/var/lib/rabbitmq/
scp /var/lib/rabbitmq/.erlang.cookie root@mq03:/var/lib/rabbitmq/
(7)重启三台主机并检查三台主机的rabbitmq服务
[root@localhost ~]# ps aux |grep rabbit ## 查看rabbit进程
[root@localhost ~]# netstat -lntp ## 查看监听端口
(8)分配节点
centos01为磁盘节点,centos02和centos03为内存节点
centos02和centos03上都执行:
停止rabbitmq
[root@localhost ~]# rabbitmqctl stop_app
备注:
表示终止RabbitMQ的应用,但是Erlang节点还在运行。在管理RabbitMQ应用时需要停止rabbitmq,但是又要使用erlang对rabbitmq进行管理。
将centos02作为内存节点连接到centos01
[root@localhost ~]# rabbitmqctl join_cluster --ram rabbit@mq01
开启rabbitmq
[root@localhost ~]# rabbitmqctl start_app
查看集群状态
[root@localhost ~]# rabbitmqctl cluster_status