RabbitMQ#RabbitMQ+Haproxy消息队列集群和代理部署

一、消息队列/中间件

1、RabbitMQ本质上起到的作用就是削峰填谷

在我们秒杀抢购商品的时候,系统会提醒我们稍等排队中,而不是像几年前一样页面卡死或报错给用户。像这种排队结算就用到了消息队列机制,放入通道里面一个一个结算处理,而不是某个时间断突然涌入大批量的查询新增把数据库给搞宕机,所以RabbitMQ本质上起到的作用就是削峰填谷,为业务保驾护航

2、MQ简介(RabbitMQ比Kafka)

MQ 全称为Message Queue, 消息队列。是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间,通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信。队列的使用除去了接收和发送应用程序,同时执行的要求。在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式,大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量

3、MQ消息队列的分类

P2P模式(安全)Point-to-Point(P2P)点对点模式
  P2P模式包含三个角色:
  1.消息队列(Queue)、
  2.发送者(Sender)、
  3.接收者(Receiver)。
  每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到它们被消费或超时。
  P2P的特点如下:
  • 每个消息只有一个消费者(Consumer),即一旦被消费,消息就不再在消息队列中
  • 发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行它不会影响到消息被发送到队列
  • 接收者在成功接收消息之后,需向队列应答成功。
  • 如果希望发送的每个消息都会被成功处理的话,那么需要P2P模式
Pub/Sub模式(并发)Publish/Subscribe 发布/订阅模式
  Pub/Sub模式包含三个角色:主题(Topic)、发布者(Publisher)、订阅者(Subscriber) 。多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。Pub/Sub的特点如下:
  • 每个消息可以有多个消费者
  • 发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息
  • 为了消费消息,订阅者必须保持运行的状态
  • 如果希望发送的消息可以不被做任何处理、或者只被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型

二、RabbitMQ介绍(端口15672)

1、RabbitMQ简介

RabbitMQ是一个在AMQP(Advanced Message Queuing Protocol )基础上实现的,可复用的企业消息系统。它可以用于大型软件系统,各个模块之间的高效通信,支持高并发,支持可扩展。它支持多种客户端如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级,更适合于企业级的开发。它同时实现了一个Broker构架,这意味着消息在发送给客户端时先在中心队列排队,对路由(Routing)、负载均衡(Load balance)或者数据持久化都有很好的支持

2、AMQP介绍

AMQP,即Advanced Message Queuing Protocol(高级消息队列服务)一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制

3、RabbitMQ架构和术语
  RabbitMQ从整体上来看是一个典型的生产者消费者模型,主要负责接收、存储和转发消息
Message
  消息,是有消息头和消息体组成的。消息体是不透明的,消息体是由一些可选属性组成的,包括路由键(routing-key)、优先级(priority)、持久性存储(delivery-mode)等
Publisher
  消息生产者,是向交换器发送消息的客户端程序,我们可以简单理解为就是一个Java程序
Exchange
  交换器,用来接收生产者发送的消息,并将这些消息路由发送给服务器中的队列。消息要先经过交换器(exchange),再到队列中去。
  常见的三种交换器类型:
    direct:发布与订阅,完全匹配 。我们可以简单理解为一对一的关系,一个交换器将消息发送给一个队列,是完全匹配的
    fanout:广播,所有订阅该广播的队列都可以收到该消息。广播式交换器,不管消息的ROUTING_KEY设置为什么,Exchange都会将消息转发给所有绑定的Queue
    topic:主题,规则匹配 。
Queue
  消息队列,用来保存消息,直到发送给消费者,是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一致在队列里面,等待消费者连接到这个队列将其取走。
Bingding
  绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键,将交换器和消息队列连接起来的路由规则,所以可以将交换器理解为一个由绑定构成的路由表
Virtual Host
  虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器区域。// 也就是说虚拟主机、交换器、队列、绑定等是通过虚拟机来实现的每个vhost本质上就是一个mini版的RabbitMQ服务器,拥有自己的队列、交换器、绑定和权限机制。vhost是AMQP概念的基础,必须再连接时指定,RabbitMQ默认的vhost是"/"
Broker
  可以理解为rabbitmq的服务器实体,可以理解为在Linux上创建的虚拟机实体
