消息队列面试题

总结

为什么使用消息队列

解耦、异步、削峰

如何选择合适的消息队列

如果对于消息队列的功能和性能要求不是很高,那么RabbitMQ就够了,开箱即用。
如果系统使用消息队列主要场景是处理在线业务,比如在交易系统中用消息队列传递订单,RocketMQ的低延迟和金融级的稳定性就可以满足。
要处理海量的消息,像收集日志、监控消息或是前端的埋点这类数据,或是你的应用场景使用了大数据、流计算相关的开源产品,那么Kafka就是最合适的。
如果数据量很大,同时不希望有Kafka的高延迟,刚好业务场景是金融场景。RocketMQ对Topic运营不太友好,特别是不支持按照Topic删除失效的消息,以及不具备宕机Failover能力。那么Pulsar可能就是最合适的。

RocketMQ

RocketMQ出自阿里公司的开源产品,用java语言实现,在设计时参考了Kafka,并做出了自己的一些改进,消息可靠性上比Kafka更好,经过多次双十一的考验,性能和稳定性还是值得信赖的,RocketMQ在阿里集团被广泛应用在订单、交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景

优点
  1. 单机吞吐量:十万级;
  2. 可用性非常高,分布式架构;
  3. 消息可靠性:经过参数优化配置,消息可以做到0丢失,RocketMQ的所有消息都是持久化的,先写入PAGECACHE,然后刷盘,可以保证内存与磁盘都有一份数据;
  4. 功能支持:MQ功能较为完善,还是分布式的,拓展性好;
  5. 支持10亿级别的消息堆积,不会因为堆积导致性能下降;
  6. 源码是java,我们可以自己阅读源码,定制自己公司的MQ,可以掌控。
缺点
  1. 支持的客户端语言不多,目前是java及c++,其中c++不成熟;
  2. 社区活跃度一般,作为国产的消息队列,相比国外的比较流行的同类产品,在国际上还没有那么流行,与周边生态系统的集成和兼容程度要略逊一筹;
  3. 没有在mq核心中去实现JMS等接口,有些系统要迁移需要修改大量代码。

Kafka

Apache Kafka是一个分布式消息发布订阅系统。它最初是由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统(a distributed commit log),之后成为Apache项目的一部分

优点

  1. 性能卓越,单机写入TPS约在百万条/秒,最大的优点就是吞吐量高;
  2. 可用性:非常高,Kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用;
  3. 消费者采用Pull方式获取消息,消息有序,通过控制能够保证所有消息被消费且仅被消费一次;
  4. 有优秀的第三方Kafka Web管理界面Kafka-Manager;
  5. 在日志领域比较成熟,被多家公司和多个开源项目使用;
  6. 功能支持:功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模的使用
缺点

由于“攒一波再处理”导致延迟比较高

Pulsar

Pulsar是一个用于服务器到服务器的消息系统,具有多租户、高性能等优势。
Pulsar最初由Yahoo开发,目前有Apache软件基金会管理

优点
  1. 更多功能:Pulsar Function、多租户、Schema registry、n层存储、多种消费模式和持久性能模式等;
  2. Pulsar的单个实例原生支持多个集群,可跨机房在集群间无缝地完成消息复制;
  3. 极低的发布延迟和端到端延迟;
  4. 可无缝扩展到超过一百万个topic;
  5. 简单的客户端Api,支持Java、GO、Python和C++;
缺点

正在处于成长期,流行度和成熟度相对没有那么高

RabbitMQ

RabbitMQ 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。

优点
  1. 开箱即用的消息队列,是一个相对轻量的消息队列,非常容易部署和使用;
  2. 多种协议的支持:支持多种消息队列协议,算得上是最流行的消息队列之一;
  3. 灵活的路由配置:和其他消息队列不同的是,他在producer和queue之间增加了一个exchange模块,可以理解为交换机。根据配置的路由规则将生产者发出的消息分发到不同的队列中。路由的规则非常灵活,甚至也可以自己来实现路由规则;
  4. 健壮、稳定、易用、跨平台、支持多种语言、文档齐全。RabbitMQ的客户端支持的编程语言大概是所有消息队列中最多的;
  5. 管理界面校丰富,社区比较活跃。
缺点
  1. RabbitMQ对消息堆积的处理不好,在它的设计理念里面,消息队列是一个管道,大量的消息堆积是一种不正常的情况,应当尽量去避免。当大量消息积压的时候,会导致RabbitMQ的性能急剧下降;
  2. 性能上有瓶颈,它大概每秒钟可以处理几万到十几万条消息,这个对于大多数场景足够使用了,如果对需求性能要求非常高,那么久不太合适了;
  3. RabbitMQ使用Erlang开发,Erlang学习成本还是很高的,如果后期进行二次开发,就不太容易了。
消息持久化
  1. Exchange设置持久化
  2. Queue设置持久化
  3. Message持久化发送:发送消息设置发送模式deliveryMode=2,代表持久化消息
