RabbitMQ简介

MQ优点

异步处理
应用解耦
流量削峰==》缓解短时间内的高并发请求
日志处理
消息通讯

MQ缺点

系统可用性降低
系统复杂度提高(数据一致性,重复消费,可靠传输)

技术选型

中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;
大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。
如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高。

关注点ActiveMQRocketMQRabbitMQKafkaZeroMQ
使用场景高并发、高负载以及高吞吐超高并发、高吞吐可以支撑高并发、高吞吐、性能很高专为超高吞吐量的实时日志采集、实时数据同步、实时数据计算等场景来设计,配合实时计算技术(比如Spark Streaming、Storm、Flink)使用的较多
开发语言JavaJavaErlangScala/JavaC
维护者ApacheAlibabaSpringApache
订阅形式点对点(p2p)、广播(发布-订阅)基于topic/messageTag以及按照消息类型、属性进行正则匹配的发布订阅模式direct, topic ,Headers和fanout基于topic以及按照topic进行正则匹配的发布订阅模式点对点(p2p)
持久化支持少量堆积支持大量堆积支持少量堆积支持大量堆积不支持
顺序消息不支持支持不支持支持不支持
性能稳定性一般较差很好
集群支持简单集群模式,比如’主-备’,对高级集群模式支持不好支持简单集群,'复制’模式,对高级集群模式支持不好镜像模式天然的‘Leader-Slave’无状态集群,每台服务器既是Master也是Slave不支持
管理界面一般一般较好
社区活跃度

消息的顺序问题

(1)保证生产者 - MQServer - 消费者是1:1:1的关系
(2)从业务层面来保证消息的顺序而不仅仅是依赖于消息系统
(3)一个 queue,对应一个 consumer,然后这个 consumer 内部用内存队列做排队,分发给底层不同的 worker 来处理

消息的重复问题

造成消息重复的根本原因是:网络不可达。
消费端处理消息的业务逻辑保持幂等性。
在写入消息队列的数据做唯一标示,消费消息时,根据唯一标识判断是否消费过。

RabbitMQ

服务间异步通信
顺序消费
定时任务
请求削峰

RabbitMQ基本概念

Broker:消息队列服务器实体
Exchange:交换机
Queue:队列
Binding:绑定交换机和队列
RoutingKey:路由关键字
Vhost:虚拟broker,独立权限系统
Producer:生产者
Consumer:消费者
Channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务

消息分发

round-robin

direct

路由键完全匹配

topic

*:匹配一个字符
#:匹配多个字符

headers

消息携带的Hash是需要全部匹配(all),还是仅匹配一个键(any)就可以了。

x-match=all
x-match=any

fanout

广播

channel

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

AMQP事务

channel.txSelect();  
channel.txCommit(); 
channel.txRollback();   

发送方确认模式

生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,broker就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了。
如果消息和队列是可持久化的,那么确认消息会在将消息写入磁盘之后发出,broker回传给生产者的确认消息中delivery-tag域包含了确认消息的序列号,此外broker也可以设置basic.ack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理。

//串行的confirm
channel.confirmSelect();  
if(channel.waitForConfirms()) {
	System.out.println("发送成功"); 
}
//批量confirm模式
channel.confirmSelect();  
channel.waitForConfirmsOrDie();  
channel.confirmSelect();  
channel.addConfirmListener(new ConfirmListener() { 
	public void handleNack(long deliveryTag, boolean multiple) throws IOException{};
	public void handleAck(long deliveryTag, boolean multiple) throws IOException{};
});

接收方确认机制

boolean autoAck = false;

消息持久化

使用非常快速的存储系统以支持全持久化(例如使用 SSD)。
仅对关键消息作持久化处理(根据业务重要程度),且应该保证关键消息的量不会导致性能瓶颈。
Exchange持久化,Durable=true
Queue持久化,Durable=true
Message持久化,deliveryMode=2

集群

  1. 单一模式
  2. 普通模式:对于Queue来说,消息实体只存在于其中一个节点,A、B两个节点仅有相同的元数据,即队列结构。
    当消息进入A节点的Queue中后,consumer从B节点拉取时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer。
    当A节点故障后,B节点无法取到A节点中还未消费的消息实体。
  3. 镜像模式:消息实体会主动在镜像节点间同步,而不是在consumer取数据时临时拉取。
    降低系统性能。
    如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。
ha-modeha-param
all
exactlycount
nodesnodeNames

ha-sync-mode:进行队列中消息的同步方式,有效值为automatic和manual

有几百万消息持续积压几小时,说说怎么解决?

  1. 临时紧急扩容
    先修复 consumer 的问题,确保其恢复消费速度,然后将现有 consumer 都停掉。
    新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍的 queue 数量。
    写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue。
    临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。
    等快速消费完积压数据之后,得恢复原先部署的架构,重新用原先的 consumer 机器来消费消息。

数据过期未消费直接被丢弃了怎么办?

将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入到 mq 里面去

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值