热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用RabbitMQ传输大文件,保证其完整性

最近计划用RabbitMQ传输文件,对于容量超过1G的大文件,肯定需要对文件进行分块传输;如果某一块丢失了,或者有损坏,必须有一种机制,通知发送方重新发送。Direct和Topic模式都可以用。

最近计划用RabbitMQ传输文件,对于容量超过1G的大文件,肯定需要对文件进行分块传输;如果某一块丢失了,或者有损坏,必须有一种机制,通知发送方重新发送。Direct和Topic模式都可以用。下面是我的研习和设计思路。

RabbitMQ本身提供的确认机制

RabbitMQ通过Publish Confirm和Consumer Acknowledgement机制,让发送方和接收方分别与broker产生确认关系;由于是异步的,发送方和接收方并不需要互相确认。下面简单说明几种场景:

  1. 生产者Publisher通过confirm.select方法设置channel(通道)confirm,消息到达broker后被放入指定的队列Queueu_A,broker发送basic.ack方法给生产者Publisher,代表消息已被broker正确接收。如下图所示:

    这里写图片描述

  2. 开启Publish Confirm机制,message A 到达broker后,Erlang进程发生错误,导致message A无法转发到指定队列queue_A中,此时broker会发送basic.nack方法给发送方,表示无法处理该消息。如下图所示:

    这里写图片描述

  3. 消息message A要求持久化到磁盘,broker要等到消息存盘完成后,才会给生产者发送basic.ack方法,告知消息已经被正确接收。如下图所示:

    这里写图片描述

  4. 生产者调用basic.Publish发送消息,设置mandatory标志位为true,当broker发现指定队列Queue_A与Exchange并未绑定,导致无法路由,无法投递时,broker会给生产者发送basic.return方法告知找不到对应的队列,生产者就不会认为message A 被接收了,它会选择重发,或者其他处理。值得说明的是mandatory不需要启动Publish Confirm机制。如下图所示:

    这里写图片描述

  5. RabbitMQ官网上探讨了下面一种情景,说明开启了Publish Confirm的好处。如下图所示。

    • 生产者Publisher发送持久化的消息message A,broker接收到后投送到队列Queue_A中。
    • 此时broker将该消息推送给消费者和存盘这2个动作可能同时发生, 消费者接收到该消息后发送了确认acknowledge。
    • 但是broker异常重启了没有收到,此时message A的存盘动作还未完成
    • 结果是消息message A丢失了。broker重启后,消费者重连。
    • 事实上消费者已经收到message A 了,但逻辑上broker由于没有收到acknowledge,应当重新deliver message A的,不过该消息已经丢失了。
    • 设置了Publish Confirm机制后,生产者也不会收到basic.ack方法,所以它知道该消息可能没有到达broker,它可以重发一次,从而避免了broker无消息可deliver的尴尬。

    这里写图片描述

还得根据业务情况分析

RabbitMQ的确保到达机制比较完善,设计也很合理,但使用过程中它涉及到confirm.select,basic.ack,basic.nack,basic.return方法以及consumer的acknowledge,比较麻烦,而且这是MQ层面的机制,并不能保证大文件传输的数据完整性。

例如:传递8K大小的文件分块,是否丢失bit数据的校验;即使消息完全正确接收,但由于校验失败,如何通知发送端重发该分块;所以面对大文件的传输不能依靠RabbitMQ本身提供的消息确认机制;而要从业务层面考虑。

确保到达的核心是合理的重传机制

文件传输业务对大文件进行分块,编号,多线程并发传输,哈希效验是必然的选择,断点续传需要记录当前的发送状态也必不可少。那么下面来重点考虑重传;

为了保证文件传输性能,采用多线程多通道并发传输;发送分块与分块确认还必须是异步的;这一层面就不要考虑RabbitMQ本身的确认机制,可以关掉。

可以模仿流媒体传输协议RTSP,创建控制通道,和数据通道;将文件分块抽象成任务,创建任务池,发送线程从任务池中获取任务,通过控制通道发送任务相关信息,通过数据通道发送任务;接收线程接收任务并验证,存盘;如果必要通过控制通道告知发送方需要重发,下面是程序基本结构图:(以2线程为例)

这里写图片描述

为了提升效率,发送线程会提前领取(n=(int)(任务总数/线程数))个任务,发送线程只负责发送任务,由控制线程来确定该任务是否完成,是否需要重新分配发送。由于是并发发送的,因此可能是乱序的,所以通过Id号进行批量确认应该不可行。

下图为了表示运行过程特意设计为顺序的,实际上发送方无须收到block1的确认消息,即可发送block2。
这里写图片描述

具体开发过程中还有很多细节需要优化

  • 如果某一个任务始终发送不成功,需要考虑发送时间和次数限制,如果超过限制,就应该保存状态,退出发送,断开连接;等待下次续传。
  • 接收方每一个任务成功都发送确认消息,控制线程检查任务是否发送成功,采用轮询,必然会消耗CPU时间。是不是可以采用不发成功确认,只发失败确认,控制线程根据失败任务Id取得该任务,分发给发送线程重发。
  • 接收方如何知道,其实5号任务,发送方已经忘了发,或者由于逻辑的原因跳过了发送。

余之拙见,欢迎批评指正。


推荐阅读
  • 线程漫谈——线程基础
    本系列意在记录Windwos线程的相关知识点,包括线程基础、线程调度、线程同步、TLS、线程池等。进程与线程理解线程是至关重要的,每个进程至少有一个线程,进程是线程的容器,线程才是真正的执行体,线程必 ... [详细]
  • 三、查看Linux版本查看系统版本信息的命令:lsb_release-a[root@localhost~]#lsb_release-aLSBVersion::co ... [详细]
  • 设计完成后,将所完成的作品交由老师检查。管理进程接收申请进入的信号,在消息队列中取下申请进入队列的用户进程的信息,针对当前临界区状态,写一个回馈信息 ... [详细]
  • RabbitMQ的消息持久化处理
    1、RabbitMQ的消息持久化处理,消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢——消息持久化。2、auto ... [详细]
  • 讨伐Java多线程与高并发——MQ篇
    本文是学习Java多线程与高并发知识时做的笔记。这部分内容比较多,按照内容分为5个部分:多线程基础篇JUC篇同步容器和并发容器篇线程池篇MQ篇本篇 ... [详细]
  • 近期看见一篇来自Intel的很有意思的分析文章,作者提到在他向45名与会的各公司程序员开发经理战略师提问“什么是实施并行编程的最大障碍”时,下面五个因素 ... [详细]
  • 分布式系统:并发系统概述
    分布式系统:并发系统概述分布式系统由多个独立的代码片段组成,它们在多个位置的许多处理节点 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 在2022年,随着信息化时代的发展,手机市场上出现了越来越多的机型选择。如何挑选一部适合自己的手机成为了许多人的困扰。本文提供了一些配置及性价比较高的手机推荐,并总结了选择手机时需要考虑的因素,如性能、屏幕素质、拍照水平、充电续航、颜值质感等。不同人的需求不同,因此在预算范围内找到适合自己的手机才是最重要的。通过本文的指南和技巧,希望能够帮助读者节省选购手机的时间。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 也可以直接用#opkginstalltftpd-hpa会直接先下载再自动安装。最后用#opkglist-installed|greptftpd-hpa来查看是不是 ... [详细]
  • 随着分布式系统的规模和复杂度提高,往往会出现如下问题:(1)系统间同步通信,客户端发出调用后,必 ... [详细]
author-avatar
浅浅的思恋的小媳妇
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有