MQ如何保证消息不丢失
生产者:发送确认机制
mq本身:做好持久化、容灾备份-队列的副本机制
消费者:消费ack确认机制-让mq重新投递
可能消息丢失的环节
1、生产者发送消息丢失
kafka:消息发送+回调
RocketMQ:1、消息发送+回调
2、事务消息机制
RabbitMQ:1、消息发送+回调
2、手动事务:channel.txSelect()开启事务,channel.txCommit()提交事务,channel.txRollback()回滚事务。这种方式对channel是会产生阻塞,造成吞吐量下降
3、Publisher Confirm 整个处理流程跟RocketMQ的事务消息,基本一样
2、MQ主从同步消息丢失 同步和异步同步
RocketMQ:1、普通集群中,同步同步、异步同步。异步同步效率更高,但有消息丢失的风险,同步同步就不会丢失消息
2、Dledger集群-两阶段提交(当大部分Slave节点同步完成,Uncommited状态变为commited状态)
每次生产者发送消息,Dledger都会重新选举出Master节点
RabbitMQ:1、普通集群:消息是分散存储,节点之间不会主动进行消息同步
2、镜像集群:镜像集群会在节点之间主动进行数据同步,这样数据安全性会得到提高
kafka:通常都是用在允许消息少量丢失的场景。acks:0 , 1, all
3、MQ消息存盘丢失
RocketMQ:同步刷盘 异步刷盘:异步刷盘效率更高,但是有可能丢消息。同步刷盘消息安全性更高,但是效率会降低
RabbitMQ:将队列配置成持久化队列。新增的Quorum类型的队列,会采用Raft协议来进行消息同步
4、MQ消费者消费消息丢失
RocketMQ:使用默认的方式消费就行,不要采用异步方式
RabbitMQ:autoCommit -> 手动提交offset
Kafka:手动提交offset
消息队列如何保证消息可靠传输
消息可靠传输代表了两层意思,既不能多也不能少。
1.为了保证消息不多,也就是消息不能重复,也就是生产者不能重复生产消息,或者消费者不能重复消费消息
2、首先要确保消息不多发,这个不常出现,也比较难控制,因为如果出现了多发,很大的原因是生产者自己的原因,如果要避免出现问题,就需要在消费端做控制
3、要避免不重复消费,最保险的机制就是消费者实现幂等性,保证就算重复消费,也不会有问题,通过幂等性,也能解决生产者重复发送消息的问题
4、消息不能少,意思就是消息不能丢失,生产者发送的消息,消费者一定要能消费到,对于这个问题,就要考虑两个方面
5、生产者发送消息时,要确认broker确实收到并持久化了这条消息,比如RabbitMQ的confirm机制,Kafka的ack机制都可以保证生产者能正确的将消息发送给broker
6、broker要等待消费者真正确认消费到了消息时才删除掉消息,这里通常就是消费端ack机制,消费者接收到一条消息后,如6.果确认没问题了,就可以给broker发送一个ack,broker接收到ack后才会删除消息
MQ如何保证消息顺序消费
全局有序和局部有序:MQ只需要保证局部有序,不需要保证全局有序
生产者把一组有序的消息放到同一个队列当中,而消费者一次消费整个队列当中的消息
RocketMQ中有完整的设计,但是在RabbitMQ和kafka当中,并没有完整的设计,需要自己进行设计
RabbitMQ:要保证目标exchange只对应一个队里了。并且一个队列只对应一个消费者
kafka:生产者通过定制partition分配规则,将消息分配到同一个partition。Topic下只对应一个消费者
如何保证消息的高效读写
零拷贝:kafka和RocketMQ都是通过零拷贝技术来优化文件读写
传统文件复制方式:需要堆文件在内存中进行四次拷贝
零拷贝:有两种方式 mmap和transfile
mmap: MappedByteBuffer
transfile:
Java对零拷贝进行了封装,mmap方式通过MappedByteBuffer对象进行操作,而transfile通过FileChannel来进行操作
mmap适合比较小的文件,通常文件大小不要超过1.5G~2G之间
Transfile没有文件大小限制
RocketMQ当中使用mmap方式来对他的文件进行读写。commitlog 1G
在kafka当中,他的index日志文件也是通过mmap的方式来读写的。在其他日志文件当中,并没有使用零拷贝的方式
kafka使用transfile方式将硬盘数据加载到网卡
Redis持久化
|-rdb快照(save、bgsave)- save 1 ,10, save 5 ,60 、 aof命令(每条命令)
|-rdb优缺点:数据恢复快、存在数据丢失的可能-可靠性低
|-aof优缺点:文件大,数据可靠性高,数据恢复慢
|-rdb结合aof:rdb做定期的备份+aof增量的持久化
Redis 大Key问题 热Key问题
大Key问题:
Redis大key问题指的是某个key对应的value值所占的内存空间比较大,导致Redis的性能下降、内存不足、数据不均衡以及主从同步延迟等问题。
到底多大的数据量才算是大key?
没有固定的判别标准,通常认为字符串类型的key对应的value值占用空间大于1M,或者集合类型的k元素数量超过1万个,就算是大key。
Redis大key问题的定义及评判准则并非一成不变,而应根据Redis的实际运用以及业务需求来综合评估。例如,在高并发且低延迟的场景中,仅10kb可能就已构成大key;然而在低并发、高容量的环境下,大key的界限可能在100kb。因此,在设计与运用Redis时,要依据业务需求与性能指标来确立合理的大key阈值。
怎么解决:拆分
对于无法拆分的:放本地缓存
热Key问题
1、二级缓存(本地缓存)
当出现热 Key 以后,把热 Key 加载到系统的 JVM 中。后续针对这些热 Key 的请求,会直接从 JVM 中获取,而不会走到 Redis 层。这些本地缓存的工具很多,比如 Ehcache,或者 Google Guava 中 Cache 工具,或者直接使用 HashMap 作为本地缓存工具都是可以的。
2、单独迁移到热点redis集群中去。
MySQL索引跳跃
MySQL一定是遵循最左前缀匹配的,这句话在以前是正确的,但是在MySQL 8.0出现了索引跳跃扫描。
MySQL 8.0.13 版本中,对于range查询引入了索引跳跃扫描(Index Skip Scan)优化,支持不符合组合索引最左前缀原则条件下的SQL,依然能够使用组合索引,减少不必要的扫描。
举例:
表中索引为:(a,b,c)
SQL语句为:
select a from tb where c>40;
该sql不符合最左前缀匹配,在以前版本的mysql不会用到索引
原理:
首先获取a,b字段的值,例如a=1,b=1;然后构造 where a=1 and b=1 and c>40;进行范围查询
一直到扫描完了a字段所有的唯一值,b字段的所有唯一值,最后将结果合并返回;
使用该策略可以减少访问的行数,因为会跳过不符合构造范围的行。
限制条件:
不能联表查询
不能使用group by聚合,以及distinct
查询的字段必须为索引中的列