IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 54.整理RabbitMQ -> 正文阅读

[大数据]54.整理RabbitMQ

消息队列的优点?

解耦:将系统按照不同的业务功能拆分,生产者和消费者都不知道对方的存在,一个只负责发布,一个只负责取

异步:主流程只需要完成业务的核心功能,对于业务的非核心功能,将消息放入到消息之中进行异步处理,减少请求的等待,提高系统的总体性能

削峰/限流:将请求都写到消息队列中,消费服务器按照规定速度处理请求,防止请求并发过高使系统崩溃

消息队列的缺点?

系统的可用性降低:系统引用的外部依赖越多,越容易挂掉,如果mq挂了,有可能导致整个系统的崩溃

系统复杂度提高,数据一致性问题等

消息队列的选型?

RabbitMQ:中小型公司的选择,erlang语言天生具备高并发特性,管理界面用起来十分方便,社区活跃,微妙级别的延迟,基本不丢消息,吞吐量会稍微低一些,集群动态扩展困难

kafka:大型软件公司的选择,具备足够的资金搭建分布式环境,也具备足够大的数据量,当有大数据领域的实时计算,日志采集功能需求的时候使用kafka,经过参数化的配置,可以做到0丢失,吞吐量很高

RocketMQ:大型公司的选择,经过参数化配置可以做到消息0丢失,分布式扩展方便,性能可靠,但是社区活跃度一般,这个技术以后有可能被丢弃

RabbitMQ的构造?

RabbitMQ是AMQP的一个开源实现,所以内部其实也是AMQP的概念:

  • 生产者:生产消息,消息一般包含两个部分消息体和标签
  • Exchange交换机:接收生产者发送的消息,根据路由键将消息路由到绑定的队列
  • Routing Key路由键:路由键,用于指定消息的路由规则
  • Binding绑定:通过绑定可以将交换机和队列关联,会在绑定中指定路由键,通过路由键,交换机就知道将消息交给哪个队列了
  • Queue队列:用来存放消息,一个消息可以投入多个或者一个队列,多个消费者可以订阅同一队列,这时队列中的消息会被均摊到每个消费者进行处理
  • Channel信道:AMQP命令都是在信道中进行的,不管是发布消息,订阅队列还是接收消息,这些动作都是通过信道完成,因为建立TCP是非常昂贵的开销,所以引入了信道的概念,复用一条TCP连接,一个TCP可以使用多个信道,客户端建立多个channel,每个channel表示一个会话任务
  • Connection:网络连接,比如一个TCP连接
  • Consumer消费者:消费消息,消费者连接RabbitMQ服务器,订阅队列,消费消息是,只消费消息体,丢弃标签
  • Vitual Host虚拟主机:用于逻辑隔离,表示一批独立的交换机,消息队列和相关对象,同一个vhost可以由若干交换机和队列,不能有同名的交换机或队列
  • Broker服务节点:表示消息队列服务器实体,一个Broker可以看做一个RabbitMQ服务器

Exchange交换机类型?

direct:一对一,路由键必须完全匹配

fanout:把消息转发到所有绑定交换机的队列,此类型转发消息是最快的

topic:通过模糊匹配的方式对消息进行路由,可以使用*匹配一个单词,也可以使用#匹配0个或者多个单词

生产者生产消息的过程?

  • 生产者先连接到Broker,建立连接,开启信道
  • 生产者声明一个交换机,通过绑定建将交换器和队列绑定起来
  • 生产者发送消息到Broker,其中包含路由键,交换器等信息
  • 交换器根据接收到的路由键查找匹配队列,将消息放入队列,如果没有找到则丢弃或者退回给生产着,关闭信道

消费者接收消息的过程?

  • 消费者连接到Broker,建立连接,开启信道
  • 向Broker请求消费队列中 对消息,可能会设置响应的回调函数,等待Broker投递消息
  • 消费者说道消息,ack
  • Broker从队列中删除已经ack的消息,关闭信道

如何保证消息不被重复消费?

重复消费的场景:由于网络故障,消费者发出的ack并没有即使传递给消息队列,导致消息队列不知道该消息已经被消费了,然后就将消息发送给了其他的消费者,导致了消息被重复消费

  • 改造业务逻辑:可以使用乐观锁的机制,引入版本号,比对消息中的版本号与数据库的版本号
  • 基于数据库的唯一主键进行约束:消费完消息后,到一个数据库中做insert操作,如果重复消费情况出现,就会导致主键冲突,避免数据库出现脏数据
  • 通过记录关键的key,当重复消息过来的时候,先判断这个key是否已经被处理过了,这个key可以是数据库里的订单ID,也可以是rabbitmq中消息的全局id

如何保证消息不丢失,进行可靠性传输?

消息的丢失为三种:生产者丢消息,消息队列丢消息,消费者丢消息

RabbitMQ提供事务机制和确认机制来保证生产者不丢消息:

  • 事务机制:发送消息前开启事务,如果有异常,事务回滚,成功则提交事务,该方法的缺点是生产者发送消息会同步阻塞等待发送结果是成功还是失败,导致生产者发送消息吞吐量下降
  • 确认机制:confirm模式,将信道设置为confirm模式,该信道发布的所有消息都会被指派一个唯一id,一旦消息被投递到了指定的队列,broker就会发送一个确认给生产者(包含消息的唯一id),这样生产者就知道消息已经正确地道目的队列了,如果broker没能处理该消息,也会发送一个nack消息,这时就可以进行重试操作,comfirm模式是异步的

