目录
1.3、Federtation插件(不是默认支持,可能会有一些其他问题)
1.5、Federtation、Shovel、cluster的区别和联系
4.2、停止运行rabbitmq的Erlang虚拟机和rabbitmq服务应用
5.5、在集群中的节点应用启动前咨询clusternode节点的最新信息,并更新相应的集群信息
2.1.3.1 rabbitmq入门及内部消息分发机制
1、RabbitMQ简介
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
2、RabbitMQ安装运行
RabbitMQ安装及配置参考如下:
本地地址:E:\meWork\study\project\subject-2\subject-2-docs\1-消息中间件\rabbitmq单机到集群完整搭建.md
环境准备:CentOS7、Erlang
需要安装erlang、socat、rabbitmq
安装教程(集群部署也在这个文件中):http://59.111.92.219/q1906-java/subject-2/blob/master/subject-2-docs/1-消息中间件/rabbitmq单机到集群完整搭建.md
自己整理命令:
rabbitmq:
启动RabbitMQ服务:sudo systemctl start rabbitmq-server
重启服务:sudo systemctl restart rabbitmq-server
查看状态:sudo systemctl status rabbitmq-server
停止服务:sudo systemctl stop rabbitmq-server
设置为开机启动:sudo systemctl enable rabbitmq-server
查找所有的rabbitmq: yum list | grep rabbitmq
删除(卸载)rabbitmq-server.noarch:yum -y remove rabbitmq-server.noarch
erlang:
查找所有的erlang: yum list | grep erlang
删除(卸载)erlang:yum -y remove erlang.x86_64
虚拟机快照:https://blog.csdn.net/weixin_41557853/article/details/86097196
启动参考:https://blog.csdn.net/qq_31615049/article/details/86556904
集群部署一些命令说明:
将当前机器的cookie 复制到zkserver2机器:scp /var/lib/rabbitmq/.erlang.cookie root@zkserver2:/var/lib/rabbitmq/
将当前机器加入zkserver1节点所在的集群:rabbitmqctl join_cluster rabbit@zkserver1 --ram
启动rabbitmq报如下错时:
Job for rabbitmq-server.service failed because the control process exited with error code. See "systemctl status rabbitmq-server.service" and "journalctl -xe" for details.
1、运行journalctl -xe查找到错误原因:journalctl -xe
或者直接查看日志文件:more /var/log/rabbitmq/startup_log
2、我这里的错误是:ERROR: epmd error for host zkserver1: timeout (timed out)
3、因为我以前改过hostname,执行如下命令:vi /etc/hosts
在文件的127.0.0.1行中添加我的hostname:zkserver1
4、然后重新执行启动rabbitmq命令就可以启动了
查看端口使用情况:netstat -naop | grep 5672
查看有哪些正在运行的java程序:ps -ef | grep java
3、RabbitMQ基本配置
1、RabbitMQ有一套默认的配置,能够满足日常开发需求,如果需要修改,需要自己创建一个配置文件
touch /etc/rabbitmq/rabbitmq.conf
配置文件示例:
https://github.com/rabbitmq/rabbitmq-server/blob/master/docs/rabbitmq.conf.example
配置项说明:
https://www.rabbitmq.com/configure.html#config-items
2、RabbitMQ端口
rabbitmq会绑定一些端口,安装完后,需要将这些端口添加至防火墙。
4369:是Erlang的端口/节点名称映射程序,用来跟踪节点名称监听地址,在集群中起到一个类似DNS的作用
5672,5671:AMQP 0-9-1和1.0客户端端口,没有使用SSL和使用SSL的端口
25672(做管理用):用于RabbitMQ节点间和CLI工具通信,配合4369使用。
15672:HTTP_API端口,管理员用户才能访问,用于管理rabbitmq,需要启用management插件。
61613,61614:当STOMP插件启用的时候打开,作为STOMP客户端端口(根据是否使用TLS选择)。
1883,8883:当MQTT插件启用的时候打开,作为MQTT客户端端口(根据是否使用TLS选择)。
15674:基于WebSocket的STOMP客户端端口(当插件Web STOMP启用的时候打开)。
15675:基于Websocket的MQTT客户端端口(当插件Web MQTT启用的时候打开)。
4、RabbitMQ管理界面
开启插件
rabbitmq-plugins enable rabbitmq_management
rabbitmq有一个默认的用户“guest”,但这个用户默认只能通过本机访问,要让其它机器可以访问,需要创建一个新用户,为其分配权限
#添加用户
rabbitmqctl add_user admin admin
#为用户分配权限
rabbitmqctl set_user_tags admin administrator
#为用户分配资源权限
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
浏览器访问地址(账号密码,就用上面配置的admin就行):IP:15672,eg:http://192.168.0.32:15672
5、rabbitmq角色
1、none
不能访问management plugin
2、management
用户可以通过AMQP做任何事,还可以做如下的事:
1、列出自己可以通过AMQP登入的virtual hosts
2、查看自己的virtual hosts中的queues,exchanges和bindings
3、查看和关闭自己的channels和connections
4、查看有关自己的virtual hosts的“全局”的统计信息,包含其他用户在这些virtual hosts中的活动。
3、policymaker
可以做management做的任何事,还可以做如下的事:
查看、创建和删除自己的virtual hosts所属的policies和parameters
4、monitoring
可以做management做的任何事,还可以做如下的事:
1、列出所有virtual hosts,包括他们不能登录的virtual hosts
2、查看其他用户的channels和connections
3、查看节点级别的数据如clustering和memory使用情况
4、查看真正的关于所有virtual hosts的全局的统计信息
5、administrator
可以做policymaker和monitoring做的任何事,还可以做如下的事:
1、创建和删除virtual hosts
2、查看、创建和删除users
3、查看创建和删除permissions
4、关闭其他用户的connections
6、Hello World
1、在java中使用rabbitmq
参考demo代码:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a132\simple\Producer.java
1、在spring中使用rabbitmq
7、AMQP
AMQP(Advanced Message Queuing Protocol),是一个提供统一消息服务的标准高级消息队列协议,
是应用层协议的一个开放标准,为面向消息的中间件而设计
2、AMQP结构
3、AMQP生产者流转过程
4、AMQP消费者流转过程
8、rabbitmq核心概念
1、rabbitmq的虚拟机就相当于数据库服务(mysql、oracle)的database(库)
2、虚拟主机用斜杠(/)来进行命名
3、一个虚拟主机可以有多个queue
4、消息是存在queue中
5、binding是将exchange和队列绑定的一种队则,java中万物皆对象,所以这个绑定也看做一个对象。
binding中还有个路由键的概念。就是即使交换机与队列进行了绑定,但是在某些场景下,我们不希望与交换机绑定的队列都能收到消息。所以就可以去指定一个路由键。
在进行绑定的时候去指定路由键,在发送消息的时候指定Exchange、指定路由键,才可以正确的将消息发送到队列上。
1、producer在发送消息时:
消息就相当于一个包裹、exchange相当于邮局、queue相当于邮递员
2、rabbitmq的Exchange
1、指定路由关系的java代码demo:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a132\routing\Producer.java
2、指定Exchange类型的java代码demo:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a132\ps\Consumer.java
// 代码定义交换器
channel.exchangeDeclare("ps_test", "fanout");
// 还可以定义一个临时队列,连接关闭后会自动删除,此队列是一个排他队列
String queueName = channel.queueDeclare().getQueue();
// 将队列和交换器绑定
channel.queueBind(queueName, "ps_test", "");
3、工作队列消费者:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a132\work\Worker1.java
prefetchCount:提前拉取的数据大小(控制mq预推送消息条数),一般使用默认值就可以了
// 同一时刻,服务器只会发送10条消息给消费者
channel.basicQos(10);
如果设置的值小于1万,就不要设置了,就使用默认就好
9、Rabbitmq整体结构
10、Producer
生产者,就是投递消息的一方,生产者创建消息,然后发布到rabbitmq中。
消息一般可以包含两个部分:消息体和附件信息。
消息体(payload)
在实际应用中,消息体一般是一个带有业务逻辑结构的数据。
eg:一个JSON字符串,当然可以进一步对这个消息体进行序列化操作
附加信息
用来表述这条消息
eg:目标交换器的名称、路由键、一些自定义属性......
11、Broker
消息中间件的服务节点
对于rabbitmq来说,一个rabbitmq Broker可以简单地看作一个rabbitmq服务节点,或者rabbitmq服务实例。
也可以将一个rabbitmq Broker看作一台rabbitmq服务器。
12、Virtual Host
虚拟主机,表示一批交换器、消息队列和相关对象。
虚拟主机是共享相同的身份认证和加密环境的独立服务器域。
每个vhost本质上就是一个mini版的rabbitmq服务器,拥有自己的队列、交换器、绑定和权限机制。
vhost是AMQP概念的基础,必须在连接时指定,rabbitmq默认的vhost是/
13、Channel
频道或信道,是建立在connection连接之上的一种轻量级的连接。
大部分的操作是在Channel这个接口中完成的,包括定义队列的声明queueDeclare、交换机的声明exchangeDeclare、
队列的绑定queueBind、发布消息basicPublish、消费消息basicConsume等。
如果把Connection比作一条光纤电缆的话,那么Channel信道就比作成光纤电缆中的其中一束光纤。一个Connection上可以创建任意数量的Channel。
14、RoutingKey
路由键。生产者将消息发给交换器的时候,一般会指定一个RoutingKey,用来指定这个消息的路由规则。
RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用
在交换器类型和绑定键(BindingKey)固定的情况下,生产者可以在发送消息给交换器时,通过指定RoutingKey来决定消息流向哪里。
15、Exchange
交换器,生产者将消息发送到Exchange(交换器,通常也可以用大写的“X”来表示),由交换器将消息路由到一个或者多个队列中。
如果路由不到,或返回给生产者,或直接丢弃。
exchange的5中类型:
默认的exchange:根据消息指定的queue发送到指定的队列
Fanout:扇型交换机
它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中(广播)
Direct:直连交换机
它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中
Topic:主题交换机
与direct类似,但它可以通过通配符进行模糊匹配
【 . 表示单词的拆分方式】
* 表示一个单词的模糊匹配【只能是一个单词,多个单词就匹配不上】
例如:路由键是*.apple.big则表示第一个单词可以是任意的,只要后边单词完全匹配,就可以。
# 表示完全模糊匹配。
例如:路由键是#.little,那么发送消息的路由键可以是green,apple,little,也就是说前面的单词是任意的。
headers:头交换机
不依赖于路由键的匹配规则,在绑定queue与exchange时指定一组键值对,只要消息头中含有该“键值对”【键、值都要匹配上】,就路由到对应的队列
direct、topic相对来说,要灵活一些,headers性能很差,也不实用
16、Queue
队列,是rabbitmq的内部对象,用于存储消息。
17、Binding
绑定,rabbitmq中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键(BindingKey),
这样rabbitmq就知道如何正确地将消息路由到队列了。
18、Consumer
消费者,就是接收消息的一方。消费者连接到rabbitmq服务器,并订阅到队列上。
当消费者消费一条消息时,只是消费消息的消息体。在消息路由的过程中,消息的标签会丢弃,
存入到队列中的消息只有消息体,消费者也只会消费到消息体,也就不知道消息的生产者是谁,当然消费者也不需要知道。
19、消息的整体运转流程
20、Rabbitmq运转流程
2.1.3.2 rabbitmq集群和高可用方案
1、Cluster
rabbitmq的cluster模式分为两种:普通模式、镜像模式
1.1、普通模式
只同步元数据信息,队列中的消息不会同步
元数据包含以下内容:
队列元数据:队列的名称及属性
交换器:交换器的名称及属性
绑定关系元数据:交换器与队列或者交换器与交换器
vhost元数据:为vhost内的队列、交换器和绑定提供命名空间及安全属性之间的绑定关系
rabbitmq添加虚拟主机
1.2、镜像队列模式集群
ha:高可用
lb:负载均衡
1、对网卡要求比较高
2、镜像就是把相同的信息同步到不同的queue上
3、添加策略的参数说明:
name: 策略名称,如果使用已有的名称,保存后将会修改原来的信息
Pattern:策略应用到对象时,对象名称的匹配规则(正则表达式)
Apply to:策略应用到什么对象上
Priority:优先级,数值越大,优先级越高,相同优先级取最后一个
Definition:策略定义的类容,对于镜像队列的配置来说,只需要包含3个部分: ha-mode 、ha-params 和 ha-sync-mode。
其中,ha-sync-mode是同步的方式,自动还是手动,默认是自动。
ha-mode 和 ha-params 组合使用。组合方式如下:
ha-sync-mode
队列中消息的同步方式,有效值为automatic和manual,默认是automatic。
4、镜像队列模式相比较普通模式,镜像模式会占用更多的带宽来进行同步,所以镜像队列的吞吐量会低于普通模式
5、但普通模式不能实现高可用,某个节点挂了后,这个节点上的消息将无法被消费,需要等待节点启动后才能被消费。
vhost和权限应用示例:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a133\cluster\VirtualHostsDemo.java
客户端连接集群示例:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a133\cluster\Producer.java
// 开启/关闭连接自动恢复,默认是开启状态
factory.setAutomaticRecoveryEnabled(true);
// 设置每100毫秒尝试恢复一次,默认是5秒:com.rabbitmq.client.ConnectionFactory.DEFAULT_NETWORK_RECOVERY_INTERVAL
factory.setNetworkRecoveryInterval(100);
// 4、使用连接集合里面的地址获取连接
connection = factory.newConnection(addresses, "生产者");
// 添加重连监听器
((Recoverable) connection).addRecoveryListener(new RecoveryListener() {
/**
* 重连成功后的回调
* @param recoverable
*/
public void handleRecovery(Recoverable recoverable) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 已重新建立连接!");
}
/**
* 开始重连时的回调
* @param recoverable
*/
public void handleRecoveryStarted(Recoverable recoverable) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(new Date()) + " 开始尝试重连!");
}
});
1.3、Federtation插件(不是默认支持,可能会有一些其他问题)
Federtation插件的设计目标是使rabbitmq在不同的broker节点之间进行消息传递而无须建立集群
该功能在以下场景,非常有用:
1、各个节点运行在不同版本的erlang和rabbitmq上
2、网络环境不稳定,比如:广域网
插件会在本地服务器创建queue(存需要同步给其他服务器的信息的),由插件将信息同步给其他服务器
会有一定的延迟,数据不一致
1.4、Shovel插件(使用不多,了解)
Shovel与Federation具备的数据转发功能类似
Shovel能够可靠、持续地从一个Broker中的队列(作为源端,即source)拉取数据并转发至另一个Broker中的交换器(作为目的端,即destination)。
Shovel可以翻译为“铲子”,是一种比较形象的比喻。这个“铲子”可以将消息从一方“挖到”另一方
Shovel的主要优势:松耦合、支持广域网、高度定制
1.5、Federtation、Shovel、cluster的区别和联系
3、rabbitmq运行出错,查看日志
4、常用管理命令
4.1、查看节点状态
rabbitmqctl status
4.2、停止运行rabbitmq的Erlang虚拟机和rabbitmq服务应用
rabbitmqctl stop [pid_file]
如果指定了pid_file,还需要等待指定进程的结束。
pid_file是通过调用rabbitmq-server命令启动rabbitmq服务时创建的,默认情况下存放于Mnesia目录中。
如果使用rabbitmq-server -detach这个带有-detach 后缀的命令来启动rabbitmq服务则不会生成pid file文件。
4.3、停止rabbitmq服务应用
rabbitmqctl stop_app
但是Erlang虚拟机还是处于运行状态。
此命令的执行优先于其他管理操作(这些管理操作需要先停止rabbitmq应用),eg:rabbitmqctl reset
4.4、启动rabbitmq服务应用
rabbitmqctl start_app
此命令典型的用途是在执行了其他管理操作之后,重新启动之前停止的rabbitmq应用,eg:rabbitmqctl reset
4.5、将rabbitmq节点重置还原到最初状态
rabbitmqctl reset
eg:从集群中删除此节点、从管理数据库中删除所有的配置数据、删除所有的持久化消息
执行此命令前必须先执行rabbitmqctl stop_app
4.6、强制将rabbitmq节点重置还原到最初状态
rabbitmqctl force_reset
此命令不论当前管理数据库的状态和集群配置时什么,都会无条件的重置节点,
只能在数据库或集群配置已损坏的情况下使用。
5、集群管理命令
5.1、将节点加入到指定集群中
rabbitmqctl [-n nodename] join_cluster {cluster_node} [--ram]
在这个命令执行前需要停止rabbitmq应用并重置节点
-n nodename:指定需要操作的目标节点,eg:rabbit@node1
cluster_node:需要加入的集群节点名,格式同上
--ram:集群节点类型,有两种类型:ram|disc,默认为disc
ram:内存节点,所有的元数据都存储在内存中
disc:磁盘节点,所有的元数据都存储在磁盘中
5.2、查看集群状态
rabbitmqctl cluster_status
5.3、修改集群节点的类型
rabbitmqctl change_cluster_node_type {disc|ram}
使用此命令前要停止rabbitmq应用
5.4、将节点从集群中删除,允许离线执行
rabbitmqctl forget_cluster_node [--offiine]
5.5、在集群中的节点应用启动前咨询clusternode节点的最新信息,并更新相应的集群信息
rabbitmqctl update_cluster_nodes {clusternode}
这个和join_cluster不同,它不加入集群。
5.6、确保节点可以启动,即使它不是最后一个关闭的节点
rabbitmqctl force_boot
5.7、设置集群名称
rabbitmqctl set_cluster_name {name}
集群名称在客户端连接时会通报给客户端。
集群名称默认是集群中第一个节点的名称,通过这个命令可以重新设置。
2.1.3.3 持久化机制、内存/磁盘控制
1、rabbitmq持久化机制
rabbitmq的持久化分为队列持久化、消息持久化和交换机持久化
不管是持久化的消息还是非持久化的消息都可以被写入到磁盘
非持久化的消息在内存不够用时,有一部分数据会持久化到磁盘;重启之后,这些数据是不存在的
1.1、队列持久化
队列的持久化是在定义队列时的durable参数来实现的,durable为true时,队列才会持久化。
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
//第二个参数设置为true,即durable=true
channel.queueDeclare("queue1", true, false, false, null);
持久化的队列在管理界面可以看到有个“D”的标识
1.2、消息持久化
消息持久化通过消息的属性deliveryMode来设置是否持久化,在发送消息时通过basicPublish的参数传入。
//通过传入MessageProperties.PERSISTENT_TEXT_PLAIN就可以实现消息持久化
channel.basicPublish("", "queue1", MessageProperties.PERSISTENT_TEXT_PLAIN, "persistent_test_message".getBytes());
1.3、交换器持久化
同队列一样,交换器也需要在定义时设置持久化标识,否则在broker重启后将丢失
//durable为true则开启持久化
Exchange.DeclareOk exchangeDeclare(String exchange,String type,boolean durable)throws IOException;
2、rabbitmq内存控制
当服务器使用内存超过最大内存(阈值,可配置的)时,或达到内存换页阈值时,或磁盘使用率达到阈值时,rabbitmq都不再接收消息
内存换页:将目前内存中的持久化、非持久化的消息都放入磁盘,因持久化的消息本身就在磁盘中有了,就不会再存一份,放入磁盘后,会将内存中的消息清除掉
默认情况下,在内存到达内存阈值的50%时会进行换页动作。
也就是说,在默认的内存阈值为0.4的情况下,当内存超过0.4 * 0.5 =0.2 时,会进行换页动作。
可以通过在配置文件中配置vm_memory_high_watermark_paging_ratio项来修改此值
vm_memory_high_watermark.relative=0.4
vm_memory_high_watermark_paging_ratio=0.75
以上配置将会在rabbitmq内存使用率达到30%时进行换页动作,并在40%时阻塞生产者。
当vm_memory_high_watermark_paging_ratio的值大于1时,相当于禁用了换页功能。
2.1、内存告警
当内存使用超过配置的阈值或者磁盘剩余空间低于配置的阈值时,rabbitmq会暂时阻塞客户端的连接,
并停止接收从客户端发来的消息,以此避免服务崩溃,客户端与服务端的心跳检测也会失效。
当出现内存告警时,可以通过管理命令临时调整内存大小
rabbitmqctl set_vm_memory_high_watermark <fraction>
fraction为内存阈值,rabbitmq默认值为0.4,表示当rabbitmq使用的内存超过40%时,就会产生告警并阻塞所有生产者连接。
通过此命令修改的阈值在broker重启后将会失效,通过修改配置文件的方式设置的阈值则不会在重启后消失,但需要重启broker才会生效。
配置文件地址:/etc/rabbitmq/rabbitmq.conf
vm_memory_high_watermark.relative = 0.4
#vm_memory_high_watermark.absolute = 1GB
rabbitmq提供relative或absolute两种配置方式
relative:相对值,即前面的fraction,建议取值在0.4~0.66之间,不建议超过0.7
absolute:单位为KB、MB、GB,对应的命令是:
rabbitmqctl set_vm_memory_high_watermark absolute <value>
3、磁盘告警
当磁盘剩余空间低于确定的阈值时,rabbitmq同样会阻塞生产者,这样可以避免因非持久化的消息持续换页而耗尽磁盘空间导致服务崩溃。
默认情况下,磁盘阈值为50MB,表示当磁盘剩余空间低于50MB时,会阻塞生产者并停止内存中消息的换页动作。
这个阈值的设置可以减小,但不能完全消除因磁盘耗尽而导致崩溃的可能性。
eg:在两次磁盘空间检测期间内,磁盘空间从大于50MB被耗尽到0MB。
一个相对谨慎的做法是将磁盘阈值设置为与操作系统所显示的内存大小一致。
通过命令可以临时调整磁盘阈值
rabbitmqctl set_disk_free_limit <disk_limit>
rabbitmqctl set_disk_free_limit_mem_ralative <fraction>
disk_limit为固定大小,单位为KB、MB、GB
fraction为相对比值,建议的取值为1.0~2.0之间
对应的配置如下:
disk_free_limit.ralative=2.0
#disk_free_limit.absolute=50mb
2.1.3.4 消息可靠性和插件化机制
1、rabbitmq消息可靠性
一般是业务系统接入消息中间件时首要考虑的问题;
一般通过三个方面保障:
发送可靠性:确保消息成功发送到Broker
存储可靠性:Broker对消息持久化,确保消息不会丢失
消费可靠性:确保消息成功被消费
1.1、发送可靠性
一般消息发送可靠性分为三个层级:
At most once:最多一次,消息可能会丢失,但绝不会重复传输
At least once:最少一次,消息绝不会丢失,但可能会重复传输
Exactly once:恰好一次,每条消息肯定会被传输一次且仅传输一次
Rabbitmq支持其中的“最多一次”和“最少一次”
其中“最少一次”投递实现需要考虑以下这几个方面的内容:
1、消息生产者需要开启事务机制或者publisher confirm机制,以确保消息可以可靠地传输到rabbitmq中。
2、消息生产者需要配合使用mandatory参数或者备份交换器来确保消息能够从交换器路由到队列中,进而能够保存下来而不会被丢弃。
参考代码:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a132\confirm\Producer.java
// 进入confirm模式, 每次发送消息,rabbtiqm处理之后会返回一个对应的回执消息
AMQP.Confirm.SelectOk selectOk = channel.confirmSelect();
“最多一次”的方式,生产者随意发送,不过这样很难确保消息会成功发送。
1.2、消费可靠性
消费者在消费消息的同时,需要将autoAck设置为false,然后通过手动确认的方式去确认已经正确消费的消息,
以免在消费端引起不必要的消息丢失
参考代码:E:\meWork\study\project\subject-2\subject-2-mq\rabbitmq-java\src\main\java\com\study\rabbitmq\a132\confirm\Consumer.java
2、rabbitmq插件机制
rabbitmq支持插件,通过插件可以扩展多种核心功能:
支持多种协议、系统状态监控、其它AMQP 0-9-1交换类型、节点联合等。
许多功能都是通过插件实现的。
1、通过命令查看rabbitmq内置插件列表:rabbitmq-plugins list
2、通过rabbitmq-plugins命令启用或禁用插件
启用:rabbitmq-plugins enable plugin-name
禁用:rabbitmq-plugins disable plugin-name
2.1.3.5 饿了么外卖场景,分布式事务解决方案
1、美团点评系统架构
2、MQ实现分布式事务
1、可靠生产
保证消息一定发送到rabbitmq服务
实现方法:在生成订单的同一事务中,增加一个记录表,记录每一条发往MQ的数据以及它的发送状态
为了避免出现MQ的回执没收到、或者消息状态修改失败等特殊情况,可以定时检查记录表,没法送成功的,再次重发
2、可靠消费
保证消息取出来一定正确消费掉,最终多方数据达到一致。
实现方法:开启手动ACK模式。由消费者控制消息的重发/清除/丢弃。
为防止重复消费,根据ID或业务数据,判断数据是否重复,重复就忽略(幂等性)。
消息丢弃(或转移到死信队列DLQ):当重试次数过多、消息内容格式错误等情况,通过线上预警机制通知运维人员
3、MQ实现分布式事务优缺点
优点:通用性强、扩展性强、方案成熟
缺点:只适合异步场景、消息处理会有延迟,需要业务上能够容忍
在实际生产环境中,尽量避免使用分布式事务;
尽量将非核心事务做成异步
4、分布式事务解决方案的理论依据
CAP理论
BASE理论
2PC协议
3PC协议
Paxos算法
Raft一致性协议