Connection
连接,我们可以理解为:rabbitmq服务器和app服务建立的TCP的连接。
Channel
  信道,也可以成为管道。是TCP里的虚拟连接。一条TCP连接,可以包含很多条的Channel。
  例如:电缆相当与TCP,信道是一条独立光纤束,一条TCP连接上创建多少条信道是没有限制的
  TCP一旦打开,就会创建AMQP信道,无论是发布消息、接收消息、订阅消息,这些动作都是通过信道完成的
Consumer
  消息的消费者,表示一个从消息队列中取得消息的客户端应用程序,和Producer类似,我们可以简单理解为就是一个Java程序

在这里插入图片描述

4、Rabbit MQ的通信过程

在这里插入图片描述
在这里插入图片描述

三、RabbitMQ单机部署

1、安装Erlang

[root@rabbitmq ~]# vim /etc/yum.repos.d/erlang.repo
[rabbitmq-erlang]
name=rabbitmq-erlang
baseurl=https://dl.bintray.com/rabbitmq-erlang/rpm/erlang/21/el/7
gpgcheck=1
gpgkey=https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc
repo_gpgcheck=0
enabled=1
[root@rabbitmq ~]# yum -y install erlang

2、安装RabbitMQ修改配置文件

[root@rabbitmq ~]# wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.13/rabbitmq-server-3.7.13-1.el7.noarch.rpm
[root@rabbitmq ~]# yum -y install rabbitmq-server-3.7.13-1.el7.noarch.rpm
[root@rabbitmq ~]# cp /usr/share/doc/rabbitmq-server-3.7.13/rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
[root@rabbitmq ~]# vim /etc/rabbitmq/rabbitmq.config
//打开配置文件,61行 去掉注释%%和逗号
{loopback_users, []}(回环用户账号)

3、安装插件并启动服务

[root@rabbitmq ~]# rabbitmq-plugins enable rabbitmq_management
//安装web管理界面插件工具
[root@rabbitmq ~]# systemctl restart rabbitmq-server
[root@rabbitmq ~]# rabbitmqctl cluster_status
//查看节点状态

4、访问测试

http://127.0.0.1:15672
默认账号密码:guest/guest
在这里插入图片描述
在这里插入图片描述

四、客户端介绍(命令行添加用户和设置用户tags)

1、界面介绍

在这里插入图片描述

2、设置虚拟主机与添加用户

(开发者)查看所有的队列:rabbitmqctl list_queues
[root@rabbitmq ~]# rabbitmqctl list_queues
(开发者)清除所有的队列:rabbitmqctl reset
[root@rabbitmq ~]# rabbitmqctl reset
添加用户:rabbitmqctl add_user username password
username 换掉
passwd 换掉
[root@rabbitmq ~]# rabbitmqctl add_user sunlizhen sunlizhen
Adding user “sunlizhen” …
分配角色:rabbitmqctl set_user_tags username administrator
[root@rabbitmq ~]# rabbitmqctl set_user_tags sunlizhen administrator
Setting tags for user “sunlizhen” to [administrator] …
后面的就不归莫我们管了
新增虚拟主机:rabbitmqctl add_vhost vhost_name
将新虚拟主机授权给新用户:rabbitmqctl set_permissions -p vhost_name username “." ".” "."(后面三个””代表用户拥有配置、写、读全部权限)
虚拟主机:关于虚拟主机(Virtual Host)其实是一个虚拟概念,类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,但是权限控制的最小粒度是Virtual Host
用户角色有下面几种:

  1. 超级管理员administrator:可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
  2. 监控者monitoring:可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
  3. 策略制定者policymaker:可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
  4. 普通管理者management:仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。无法登陆管理控制台,通常就是普通的生产者和消费者。

在这里插入图片描述

五、RabbitMQ+Haproxy集群部署

1、集群介绍

消息中间件RabbitMQ,一般以集群方式部署,主要提供消息的接受和发送,实现各微服务之间的消息异步。以下将介绍RabbitMQ+HA方式进行部署。

2、原理介绍