消息队列丢失数据:一般开启持久化磁盘,其配置如下:

  • 创建queue的时候将queue持久化标志durable设置为true
  • 发送消息的时候将deliveryMode设置为2

消费者丢失消息一般是因为采用自动确认模式,在该模式下,当消息被消费者接收以后,消费者会通知broker消息已经收到了,这时broker就会将消息删除,这种情况下如果消费者异常而未能处理消息,那么就会丢失该消息,解决方案为手动确认消息

  • 如果消费者接收到消息,在确认之前断开了连接或者取消订阅,broker会任务消息没有被消费,然后重写分发给下一个订阅的消费者,所以存在消息重复消费的隐患
  • 如果消费者接收到消息却还没有确认消息,连接也没有断开,broker会任务该消费者繁忙,不会给该消费者发送更多消息
  • 消息的可靠性增强了,性能就下降了,所以是否要对消息进行持久化操作,需要综合考虑
  • 如果启用了手动ack,却没有写相关手动ack的代码,会导致大量任务处于unack的状态,造成队列堆积
  • 启动消息拒绝或者发送nack后导致死循环的问题:在消息处理异常的时候,直接拒绝消息,消息会重写进入队里e,ruguo消息再次被处理的时候又被拒绝,这样就会进入死循环

如何保证消息的有序性?

方法一:拆分queue,使得一个queue值对应一个消费者,由于mq一般都可以保证内部队列先进先出,所以把需要保持先后顺序的一组消息通过某种算法撇皮到同一个消息队列中,只用一个消费者单线程区消费该队列,这样就可以保证消费者是按照顺序进行消费的了,但是使用多个消费者消费一个队列还是可能会出现顺序错乱的情况

方法二:对于多线程消费同一个队列的情况,可以使用重试机制,比如有一个微博业务场景的操作,发微博,写评论,删除微博,这三个异步操作,如果一个消费者先执行了写评论操作,这是微博都没有发,那么一定是失败的,等待一段时间,等另一个消费者,先执行发微博的操作后,再进行执行就可以成功

如何处理消息堆积的情况?

出现该问题的原因?

生产者的速度与消费者速度不匹配,消息消费失败反复重试等

解决方案?

临时扩容,快速处理积压的消息:

  • 先修复消费者的问题,确保其恢复消费速度,然后将现有的消费者停掉
  • 创建原先n倍数量的queue,写一个临时分发数据的消费者程序,将该程序部署上去消费队列中积压的数据,消费知乎,不做任何耗时处理,直接均匀轮询写入临时建好的queue中
  • 征用n倍的机器来部署consumer,每个consumer消费一个临时queue的数据
  • 等快速消费完积压的数据之后,恢复原来部署的架构,重写用原来的consumer机器消费消息

恢复队列汇总丢失的数据:如果使用的是rabbitmq,并且设置了过期时间,消息在queue积压超过了一定时间会被rabbitmq清理掉,导致数据的丢失,这种情况下,队列其实没有积压消息,而是丢失了大量消息,这种情况可以采取"批量重导"的方案来解决,在流量地峰期,写一个程序,手动查询丢失的那部分数据,然后将消息重新发送到mq里,把丢失的数据重新补回来

mq长时间未处理导致mq写满:这种情况是临时扩容方案执行太慢,此时应该使用丢弃+批量重导的方式来解决了,首先临时写个程序,连接到mq里消费数据,消费一个丢弃一个,快速消费掉积压的消息,降低mq压力,然后在流量低峰区手动查询重导丢失的这部分数据

如何保证消息队列高可用?

rabbitmq是基于主从做高可用的,有三种模式:单机(一般没人用),普通集群,镜像集群

普通集群模式

通过添加节点来线性扩展消息队列的吞吐量,队列的消息只会存放在其中一个broker上,每个实例都同步queue的元数据,消费的时候,如果连接到了另外的实例,那么该实例就会从数据实际所在实例上的queue拉取消息,就是说让集群中多个节点拉以服务某个queue的读写操作

其缺点在于无高可用性,queue所在的节点如果宕机,其他实例就无法从那个实例拉取数据,并且mq内部会产生大量的数据传输

镜像队列集群模式

正在的高可用模式,集群中包含一个主节点master和若干个从节点slave,如果master因为某种原因失效,那么按照slave加入的时间排序,资历最老的slave会被提升为新的master

镜像队列下,所有的消息只会向master发送,再由master广播给slave,所以master和slave的状态相同,比如写消息到queue时,master会自动将消息同步到各个slave的queue,如果消费者与slave建立连接并且订阅消费,其实也是从master获取消息,只不过看似是在slave上消费而已,因为消费者与salve建立连接,进行获取消息的请求,这个请求会由slave发送给master,再由master准备好数据返回slave,最后由slave投递给消费者

总结起来就是队列的元数据和消息会存在于多个实例上,也就是说每个rabbitmq节点都有这个queue的完整镜像,任何一个节点宕机,其他机器都包含了这个queue的完整数据,其他消费者都可以到其他节点上去消费数据

缺点在于:

  • 性能开销比较大,消息需要同步到所有机器上,造成网络带宽压力消耗很重
  • 非分布式,没有扩展性,如果queue的数据量达到这个机器的容量无法容纳,该方案就会存在问题

延迟队列?优先级队列?

rabbitmq的延迟队列基于死信队列和消息过期时间实现,消费者监听死信交换器绑定的队列,而不监听消息发送到的死信队列

优先级队列使用x-max-priority属性来实现,但是当消费速度大于生成速度的时候,且broker没有堆积的情况下,优先级显得没有意义

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-05-13 11:48:46  更:2022-05-13 11:50:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 5:46:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码