RabbitMQ消息队列
什么是消息队列?
当我们秒杀抢购商品的时候,系统提醒我们稍等排队中,这种排队结算,就用到了消息队列机制,一个一个处理,而不是某个时间突然融入大批量查询新增把数据库搞宕机,所以,消息队列的本质就是削峰填谷,为服务保驾护航。
什么是MQ?
Message Queue,消息队列,一种应用程序对应用程序的通信方法。
应用程序读写出入队列消息进行通信,无需专用连接。
消息传递时程序之间,通过消息中发送数据进行通信,而不是通过直接调用彼此来通信,除去了接收和发送应用程式,同时执行的要求。
项目中,将一些无需即时返回,而且耗时的操作提取出来,进行***异步处理***,节省服务器请求响应时间,从而提高i系统吞吐量。
核心功能
-
解耦(将不同系统分离开)
-
冗余(存储)
-
扩展性
-
削峰
-
可恢复性
-
顺序保证
-
缓冲
-
异步通信
消息队列的模式
两种模式:P2P模式(安全);Publish/Subscribe
一对一和一对多的两种模式
同类型产品:
1.kafka时linkedin开源分布式发布-订阅消息,目前归属于Apache顶级项目。kafka主要特点时基于Pull的模式来处理消息消费,追求高吞吐量,一开始就用于日志收集和传输。0.8版本开始支持复制,不支持事务,对于消息的重复、丢失、错误,是没有严格要求的,适合产生大量数据的互联网服务的数据收集业务,一般应用于大数据日志处理,或者对实时性、可靠性要求不高的场景使用,比如说elk日志收集。
2.rabbitmq
3.rocketmq
RabbitMQ详解
RabbitMQ是在AMQP基础上实现的,什么是AMQP?是一个协议,advanced message queuing prootocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议。为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。可复用的企业消息系统。
使用的语言是Erlang编写的开源消息队列,支持很多协议,重量级,适合企业级开发,同时实现了一个Broker框架,对路由,负载均衡,数据持久化都有很好的支持。
rabbitmq架构
- Message 消息头和消息体组成,消息体不透明,由一些可选属性组成,包括路由键(routing-key)、优先级(routing-key)、持久性存储(delivery-mode)等
- Publisher 消息生产者,向交换机发送消息的客户端程序,也可以理解为一个Java程序,如下所示。
- Exchange 交换器,接收生产者publisher发送的消息,并且将这些消息路由发送给服务器中的队列中,消息先经过交换器exchang,然后再到队列里。三种交换器类型:direct、fanout、topic
- Queue 消息的容器也是消息的终点,用来保存信息,直到发送给消费者cunsumeer,一个信息可以投入一个或者多个队列,消息一致在队列里面,等待消费者连接到这个队列将其取走。
- Bingding 绑定,用户消息队列和交换器之间的关联
- Virtual host 就是一个盒子,放两个东西,一个是exchange 一个是queue
- Broker 中间人,也可以理解为rabbitmq的实体
- Conection 连接,rabbitmq服务器和app服务建立的TCP连接
- Channel 信道,发布消息、接收消息、订阅消息都是通过信道完成的,conection连接的tcp连接一旦打开,就会创建AMQP信道。
- Cunsumer 消费者,与producer类似,一个Java程序,从一个消息队列中取得消息的客户端应用程序。如下所示。
public class Procuder {
private static final Logger log = LoggerFactory.getLogger(Procuder.class);
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost(RabbitMQCommon.RABBITMQ_HOST);
connectionFactory.setPort(RabbitMQCommon.RABBITMQ_PORT);
connectionFactory.setVirtualHost(RabbitMQCommon.RABBITMQ_DEFAULT_VIRTUAL_HOST);
// 2 通过连接工厂创建连接
Connection connection = connectionFactory.newConnection();
// 3 通过connection创建一个Channel
Channel channel = connection.createChannel();
Map<String, Object> headers = new HashMap<>();
headers.put("myHeaders1", "111");
headers.put("myHeaders2", "222");
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(2).contentEncoding("UTF-8")
.expiration("10000").headers(headers).build();
// 4 通过Channel发送数据
for (int i = 0; i < 5; i++) {
String msg = "Hello RabbitMQ!";
// 1 exchange 2 routingKey
log.info("生产端,test001: {}", msg);
channel.basicPublish("", "test001", properties, msg.getBytes());
}
// 5 记得要关闭相关的连接
channel.close();
connection.close();
}
}
public class Procuder {
private static final Logger log = LoggerFactory.getLogger(Procuder.class);
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost(RabbitMQCommon.RABBITMQ_HOST);
connectionFactory.setPort(RabbitMQCommon.RABBITMQ_PORT);
connectionFactory.setVirtualHost(RabbitMQCommon.RABBITMQ_DEFAULT_VIRTUAL_HOST);
// 2 通过连接工厂创建连接
Connection connection = connectionFactory.newConnection();
// 3 通过connection创建一个Channel
Channel channel = connection.createChannel();
Map<String, Object> headers = new HashMap<>();
headers.put("myHeaders1", "111");
headers.put("myHeaders2", "222");
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(2).contentEncoding("UTF-8")
.expiration("10000").headers(headers).build();
// 4 通过Channel发送数据
for (int i = 0; i < 5; i++) {
String msg = "Hello RabbitMQ!";
// 1 exchange 2 routingKey
log.info("生产端,test001: {}", msg);
channel.basicPublish("", "test001", properties, msg.getBytes());
}
// 5 记得要关闭相关的连接
channel.close();
connection.close();
}
}
RabbitMQ部署安装
环境
三台服务器,centos7,全部设置主机名和域名解析rabbitmq1、2、3
hostnamectl set-hostname rabbitmq1
设置主机名,退出连接再连接就更新了。
安装erlang
1.配置erlang的yum仓库
[rabbitmq_erlang]
name=rabbitmq_erlang
baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
[rabbitmq_erlang-source]
name=rabbitmq_erlang-source
baseurl=https://packagecloud.io/rabbitmq/erlang/el/7/SRPMS
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/rabbitmq/erlang/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
yum -y install erlang
安装rabbitmq
直接下载rpm包安装即可
(下载过了 ,直接上传)
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.13/rabbitmq-server-3.7.13-1.el7.noarch.rpm
或者rz上传包,然后再:
yum -y install rabbitmq-server-3.7.13-1.el7.noarch.rpm
cp /usr/share/doc/rabbitmq-server-3.7.13/rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
vim /etc/rabbitmq/rabbitmq.config
##61行去掉注释%%和,
{lopback_user, []}
rabbitmq-plugins enable rabbitmq_management
web管理界面
systemctl restart rabbitmq-server
启动消息队列服务
rabbitmqctl cluster_status
查看rabbitmq集群状态,现在只装了一台,所以只能看见自己的
访问iip加端口15672 默认账号密码guest
设置虚拟主机与添加用户
列出所有队列rabbitmqctl list_queues
清除所有队列rabbitmqctl reset
添加用户rabbitmqctl add_user username passwd
分配角色rabbitmqctl set_tags username administrator
新增虚拟主机rabbitmqctl add_vhost vhost_name
将新虚拟主机授权给用户rabbitmqctl set_permisssions -p vhost_name username ".*" ".*" ".*"
.*表示拥有读写执行的权限。
集群部署
提供分布式高可用的 提升读写性能和数据安全性
-
cookie
rabbitmq底层通过erlang架构来实现,所以,rabbitmqctl会启动erlang节点,并基于erlang节点使用erlang系统连接rabbitmq节点,再连接过程中需要正确的erlang cookie和节点名称。erlang节点 通过 erlang cookie 来获得认证,实现分布式,所以部署rabbitmq分布式集群要先安装erlang,并把其中一个服务的cookie复制到别节点里,以保证cookie的一致性问题。 -
内存节点和磁盘节点
每个rabbitmq为对等节点,也就是每个节点均提供给客户端连接,进行消息的接收和发送,节点分为内存节点和磁盘节点,一般都建立为磁盘节点,为了防止机器重启后消息消失。 -
普通模式和镜像模式
普通模式:消息只存在一个机器上
镜像模式:会复制到别的机器上,高可用,but占资源
环境
- 所有节点要在一个局域网内
- 所有节点要有相同的erlang cookie,可以使用scp进行复制传输
- 三台虚拟机进行测试,要求配置相同,都设置好主机名,并进行域名解析
- 系统版本,centos7
部署
所有节点安装erlang和rabbitmq
导入rabbitmq管理界面rabbitmq-plugins enabe rabbitmq_management
设置运行节点:
scp -r /var/lib/rabbitmq/.erlang.cookie rabbitmq2:/var/lib/rabbitmq/.erlang.cookie
scp -r /var/lib/rabbitmq/.erlang.cookie rabbitmq3:/var/lib/rabbitmq/.erlang.cookie
systemctl restart rabbitmq-server
rabbitmq1节点运行rabbitmq服务,而rabbitmq2和3关闭systemctl stop rabbitmq-server
在rabbitmq2和3节点独立运行节点rabbitmq-server-datached
在rabbitmq1中rabbitmqcl cluster_status
查看各个节点状态,现在只能看见当前的server信息,因为还没组成集群
添加用户admin,密码为admin(测试用。真实使用请设置复杂密码)
rabbitmqctl set_user_tags admin administrator rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*" rabbitmqctl add_user admin admin
组成集群
rabbitmq-server启动时,会一起启动节点和应用,会预先设置rabbitmq应用为standalone模式(脱机模式),注意,加入节点到集群中给,要先停止这个应用,并且将节点设置为原始状态,如果使用rabbitmqctl stop
会把应用和节点都关闭,不可取,所以使用rabbitmqctl stop_app
仅关闭应用,不停止节点。
将rabbitmq2、3加入到rabbitmq1里,也就是把node2、3加入到node1中
rabbitmq2、3都输入rabbitmqctl stop_app
停止其应用
rabbitmqctl join_cluster rabbit@rabbitmq1
加入集群
rabbitmqctl start_app
加完后,启动节点2、3的应用
rabbitmqcl cluster_status
查看
over,结束