cookie
  RabbitMQ底层是通过Erlang架构来实现的,所以rabbitmqctl会启动Erlang节点,并基于Erlang节点来使用Erlang系统连接RabbitMQ节点,在连接过程中需要正确的Erlang Cookie和节点名称,Erlang节点通过交换Erlang Cookie以获得认证来实现分布式,所以部署Rabbitmq分布式集群时要先安装Erlang,并把其中一个服务的cookie复制到另外的节点。
内存节点和磁盘节点
  RabbitMQ集群中,各个RabbitMQ为对等节点,即每个节点均提供给客户端连接,进行消息的接收和发送。节点分为内存节点和磁盘节点,一般都建立为磁盘节点,为了防止机器重启后的消息消失
普通模式和镜像模式
  RabbitMQ的Cluster集群模式一般分为两种,普通模式和镜像模式。消息队列通过RabbitMQ HA镜像队列进行消息队列实体复制。
普通模式:
  普通模式下,以两个节点(rabbit01、rabbit02)为例来进行说明。对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构。当消息进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。
镜像模式:集群高可用
  镜像模式下,将需要消费的队列变为镜像队列,存在于多个节点,这样就可以实现RabbitMQ的HA高可用性。作用就是消息实体会主动在镜像节点之间实现同步,而不是像普通模式那样,在consumer消费数据时临时读取。缺点就是,集群内部的同步通讯会占用大量的网络带宽。

3、环境部署

域名解析:
10.11.67.85 rabbitmq-node1
10.11.67.19 rabbitmq-node2
10.11.67.69 rabbitmq-node3
三台rabbitmq都需要单台部署rabbitmq和erling(不赘述)
所有节点需要有相同的 erlang cookie,否则不能正常通信,为了实现cookie内容一致,采用scp的方式进行

4、设置erlang独立运行节点

保证三台机器的cookie内容一致
  找到erlang cookie文件的位置,源码包部署一般会存在.erlang.cookie文件;rpm包部署一般是在/var/lib/rabbitmq/.erlang.cookie。将 node1 的该文件使用rsync或者是scp复制到 node2、node3,文件权限需要是400。
[root@rabbitmq-node1 ~]# scp -r /var/lib/rabbitmq/.erlang.cookie rabbitmq-node2:/var/lib/rabbitmq/.erlang.cookie
[root@rabbitmq-node1 ~]# scp -r /var/lib/rabbitmq/.erlang.cookie rabbitmq-node3:/var/lib/rabbitmq/.erlang.cookie
[root@rabbitmq-node2 ~]# systemctl restart rabbitmq-server
[root@rabbitmq-node3 ~]# systemctl restart rabbitmq-server
rabbitmq2和rabbitmq3
  关闭rabbitmq2和rabbitmq3的服务(不要关rabbitmq1)如果2,3节点没有启动服务,会提示关闭错误。
  独立运行节点,warning提示不用理会。Warning: PID file not written; -detached was passed.
[root@rabbitmq-node2 ~]# rabbitmqctl stop
Stopping and halting node rabbit@rabbitmq-node2 …
[root@rabbitmq-node3 ~]# rabbitmqctl stop
Stopping and halting node rabbit@rabbitmq-node3 …
[root@rabbitmq-node2 ~]# rabbitmq-server -detached
[root@rabbitmq-node3 ~]# rabbitmq-server -detached
  查看节点状态,每台主机看到的只有一个的server信息。目前尚未组合成集群rabbitmqctl cluster_status
rabbitma-node1、rabbitmq2和rabbitmq3
  由于guest这个用户,只能在本地访问,所以我们要在每个节点上,新增一个用户并赋予对/的所有权限,然后添加到管理员组中,让此用户能够远程访问
rabbitmqctl add_user admin admin

rabbitmqctl set_permissions -p “/” admin “." ".” “.*”
rabbitmqctl set_user_tags admin administrator
访问测试:
http://ip:15672
账号:admin密码admin
此时每个节点是单独的一台RabbitMQ,下面来将他们组成集群
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

5、组成集群

简介
  rabbitmq-server 启动时,会一起启动:节点和应用,它预先设置RabbitMQ应用为standalone(脱机)模式。要将一个节点加入到现有的集群中,你需要停止这个应用,并将节点设置为原始状态。如果使用rabbitmqctl stop,应用和节点都将被关闭。所以使用rabbitmqctl stop_app仅仅关闭应用。(停应用,不停止节点)
