专栏首页后台技术底层理解消息队列的可靠性

消息队列的可靠性

RabbitMQ可能存在的数据丢失问题

数据丢失分为三类:

  1. 生产者:生产者写消息存在丢失或者MQ接受存在问题
  2. MQ : MQ接受到数据先暂存在内存中,消费者还没有消费,MQ挂掉,缓存丢失。
  3. 消费者:消费拉取到消息还没处理直接挂掉,但MQ以为对方收到消息。
解决方法

生产者: rabbitMQ支持事务,可以在发送中进行捕获异常,如果出现未接受异常进行回滚操作。

但是rabbitMQ事务操作太耗费性能,因为为了保证可靠性,需要同步等待机制,等待你成功。

confirm机制,先设置 channel 为confirm,如果接受到消息,回调这个接口,接受成功。如果没接收,调用回调接口,接收失败。

MQ : 防止MQ突然挂掉内存数据丢失,就需要将MQ持久化到磁盘。第一个是创建queue的时候将其设置为持久化的,这样就可以保证rabbitmq持久化queue的元数据,但是不会持久化queue里的数据;第二个是发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时rabbitmq就会将消息持久化到磁盘上去。

消费者 : rabbitmq如果丢失了数据,主要是因为你消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,rabbitmq认为你都消费了,这数据就丢了。

这个时候得用rabbitmq提供的ack机制,简单来说,就是你关闭rabbitmq自动ack,可以通过一个api来调用就行,然后每次你自己代码里确保处理完的时候,再程序里ack一把。这样的话,如果你还没处理完,不就没有ack?那rabbitmq就认为你还没处理完,这个时候rabbitmq会把这个消费分配给别的consumer去处理,消息是不会丢的。

Kafka可能存在的数据丢失问题

消费者 : 唯一可能导致消费者弄丢数据的情况,就是说,你那个消费到了这个消息,然后消费者那边自动提交了offset。关闭自动提交offset,在处理完之后自己手动提交offset,就可以保证数据不会丢。同时自己要用程序保证幂等性。

kafka : kafka某个broker宕机,然后重新选举partiton的leader时。大家想想,要是此时其他的follower刚好还有些数据没有同步,结果此时leader挂了,然后选举某个follower成leader之后,他不就少了一些数据.

所以此时一般是要求起码设置如下4个参数:

给这个topic设置replication.factor参数:这个值必须大于1,要求每个partition必须有至少2个副本

在kafka服务端设置min.insync.replicas参数:这个值必须大于1,这个是要求一个leader至少感知到有至少一个follower还跟自己保持联系,没掉队,这样才能确保leader挂了还有一个follower吧

在producer端设置acks=all:这个是要求每条数据,必须是写入所有replica之后,才能认为是写成功了

在producer端设置retries=MAX(很大很大很大的一个值,无限次重试的意思):这个是要求一旦写入失败,就无限重试,卡在这里了

我们生产环境就是按照上述要求配置的,这样配置之后,至少在kafka broker端就可以保证在leader所在broker发生故障,进行leader切换时,数据不会丢失

生成者 : 如果按照上述的思路设置了ack=all,一定不会丢,要求是,你的leader接收到消息,所有的follower都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。

保证消息队列顺序性

rabbitmq:一个queue,多个consumer。因为多个 消费者是并行运行,最后的结果可能会乱序。

解决办法: 就是为每一个机器设置一个queue,然后如果要求有序的数据必须确保发到同一个queue中,那么数据的接受就不会乱序。

kafka:一个topic,一个partition,一个consumer,内部多线程.

kafka写到一个partition中的数据一定是有数据的。

解决办法: 一个topic,一个partition,一个consumer,内部单线程消费,写N个内存queue,然后N个线程分别消费一个内存queue即可,既消费者不要使用多线程进行处理。或者你想多线程进行处理,你可以建立一个内存队列,通过hash进任务id相同分到一个内存队列,每一个内存队列对应一个线程。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java 多线程 Thread 和 Runnable

    多线程是并行计算实现的方式, 但是在单cpu中实际上没有真正的并行,只不过是多个任务通过cpu的快速轮转,产生多任务同一时间运行的错觉.而其中的任务就是进程. ...

    黑白格
  • Java 线程池原理与使用

    在java 中我们会一般要求创建线程必须使用线程池,因为这样可以避免资源消耗,通过重复利用已经创建的线程来降低线程创建和销毁所造成的消耗, 其次当任务到达时任务...

    黑白格
  • java 线程池设计模式

    进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地...

    黑白格
  • node中和C++有什么关联

    参考文章-写得不错 都说node的一些底层借助了一些c++函数,到底如何交互的以及为什么会用到C++

    用户2436820
  • Python 多线程爬虫实战

    在线程中,访问一些全局变量,加锁是一个经常的过程。如果你是想把一些数据存储到某个队列中,那么Python内置了一个线程安全的模块叫做queue模...

    Python知识大全
  • 来玩Play框架05 数据库

    数据库是整个站点的数据储藏室。用户提交的数据可以存储在数据库中,以便未来使用。Play可以通过JDBC和数据库通信。我讲介绍Play和mysql数据库的连接。 ...

    Vamei
  • Dubbo on Istio 改造方案的思考

    虽然 Dubbo 是个很优秀的 SOA 框架,在国内也是非常流行,但在 service mesh 的大风下,有些跟不上时代了。一方面官方还没有给出权威的 mes...

    鲍远林
  • Dubbo on Istio 改造方案的思考

    虽然 Dubbo 是个很优秀的 SOA 框架,在国内也是非常流行,但在 service mesh 的大风下,有些跟不上时代了。一方面官方还没有给出权威的 mes...

    鲍远林
  • jQuery无缝图片横向(水平)/竖向(垂直)滚动

    jQuery的一个不错的小插件,记性越来越差了,整理一下贴在这里,方便以后Copy & Paste <!DOCTYPE html PUBLIC "-//W3C/...

    菩提树下的杨过
  • 通过一个实际案例,彻底搞懂 HashMap

    我知道大家都很熟悉hashmap,并且有事没事都会new一个,但是hashmap的一些特性大家都是看了忘,忘了再记,今天这个例子可以帮助大家很好的记住。

    南风

扫码关注云+社区

领取腾讯云代金券