MQ 学习日志(六) 保证消息的可靠性传输

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 消息的可靠性传输 简述

如何保证消息的可靠性传输(如何处理消息丢失的问题)

消息丢失的原因

  1. 生产者在写入消息到MQ的过程中,由于网络或者一些问题导致消息丢失
  2. 生产者将消息传输到MQ,但是MQ在保存消息的时候,内部问题导致消息丢失
  3. MQ收到消息之后,还未持久化到磁盘中,然后自己挂掉了,导致消息丢失
  4. 消费者获取到了这个消息,但是自己还没消费挂掉了,导致消息丢失

解决办法

生产者丢失消息
RabbitMQ

生产者将消息发送到RabbitMQ的时候,可能数据就在半路搞丢了,此时可以使用RabbitMQ的事务功能,就是生产者发送数据之前开启RabbitMQ事务(Channel.txSelect),然后发送消息,如果消息没有成功被RabbitMQ接收到,那么生产者会收到异常报错,此时就可以回滚事务(Channel.txRollback),然后重试发送消息,如果收到了消息,那么可以提交事务(channel.txCommit),但是问题是,RabbitMQ事务机制一搞,基本上吞吐量会下来,因为太耗费性能

所以一般来说,如果说确保将消息写入到RagbbitMQ的时候,可以开启Confirm模式,在生产者哪里设置开启COnfirm模式之后,每次写的消息都会分配一个唯一的id,如果RabbitMQ没能处理到这个消息,会回调一个nack接口,告知这个消息接收失败,可以重试发送消息

简单来说,启动rabbitMQ的confirm模式后,在消息的提供者方面可以写两个接口,用来做RabbitMQ的异步回调通知,一个是ack()方法,代表的是消息成功接收,另一个是nack()方法,代表的是消息未成功接收,再未成功接收时,可以调用这个方法进行重新发送消息

MQ丢失数据
RabbitMQ

解决这个问题,需要开启RabbitMQ的持久化,就是消息写入之后,会持久化到磁盘,哪怕是RabbitmQ自己挂了,但是恢复之后也是会自动读取之前存储的数据,一般数据不会丢失,但是极其罕见的是,RabbitMQ还没持久化,自己就挂了,可能会导致少量的数据丢失,这个概率比较小

设置持久化有两个步骤,第一个是queue的时候将其设置为持久化的,这样就可以保证RabbitMQ持久化queue的元数据,但是不会持久化queue里面的数据,第二个是发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化的,此时rabbitMQ就会将消息持久化到磁盘上去,必须要同时设置这两个持久化才行

而且持久化可以跟生产者的confirm机制配合起来,只有消息被持久化到磁盘之后,才会通知生产者ack了,所以哪怕是持久化到磁盘之前,rabbitMQ挂了,数据丢了,生产者收不到ack(),同样也是可以重发的

Kafka

这个其实是比较常见的一个场景,kafka的某个Broker宕机,然后重新选举partition的leader时,如果这个时候其他的follower刚好有些数据没有同步,结果此时leader挂了,然后选举某个follower成为leader之后,这样就少了一些数据

解决上述问题需要设置下面的四个参数

  1. 给topic设置replication.factor参数:这个参数值必须大于1,要求每个partition必须有至少2个副本
  2. 再kafka服务端设置min.insync.replicas参数,这个值必须大于1,这个要求是一个leader至少感知到有个follower,还跟自己保持联系,没掉队,这样才能确保leader挂了还有个follower
  3. 再producer端设置acks=all,这个要求是每条数据,必须是写入所有的replica之后,才能认为是写入成功
  4. 在product端设置retries=MAX;这个是要求一旦写入失败,就会无限重试,卡在这里

按照上述配置之后,至少再kafka broker端就可以保证再leader所在的broker发生故障,进行leader切换的时候,数据不会丢失,同时 asks=all,retries这两个参数也一样保证了生产者的消息不会丢失

消费端弄丢了数据
RabbitMQ

RabbitMQ如果丢失了数据,主要是因为消费的时候,刚消费到,还没处理,结果进程挂了,比如说重启,这样就出问题了,RabbitMQ以为消费了,但是数据没消费,这样消息就丢了

这个时候可以使用RabbitMQ提供的ack机制,简单来说,就是关闭RabbitMQ的自动Ack,通过一个Api来手动调用ack回调,每次代码处理完成之后,直接在程序里进行ack调用,这样可以极大的保证消息的消费端不会丢失

kafka

kafka导致消费者弄丢数据的情况就是当你消费到这个消息的时候,然后消费者那边自动提交了offset,让kafka认为已经消费好了这个消息,其实刚准备处理这个消息,还没来得及处理,自己就挂了,这个会导致这条消息丢失

这个保证的方式还是一样,关闭kafka自动提交offset,改为手动提交,这样就可以保证消息数据不会丢失,当然有可能出现幂等的问题,但是自己保证幂等就可以

目录
相关文章
|
4月前
|
消息中间件 存储 数据库
深入学习RocketMQ的底层存储设计原理
文章深入探讨了RocketMQ的底层存储设计原理,分析了其如何通过将数据和索引映射到内存、异步刷新磁盘以及消息内容的混合存储来实现高性能的读写操作,从而保证了RocketMQ作为一款低延迟消息队列的读写性能。
|
1天前
|
消息中间件 Java 中间件
MQ四兄弟:如何保证消息可靠性
本文介绍了RabbitMQ、RocketMQ、Kafka和Pulsar四种消息中间件的可靠性机制。这些中间件通过以下几种方式确保消息的可靠传输:1. 消息持久化,确保消息在重启后不会丢失;2. 确认机制,保证消息从生产者到消费者都被成功处理;3. 重试机制,处理失败后的重试;4. 死信队列,处理无法消费的消息。每种中间件的具体实现略有不同,但核心思想相似,都是从生产者、中间件本身和消费者三个角度来保障消息的可靠性。
10 0
|
2月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
68 3
|
2月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
34 3
|
2月前
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
202 0
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
3月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
42 0
|
4月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
156 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
4月前
|
Java 数据库连接 数据库
后端框架的学习----mybatis框架(6、日志)
这篇文章介绍了如何在MyBatis框架中使用日志功能,包括配置MyBatis的日志实现、使用log4j作为日志工具,以及如何通过配置文件控制日志级别和输出格式。
|
4月前
|
消息中间件 存储 运维
RabbitMQ-消息消费时的可靠性保障
将这些实践融入到消息消费的处理逻辑中,可以很大程度上保障RabbitMQ中消息消费的可靠性,确保消息系统的稳定性和数据的一致性。这些措施的实施,需要在系统的设计和开发阶段充分考虑,以及在后续的维护过程中不断的调整和完善。
64 0
下一篇
DataWorks