将node2、node3加入到node1中组成集群(磁盘节点)
第二台节点
仅停止应用,不关闭节点(注意是节点2)
[root@rabbitmq-node2 ~]# rabbitmqctl stop_app
集群名字一定不要写错(查看rabbitmq1 的节点状态)
[root@rabbitmq-node2 ~]# rabbitmqctl join_cluster rabbit@rabbitmq-node1
如果此时查看节点1,会发现集群节点信息增加
[root@rabbitmq-node2 ~]# rabbitmqctl start_app
第三台节点
[root@rabbitmq-node3 ~]# rabbitmqctl stop_app
[root@rabbitmq-node3 ~]# rabbitmqctl join_cluster rabbit@rabbitmq-node1
[root@rabbitmq-node3 ~]# rabbitmqctl start_app

此时任意一个节点查看节点信息:
Cluster status of node rabbit@rabbitmq-node2 …
[{nodes,[{disc,[‘rabbit@rabbitmq-node1’,‘rabbit@rabbitmq-node2’,
‘rabbit@rabbitmq-node3’]}]},
{running_nodes,[‘rabbit@rabbitmq-node3’,‘rabbit@rabbitmq-node1’,
‘rabbit@rabbitmq-node2’]},
{cluster_name,<<“rabbit@rabbitmq-node1”>>},
{partitions,[]},
{alarms,[{‘rabbit@rabbitmq-node3’,[]},
{‘rabbit@rabbitmq-node1’,[]},
{‘rabbit@rabbitmq-node2’,[]}]}]

内存节点(了解)使用内存节点加入集群
rabbitmqctl join_cluster --ram rabbit@rabbitmq1

6、在任意节点上设置镜像队列策略

在web界面登陆,点击“Admin–Virtual Hosts(页面右侧)”,在打开的页面上的下方的“Add a new virtual host”处增加一个虚拟主机,同时给用户“admin”和“guest”均加上权限(在页面直接设置、点点点即可);(另外两个节点会自动同步)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

生产端规则实例

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();
	}
}

在这里插入图片描述

7、配置Haproxy代理

在独立服务器上安装HAProxy
[root@haproxy ~]# yum -y install haproxy
修改配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg

global 
    
    log         127.0.0.1 local2
 
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
 
    stats socket /var/lib/haproxy/stats
 
defaults 
       log        global 
       mode       tcp 
       option     tcplog 
       option     dontlognull 
       retries    3 
       option redispatch 
       maxconn 2000 
       contimeout      5s 
       clitimeout      120s 
       srvtimeout      120s 
 
listen rabbitmq_cluster 0.0.0.0:80#作为代理的服务器的IP和端口
       mode      tcp 
       balance roundrobin 
       server rabbit1  10.11.67.85:15672 check inter 5000 rise 2 fall 2 
       server rabbit2  10.11.67.19:15672 check inter 5000 rise 2 fall 2        
       server rabbit3  10.11.67.69:15672 check inter 2000 rise 2 fall 3


listen monitor
    bind 0.0.0.0:8100#监控页面的访问端口
    mode http
    option httplog
    stats enable
    stats uri /rabbitmqstats
    stats refresh 30s
    stats auth admin:admin

重启HAProxy
[root@haproxy ~]# systemctl restart haproxy

登录浏览器输入地址
查看HAProxy的状态
http://10.11.67.32:8100/rabbitmqstats
账号:admin
密码:admin
在这里插入图片描述

高可用使用rabbitmq。实战完毕
http://10.11.67.32:80
在这里插入图片描述

6、在任意节点上设置镜像队列策略
  在web界面登陆,点击“Admin–Virtual Hosts(页面右侧)”,在打开的页面上的下方的“Add a new virtual host”处增加一个虚拟主机,同时给用户“admin”和“guest”均加上权限(在页面直接设置、点点点即可);(另外两个节点会自动同步)
  规则的设定,不归我管

7、配置Haproxy代理
在独立服务器上安装HAProxy
[root@haproxy ~]# yum -y install haproxy
修改配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg

global 
    
    log         127.0.0.1 local2
 
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
 
    stats socket /var/lib/haproxy/stats
 
