RabbitMQ 如何保证消息不丢失?
RabbitMQ一般情况很少丢失,但是不能排除意外,为了保证我们自己系统高可用,我们必须作出更好完善措施,保证系统的稳定性。
-
消息持久化
-
ACK确认机制
-
设置集群镜像模式
-
消息补偿机制
-
消息入库:顾名思义就是将要发送的消息保存到数据库中。
-
事务消息机制:由于会严重降低性能,所以一般不采用这种方法
-
confirm消息确认机制
消息丢失是系统常见的故障,还建议这几方面
-
监控 ,监控系统对消息发送情况监控
-
核对 ,有核对系统对每笔数据核对有异常就报警(通过邮件、短信、微信 等等)
-
值班,每天值班 互联网公司都有默认的值班制度
在推荐一篇文章比较详细 https://blog.csdn.net/hsz2568952354/article/details/86559470
redis的场景数据类型和应用场景
1. String: 一般做一些复杂的计数功能的缓存
2. List: 做简单的消息队列的功能
3. Hash: 单点登录
4. Set: 做全局去重的功能
5. SortedSet: 做排行榜应用,取TopN操作;延时任务;做范围查找
应用场景
String类型是最基础的一种key-value存储形式,value其实不仅仅可以是String,也可以是数值类型。常常用来做计数器这类自增自减的功能,可用在B站或头条上 粉丝数、关注数、点赞等。
也可以用在分布式session 用户的登录信息缓存在redis中
key:value
key加密过的签名
value就是对应用户信息json格式存储
一般项目订单记录就是放到redist里list中,需要支持分页查询,减少对mysql的查询压力
Java的模板设计模式
定义:一个操作算法中的框架,而将这些步骤延迟加载到子类中。
本质就是固定算法框架
解决问题:让父类控制子类方法的调用顺序,有种逆向思维
模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
1)模板模式(Template Pattern),在一个抽象类定义类执行它的方法的模版。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
2)简单来说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
3)这种类型的设计模式属于行为型模式。
模板类+钩子接口+匿名内部类 (记住这3个模板核心你就懂了)
maven依赖包有冲突怎么解决
Maven冲突简而言之就是需要的Maven版本和实际导入的版本不一致,从而导致了各种问题。
打印依赖树
mvn dependency:tree > tree.txt
使用Maven helper 查看依赖冲突 (插件都牛逼)
使用exclusion排除依赖 (这个单词很重要)
推荐一个Idea的插件,Maven Helper,
-
提供可视化的Maven树状视图。
-
可以一键搜索所有包含该包的父包。
-
右键直接排出
分布式缺点
1、架构设计变得复杂,事务不好处理(分布式事务)
2、部署服务复杂话,启动需要很久
3、系统的吞吐量会变大,但是响应时间会变长
5、架构复杂导致学习曲线变大
6、测试和查错的复杂度大,因为链路太长环境太多,需要花时间定位具体在什么服务上在物理在什么机器上
8、最麻烦的是消息不知道落地哪台机器上了,大公司有分布式日志框架来解决这个问题TraceID
消息队列-如何保证消息的顺序性?
RabbitMQ:拆分多个queue,每个queue一个consumer,就是多一些queue而已,确实是麻烦,或者就是一个queue,但是对应一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底层不同的worker来处理。
下图为:一个consumer 对应 一个 queue,这样就保证了消息消费的顺序性。
消息队列的优缺点
优点:异步、解耦、削峰
缺点:1)系统可用性降低
外部依赖的系统多了,增加了消息队列系统。
2)系统复杂度提高
怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?
3)一致性问题
数据可能不一致。
如何保证消息队列的高可用?
镜像集群模式
镜像集群模式是RabbitMQ的高可用模式,和普通的集群模式不一样的是,你创建的queue无论元数据还是queue里的消息都会存在与多个实例中,然后每次你写消息到queu的时候,都会自动把消息推送到多个实例的queue中进行消息同步。
这样的好处在于,你任何一个机器宕机了,别的机器都可以用。坏处在于,性能开销提升,消息同步所有的机器,导致网络带宽压力和消耗增加,第二就是没有什么扩展性科研,如果某个queue负载很重,你加机器,新增的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue
如何保证消息不被重复消费?如何保证消息消费的幂等性?
让每个消息携带一个全局的唯一ID,即可保证消息的幂等性,具体消费过程为:
1、消费者获取到消息后先根据id去查询redis/db是否存在该消息
2、如果不存在,则正常消费,消费完毕后写入redis/db
3、如果存在,则证明消息被消费过,直接丢弃。
如何保证消息不丢失(可靠性传输)
生产者没有成功把消息发送到MQ
a、丢失的原因:因为网络传输的不稳定性,当生产者在向MQ发送消息的过程中,MQ没有成功接收到消息,但是生产者却以为MQ成功接收到了消息,不会再次重复发送该消息,从而导致消息的丢失。
b、解决办法: 有两个解决办法:事务机制和confirm机制,最常用的是confirm机制。
具体解决办法
RabbitMQ接收到消息之后丢失了消息
a、丢失的原因:RabbitMQ接收到生产者发送过来的消息,是存在内存中的,如果没有被消费完,此时RabbitMQ宕机了,那么再次启动的时候,原来内存中的那些消息都丢失了。
b、解决办法:开启RabbitMQ的持久化。当生产者把消息成功写入RabbitMQ之后,RabbitMQ就把消息持久化到磁盘。结合上面的说到的confirm机制,只有当消息成功持久化磁盘之后,才会回调生产者的接口返回ack消息,否则都算失败,生产者会重新发送。存入磁盘的消息不会丢失,就算RabbitMQ挂掉了,重启之后,他会读取磁盘中的消息,不会导致消息的丢失。
c、持久化的配置:
第一点是创建 queue 的时候将其设置为持久化,这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是它是不会持久化 queue 里的数据的。
第二个是发送消息的时候将消息的 deliveryMode 设置为 2,就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。
消费者弄丢了消息
a、丢失的原因:如果RabbitMQ成功的把消息发送给了消费者,那么RabbitMQ的ack机制会自动的返回成功,表明发送消息成功,下次就不会发送这个消息。但如果就在此时,消费者还没处理完该消息,然后宕机了,那么这个消息就丢失了。
b、解决的办法:简单来说,就是必须关闭 RabbitMQ 的自动 ack,可以通过一个 api 来调用就行,然后每次在自己代码里确保处理完的时候,再在程序里 ack 一把。这样的话,如果你还没处理完,不就没有 ack了?那 RabbitMQ 就认为你还没处理完,这个时候 RabbitMQ 会把这个消费分配给别的 consumer 去处理,消息是不会丢的。