部署方式
  1. 单节点模式:最简单的情况,非集群模式,节点挂了,消息就不能用了,业务可能瘫痪,只能等待;
  2. 普通模式:默认的集群模式,某个节点挂了,该节点上的消息不能用,有影响的业务瘫痪,只能等待节点恢复重启可用(必须持久化消息情况下)
  3. 镜像模式:把需要的队列做成镜像模式,存在于多个节点,属于RabbitMQ的HA方案;
如何保证消息不丢失
  1. 消息持久化:也就是默认把消息序列化到磁盘中,就算MQ崩溃也能恢复消息;
  2. ACK确认机制:使用Message acknowledgment机制,就是消费端消费完成要通知服务端,服务端才会把消息从内存中删除;
  3. 设置集群镜像模式:HA策略模式(1,同步至所有的;2,同步醉的的N个机器;3,只同步至符合指定名称的nodes)HA镜像队列有一个很大的缺点就是系统的吞吐量会有所下降;
  4. 消息补偿机制:消息补偿机制需要建立在消息写入DB日志,发送日志,接受日志,两者的状态必须记录,然后根据DB日志记录check消息是否消费成功,不成功就进行消息补偿措施,重新发送消息。
限流

服务端设置接收broker每次推送消息的个数,设置ack手动签收,当消费端处理完当次推送的消息后,broker会再次推送一定个数的消息,如果没处理完,就不让broker推送消息,直至消费端成功签收。

Kafka如何避免重复消费

问题产生原因

  • kafka Broker上存储的消息都有一个Offset标记,kafka的消费者是通过offset这个标记来维护当前已经消费数据,消费者每消费一批数据kafkaBroker就会更新offset的一个值,避免重复消费的一个问题。默认情况下,消息消费完成以后会自动提交offset的值避免重复消费,kafka的消费端自动提交的逻辑里边是有默认五秒的间隔,在五秒之后下一次向broker获取消息的时候来实现offset的提交,所以在consumer的消费过程中,应用程序强制被kill调或者宕机的时候可能会导致offset没有提交,从而产生重复消费的问题。
  • kafka里边有一个partitionBalance,就是把partition均衡的分配各多个消费者,consumer端会从分配的partition里边去消费消息,如果consumer在默认的五分钟以内,没办法处理完这一批消息的时候,就会触发kafka的Rebalance机制,从而导致offset自动提交失败,在重新Rebalance以后,consumer端还是会从之前没有提交的offset的位置开始去消费,从而产生重复消费的问题。

解决方法

  • 可以针对消费的消息生成一个md5值,然后存储到mysql或者redis中,再处理消息之前先去数据库中判断对应的md5值是否已经存在,如果存在就不去消费了;
    2. 提高消费端的处理性能,避免触发Balance机制。异步方式处理消息,缩短消费时长;调整消息处理的超时时间;减少从broker一次拉取消息的数量

kafka如何保证消息不丢失

producer --> broker --> consumer

第一步:producer确保消息到达broker并且成功存储

  • producer默认是异步发送消息的,可以选择把异步改成同步,这样producer就能实时知道消息发送的结果;
  • 添加异步回调函数来监听消息发送的结果,如果发送失败,可以在回调中重试;
  • producer本身提供了一个重试参数retries,如果因为网络问题或者broker故障导致发送失败,producer会自动重试

第二步:broker需要确保producer发送过来的消息是不会丢失的

正常来说只要把消息持久化到磁盘当中就可以了。但是kafka为了提升性能,采用了异步批量刷盘的实现机制,所以如果在刷盘之前系统崩溃了就会导致数据丢失
producer可以设置acks的参数结合broker的副本机制来共同保障数据的可靠性;
acks=0 ,producer不需要等待broker的响应就认为消息发送成功;
acks=1,表示broker中的leader Partition收到消息之后不等待其他的follower Partition的同步,就向producer返回确认;
acks=-1,表示broker中的leader Partition收到消息且等待ISR列表中的follower同步完成,之后再向producer返回确认;

只要producer和broker的消息可靠性得到保障,那么consumer是不太会出现消息无法消费的问题。除非是consumer在没有消费完这个消息就已经提交了offset,即便是出现这样的情况,我们也可以通过重新调整offset的值来实现重新消费

kafka高性能高吞吐的原因

  • 磁盘顺序读写:保证了消息的堆积。
  • 零拷贝:零拷贝不是说不存在拷贝,只是取消了用户缓冲区的过程。传统数据复制,磁盘文件–>内核缓冲区–>用户缓冲区–>socket的发送缓冲区–>网卡接口–>消费者进程;零拷贝:磁盘文件–>内核缓冲区–>网卡接口–>消费者进程。
  • 分区分段+索引
  • 批量压缩:多条消息一起压缩,降低带宽
  • 批量读写
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值