defaults 
       log        global 
       mode       tcp 
       option     tcplog 
       option     dontlognull 
       retries    3 
       option redispatch 
       maxconn 2000 
       contimeout      5s 
       clitimeout      120s 
       srvtimeout      120s 
 
listen rabbitmq_cluster 0.0.0.0:80#作为代理的服务器的IP和端口
       mode      tcp 
       balance roundrobin 
       server rabbit1  10.11.67.85:15672 check inter 5000 rise 2 fall 2 
       server rabbit2  10.11.67.19:15672 check inter 5000 rise 2 fall 2        
       server rabbit3  10.11.67.69:15672 check inter 2000 rise 2 fall 3


listen monitor
    bind 0.0.0.0:8100#监控页面的访问端口
    mode http
    option httplog
    stats enable
    stats uri /rabbitmqstats
    stats refresh 30s
    stats auth admin:admin
    

重启HAProxy
[root@haproxy ~]# systemctl restart haproxy

登录浏览器输入地址
查看HAProxy的状态
http://10.11.67.32:8100/rabbitmqstats
高可用使用rabbitmq。实战完毕
http://10.11.67.32:80

六、问题汇总

1、使用 rabbitmq-server -detached命令启动rabbitmq时,出现Warning: PID file not written; -detached was passed,此时使用rabbitmqctl status提示服务已启动,此问题不用解决

2、由于更改hostname文件,在每次rabbitmqctl stop或者rabbitmqctl cluster_status等,只要是rabbitmq的命令就报错,提示大概如下
  Cluster status of node rabbit@web2 …
  Error: unable to connect to node rabbit@web2: nodedown

DIAGNOSTICS
  ===========

  attempted to contact: [rabbit@web2]

  rabbit@web2:
  * connected to epmd (port 4369) on web2
  * epmd reports node ‘rabbit’ running on port 25672
  * TCP connection succeeded but Erlang distribution failed

  * Hostname mismatch: node “rabbit@mq2” believes its host is different. Please ensure that hostnames resolve the same way locally and on “rabbit@mq2”

current node details:
  - node name: ‘rabbitmq-cli-11@web2’
  - home dir: /root
  - cookie hash: SGwxMdJ3PjEXG1asIEFpBg==

解决办法
    ps aux |grep mq
    killall -9 beam.smp
    rabbitmq-server -detached

3、使用rabbitmqctl stop,rabbitmq-server -detached重新启动后,原先添加的用户admin、虚拟主机coresystem等均丢失,还需要重新添加。
  采用脚本启动,在脚本中写好启动好需要加载的各配置项(创建admin用户并授权,创建虚拟主机并授权,配置镜像队列)

4、rabbitmqctl stop_app #仅关闭应用,不关闭节点
  rabbitmqctl start_app #开启应用
  rabbitmq-server -detached #启动节点和应用
  rabbitmqctl stop #关闭节点和应用

5、常用命令
  Rabbitmq服务器的主要通过rabbitmqctl和rabbimq-plugins两个工具来管理,以下是一些常用功能。
  1、 服务器启动与关闭
  启动: rabbitmq-server –detached
  关闭: rabbitmqctl stop
  若单机有多个实例,则在rabbitmqctl后加 –n 指定名称
  2、插件管理
  开启某个插件:rabbitmq-plugins enable xxx
  关闭某个插件:rabbitmq-plugins disable xxx
  注意:重启服务器后生效。
  3、virtual_host管理
  新建virtual_host:rabbitmqctl add_vhost xxx
  撤销virtual_host:rabbitmqctl delete_vhost xxx
  4、用户管理
  新建用户:rabbitmqctl add_user xxxpwd
  删除用户: rabbitmqctl delete_user xxx
  查看用户:rabbitmqctl list_users
  改密码: rabbimqctl change_password {username} {newpassword}
  设置用户角色:rabbitmqctlset_user_tags {username} {tag …}
  Tag可以为 administrator,monitoring, management
  5、 权限管理
  权限设置:set_permissions [-pvhostpath] {user} {conf} {write} {read}
  Vhostpath: Vhost路径
  user: 用户名
  Conf: 一个正则表达式match哪些配置资源能够被该用户访问。
  Write: 一个正则表达式match哪些配置资源能够被该用户读。
  Read: 一个正则表达式match哪些配置资源能够被该用户访问。
  6、获取服务器状态信息
  服务器状态:rabbitmqctl status ##其中可查看rabbitmq的版本信息
  7、获取集群状态信息
  rabbitmqctl cluster_status

