如何避免消息重复消费
RocketMQ:给每个消息分配了一个MessageID。这个MessageID就可以作为消费者判断幂等的依据。这种方式不太建议,原因是在高并发场景下这个MessageID不保证全局唯一性。
最好由业务方创建一个与业务相关的全局唯一的ID来区分消息,避免重复消费。
RabbitMQ与Kafka都未提供MessageID.
消息的顺序:
RocketMQ对消息提供有序消息,但只保证局部有序,不保证全局有序。producer中可以选择队列,consummer中必须注册一个MessageListenOrderly监听,普通方式的监听是不能保证顺序的。生产者把一组有序的消息放到一个队列当中,而消费者一次消费整个队列当中的消息。
但是RabbitMQ和kafka都未提供完整的机制来实现消息顺序。
RabbitMQ:要保证上标exchange只对应一个队列,并且一个队列只对应一个消费者。当然这会影响性能。
kafka:生产者保证一组消息发送到一个partition里面,保证Topic下只对应一个消费者。
如何保证消息的高效读写
零拷贝:kafka和RocketMQ都是通过零拷贝技术来优化文件读写的。
应用程序跑在用户空间中,用户空间不能直接访问内核空间,传统文件复制到用户
零拷贝分两种方式:mmap和transfile(文件传输过程中直接使用DMA进行优化),java中的MappedByteBuffer就是使用的mmap的方式,而FileChannel的底层就是使用了transfile来操作。mmap适合操作比较小的文件,文件大小不要超过1.5G-2G,transfile则不进行限制。RockeMQ当中使用mmap方式来对他的文件进行读写,commitlog文件大小为1G,如果写满再生成一个1G的文件。
在kafka中,它的index日志文件也是使用mmap的方式来读写的,在其它日志文件中,并没有使用零拷贝的方式。kafka使用transfile方式将硬盘数据加载到网卡。
如何设计一个MQ:
1、实现一个单机的队列数据结构。高效、可扩展。
2、将单机队列扩展成为分布式队列。分布式集群管理
3、基于Topic定制消息路由策略。-发送者路由策略,消费者与队列对应关系,消费者路由策略
4、实现高效的网络通信。-Netty Http
5、规划日志文件,实现文件高效读写。-零拷贝、顺序写。服务重启后,快速还原运行现场。
6、定制高级功能,死信队列、延迟队列、事务消息等等。贴合实际,随意发挥。