6、为什么选择RabbitMQ
  现在的市面上有很多MQ可以选择,比如ActiveMQ、ZeroMQ、Appche Qpid,那问题来了为什么要选择RabbitMQ?
  除了Qpid,RabbitMQ是唯一一个实现了AMQP标准的消息服务器;
  可靠性,RabbitMQ的持久化支持,保证了消息的稳定性;
  高并发,RabbitMQ使用了Erlang开发语言,Erlang是为电话交换机开发的语言,天生自带高并发光环,和高可用特性;
  集群部署简单,正是应为Erlang使得RabbitMQ集群部署变的超级简单;
  社区活跃度高,根据网上资料来看,RabbitMQ也是首选;

7、如何设置Rabbit的消息持久化
  持久化工作原理
  Rabbit会将你的持久化消息写入磁盘上的持久化日志文件,等消息被消费之后,Rabbit会把这条消息标识为等待垃圾回收。
  Rabbit队列和交换器有一个不可告人的秘密,就是默认情况下重启服务器会导致消息丢失,那么怎么保证Rabbit在重启的时候不丢失呢?答案就是消息持久化。
  当你把消息发送到Rabbit服务器的时候,你需要选择你是否要进行持久化,但这并不能保证Rabbit能从崩溃中恢复,想要Rabbit消息能恢复必须满足3个条件:
  投递消息的时候durable设置为true,消息持久化,代码:channel.queueDeclare(x, true, false, false, null),参数2设置为true持久化;
  设置投递模式deliveryMode设置为2(持久),代码:channel.basicPublish(x, x, MessageProperties.PERSISTENT_TEXT_PLAIN,x),参数3设置为存储纯文本到磁盘;
  消息已经到达持久化交换器上;
  消息已经到达持久化的队列;

8、vhost特性是什么
  RabbitMQ默认的vhost是“/”开箱即用;
  多个vhost是隔离的,多个vhost无法通讯,并且不用担心命名冲突(队列和交换器和绑定),实现了多层分离;创建用户的时候必须指定vhost;

9、消息队列RabbitMq的队列形式?
  1.点对点的队列
  功能:一个生产者P发送消息到队列Q,一个消费者C接收
  生产者实现思路:
  创建连接工厂ConnectionFactory,设置服务地址127.0.0.1,端口号5672,设置用户名、密码、virtual host,从连接工厂中获取连接connection,使用连接创建通道channel,使用通道channel创建队列queue,使用通道channel向队列中发送消息,关闭通道和连接。
  消费者实现思路
  创建连接工厂ConnectionFactory,设置服务地址127.0.0.1,端口号5672,设置用户名、密码、virtual host,从连接工厂中获取连接connection,使用连接创建通道channel,使用通道channel创建队列queue, 创建消费者并监听队列,从队列中读取消息。
  2 工作队列模式Work Queue
  功能描述:一个生产者发送消息到队列中,有多个消费者共享一个队列,每个消费者获取的消息是唯一的。为了保证服务器同一时刻只发送一条消息给消费者,保证资源的合理利用。channal.basicQos(1);这样是为了保证多个消费者接收的消息数量不一样,能者多劳,如果不设置,那么消费者是平均分配消息(例如10条消息,每个消费者接收5条)
  3 发布/订阅模式Publish/Subscribe
  这个可能是消息队列中最重要的队列了,其他的都是在它的基础上进行了扩展。
  功能实现:一个生产者发送消息,多个消费者获取消息(同样的消息),包括一个生产者,一个交换机,多个队列,多个消费者。
  思路解读(重点理解):
  (1)一个生产者,多个消费者
  (2)每一个消费者都有自己的一个队列
  (3)生产者没有直接发消息到队列中,而是发送到交换机
  (4)每个消费者的队列都绑定到交换机上
  (5)消息通过交换机到达每个消费者的队列
  注意:交换机没有存储消息功能,如果消息发送到没有绑定消费队列的交换机,消息则丢失。
  4 路由模式Routing
  功能:生产者发送消息到交换机并指定一个路由key,消费者队列绑定到交换机时要制定路由key(key匹配就能接受消息,key不匹配就不能接受消息),例如:我们可以把路由key设置为insert ,那么消费者队列key指定包含insert才可以接收消息,消费者队列key定义为update或者delete就不能接收消息。很好的控制了更新,插入和删除的操作。
  5 通配符模式Topics
  说明:此模式实在路由key模式的基础上,使用了通配符来管理消费者接收消息。生产者P发送消息到交换机X,type=topic,交换机根据绑定队列的routing key的值进行通配符匹配;
  符号#:匹配一个或者多个词lazy.# 可以匹配lazy.irs或者lazy.irs.cor
  符号*:只能匹配一个词lazy.* 可以匹配lazy.irs或者lazy.cor
  6.spring集成rabbitmq配置
  提供了AMQP的一个实现,并且spring-rabbit是RabbitMQ的一个实现,下面给出订阅者模式的事例配置如下:
  7.总结
  RabbitMQ提供了6种模式,分别是HelloWorld,Work Queue,Publish/Subscribe,Routing,Topics,RPC Request/reply,本文详细讲述了前5种,并给出代码实现和思路。其中Publish/Subscribe,Routing,Topics三种模式可以统一归为Exchange模式,只是创建时交换机的类型不一样,分别是fanout、direct、topic。Spring提供了rabbitmq的一个实现,所以集成起来很方便,文章第4章给出了订阅者模式的一种spring配置。

10、如何确保消息正确地发送至RabbitMQ?
RabbitMQ使用发送方确认模式,确保消息正确地发送到RabbitMQ。
  发送方确认模式:将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一ID)。如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack(not acknowledged,未确认)消息。
  发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

11、如何确保消息接收方消费了消息?
  接收方消息确认机制:消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。
  这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。
  下面罗列几种特殊情况:
  如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要根据bizId去重)
  如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙,将不会给该消费者分发更多的消息。

12、如何避免消息重复投递或重复消费?
  在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重和幂等的依据,避免同一条消息被重复消费。

13、消息基于什么传输?
  由于TCP连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制。

14、消息如何分发?
  若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。

15、消息怎么路由?
  从概念上来说,消息路由必须有三部分:交换器、路由、绑定。生产者把消息发布到交换器上;绑定决定了消息如何从路由器路由到特定的队列;消息最终到达队列,并被消费者接收。
  消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。
  通过队列路由键,可以把队列绑定到交换器上。
  消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则)。如果能够匹配到队列,则消息会投递到相应队列中;如果不能匹配到任何队列,消息将进入 “黑洞”。
  常用的交换器主要分为一下三种:
    direct:如果路由键完全匹配,消息就被投递到相应的队列
    fanout:如果交换器收到消息,将会广播到所有绑定的队列上
    topic:可以使来自不同源头的消息能够到达同一个队列。 使用topic交换器时,可以使用通配符,比如:“*” 匹配特定位置的任意文本, “.” 把路由键分为了几部分,“#” 匹配所有规则等。特别注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由"."隔开的一系列的标识符组成。

16、如何确保消息不丢失?
  消息持久化的前提是:将交换器/队列的durable属性设置为true,表示交换器/队列是持久交换器/队列,在服务器崩溃或重启之后不需要重新创建交换器/队列(交换器/队列会自动创建)。
  如果消息想要从Rabbit崩溃中恢复,那么消息必须:
  在消息发布前,通过把它的 “投递模式” 选项设置为2(持久)来把消息标记成持久化
  将消息发送到持久交换器
  消息到达持久队列
  RabbitMQ确保持久性消息能从服务器重启中恢复的方式是,将它们写入磁盘上的一个持久化日志文件,当发布一条持久性消息到持久交换器上时,Rabbit会在消息提交到日志文件后才发送响应(如果消息路由到了非持久队列,它会自动从持久化日志中移除)。一旦消费者从持久队列中消费了一条持久化消息,RabbitMQ会在持久化日志中把这条消息标记为等待垃圾收集。如果持久化消息在被消费之前RabbitMQ重启,那么Rabbit会自动重建交换器和队列(以及绑定),并重播持久化日志文件中的消息到合适的队列或者交换器上。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值