分布式对象存储学习笔记(七)——断点续传

分布式对象存储——原理、架构及Go语言实现 胡世杰

本章我们要实现断点续传功能。断点续传功能分两部分,分别是断点下载和断点上传。

为什么对象存储需要支持断点续传

在实验室的理想环境里网络永远通畅,对象存储系统并不需要断点续传这个功能。但在现实世界,对象存储服务在数据中心运行,而客户端在客户本地机器上运行,它们之间通过互联网连接。互联网的连接速度慢且不稳定,有可能由于网络故障导致断开连接。 在客户端上传或下载一个大对象时,因网络断开导致上传下载失败的概率就会变得不可忽视。为了解决这个问题,对象存储服务必须提供断点续传功能,允许客户端从某个检查点而不是从头开始上传或下载对象。

断点下载流程

断点下载的实现非常简单,客户端在GET对象请求时通过设置 Range头部来告诉接口服务需要从什么位置开始输出对象的数据。

接口服务的处理流程在生成对象流之前和上一章没有任何区别,但是在成功打开了对象数据流之后,接口服务会额外调用 rs.RSGetStream.Seek 方法跳至客户端请求的位置,然后才开始输出数据。
在这里插入图片描述

断点上传流程

断点上传的流程则要比断点下载复杂得多,这是由 HTTP 服务的特性导致的。客户端在下载时并不在乎数据的完整性,一旦发生网络故障,数据下到哪算哪,下次继续从最后下载的数据位置开始续传就可以了。

但是对于上传来说,接口服务会对数据进行散列值校验,当发生网络故障时,如果上传的数据跟期望的不一致,那么整个上传的数据都会被丢弃。

所以断点上传在一开始就需要客户端和接口服务做好约定,使用特定的接口进行上传,客户端在知道自己要上传大对象时就主动改用对象POST接口提供对象的散列值和大小。

接口服务的处理流程和上一章处理对象 PUT 一样,搜索6个数据服务并分别 POST临时对象接口。数据服务的地址以及返回的 uuid 会被记录在一个 token 里返回给客户端。

客户端POST对象后会得到一个 token。对 token 进行PUT可以上传数据。在上传时客户端需要指定range 头部来告诉接口服务上传数据的范围。接口服务对 token进行解码,获取6个分片所在的数据服务地址以及 uuid,分别调用 PATCH 将数据写入6个临时对象。在这里插入图片描述
在这里插入图片描述
通过 PUT上传的数据并不一定会被接服务完全接收。我们在第5章已经知道经过 RS分片的数据是以块的形式分批写入 4 个数据片的,每个数据片一次写入 8000字节,4 个数据片一共写入 32 000 字节。所以除非是最后一批数据,否则接口服务只接收 32 000 字节的整数倍进行写入。这是一个服务端的行为逻辑,我们不能要求客户端知道接口服务背后的逻辑,所以接口服务必须提供 token 的 HEAD 操作,让客户端知道服务端上该 token目前的写入进度。
在这里插入图片描述

接口服务的REST接口

接口服务的 objects 接口 GET 方法新增了 Range 请求头部,用于告诉接口服务需要的对象数据范围。
GET /objects/<object name>
请求头部
Range: bytes=<first>-
响应头部
Content-Range: bytes <first>-<size>/<size>
响应正文
first开始的对象内容

Range 请求头部定义在RFC7233 中,是HTTP/1.1协议的一部分。给GET 请求加上Range 头部意味着这个请求期望的只是全体数据的一个或多个子集。Range 请求主要支持以字节为单位的 byte Range 。byte range的格式是固定字符串“bytes=”开头,后面跟上一个或多个数字的范围,由逗号分隔。假设我们的整体数据是 10000 字节,那么合法的byte range格式可以有以下几个例子:

  • 请求最后500个字节(9500~9999): bytes–500 或 bytes-9500
  • 请求第一个和最后一个字节(字节 0和9999):bytes=0-0,-1

其他几个合法但不常见的请求第 500~999 个字节的格式。

  • bytes=500-600,601-999
  • bytes=500-700,601-999

我们的对象存储系统实现的格式是bytes=<first>-。客户端通过指定first的值告诉接口服务下载对象的数据范围,接口服务返回的数据从 first 开始,first 之前的对象数据会在服务端被丢弃。根据 Range 请求的协议规范,接口服务需要返回 HTTP 错误代码206 Partial Content,并设置 Content-Range 响应头部告知返回数据的范围<first>-<size>/<size>,其中<firs>是客户端要求的起始位置,<size>是对象的大小。

objects 接口还新增了POST方法,用于创建 token。
POST /objects/<object name>
请求头部
Digest: SHA-256=<对象散列值的 Base64 编码>
Size:<对象内容的长度>
响应头部
Location:<访问/temp/token的 URI>
token 被放在Location 头部返回给客户端,客户端拿到后可以直接访问该URI。

除了 objects 接口发生的改变以外,接口服务还新增temp 接口。
HEAD /temp/<token>
响应头部
Content-Length:<token当前的上传字节数>

PUT /temp/<token>
请求头部
Range: bytes=<first>-<last>
请求正文
对象的内容,字节范围为 first~last

客户端通过 Range头部指定上传的范围,first必须跟tken 当前的上传字节数一致否则接口服务会返回416 Range Not Satisfiable。如果上传的是最后一段数据,<last>为空

数据服务的REST接口

数据服务的 temp 接口新增了 HEAD 和GET两个方,HEAD 方法用于取某个分片临时对象当前的大小;而 GET 方法则用于获取临时对象的数据。
HEAD /temp/<uuid>
响应头部
Content-Length:<临时对象当前的上传字节数>

GET /temp/<uuid>
响应正文
临时对象的内容

客户端将对象所有的数据上传完毕之后,接口服务需要调用这个方法从数据服务读取各分片临时对象的内容并进行数据校验,只有在验证了对象的散列值符合预期的情况下,服务端才认为该对象的上传是成功的,进而将临时对象转正。

小结

本章实现了对象数据的断点续传。断点下载通过 Range 请求头部实现,客户端可以在调用对象的GET 接口时,通过 Range 头部告知服务端下载数据的偏移量,接口服务将该偏移量之前的对象数据流丢弃并将剩下的部分返回给客户端。

断点上传则比较复杂,由于 HTTP 服务的特点,需要使用新的对象 POST 接创建一个token,并通过接口服务的temp 接口访问token 上传数据。客户端需要根据上传对象的大小自行选择上传的方式:对于小对象,客户端可以使用之前的 PUT 方法上传对于大对象,客户端需要选择POST方法并自行分块上传。

除非正好将对象完整上传,否则接口服务每次只接受 32 000字节的整数倍,不足的部分将被丢弃。如果客户端的分块小于 32 000字节,那么上传的数据就会被全部丢弃。客户端需要在PUT每一块之前调用HEAD检查该 token 当前的进度,并选择合适的偏移量和分块大小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: FastDFS是一个开源的轻量级分布式文件系统,用于分布式存储和管理大规模的文件。在使用FastDFS进行断点下载时,可以结合Java语言来实现。 在Java中,首先需要引入FastDFS的相关依赖库,比如fastdfs-client-java。然后,通过FastDFS的Java API来实现断点下载的功能。 具体实现步骤如下: 1. 首先,需要获取待下载文件的文件元数据,如文件名、文件大小等信息,可以通过FastDFS的API来获取。 2. 然后,根据文件元数据和下载路径,创建一个本地文件,用于存储下载的文件内容。 3. 接着,通过FastDFS的API,通过指定的文件偏移量和下载长度来读取文件内容,将文件内容写入到本地文件中。同时,记录已下载的文件长度。 4. 当下载完成时,关闭与FastDFS的连接,并完成断点下载的过程。 需要注意的是,在断点下载前,需要判断是否已有部分文件已经下载完成,如果是,则可以根据已有的文件长度来设置文件偏移量和下载长度,从而进行断点下载。 总而言之,Java可以通过调用FastDFS的API来实现断点下载功能,具体的实现步骤包括获取文件元数据、创建本地文件、通过指定的偏移量和长度读取文件内容,并将内容写入到本地文件中,最后完成断点下载过程。 ### 回答2: FastDFS是一个开源的轻量级分布式文件系统,它主要用于解决大规模数据存储分布式文件访问的问题。FastDFS完整的文件输过程可以分为文件上和文件下载两部分。而断点则是指在网络异常或用户主动中断的情况下,能够恢复之前未输完成的文件输。 在Java中实现FastDFS的断点下载可以通过以下步骤: 1. 首先,通过FastDFS提供的Java客户端API,连接到FastDFS服务器。 2. 检查本地文件系统,判断是否存在已下载的临时文件。 3. 如果存在未下载完成的临时文件,获取已下载字节数并记录。 4. 通过FastDFS的文件下载API,设置偏移量为已下载的字节数。 5. 将下载的文件片段追加到本地临时文件中,并更新已下载的字节数。 6. 重复步骤4和步骤5,直到下载完成。 7. 删除临时文件并保存完整的文件。 在每次下载时,需要记录已下载的字节数,以便下次下载时可以根据该偏移量进行断点。可以将该信息保存在本地文件系统的临时文件中,或者通过数据库等方式进行持久化存储断点的实现可以大大提高文件输的可靠性和效率,特别是在网络不稳定或文件较大的情况下。通过合理地记录已下载的字节数,并使下载从中断处继,可以减少重复输的数据,节省带宽和时间。 总之,使用Java可以通过FastDFS的API实现断点下载。这样可以提高文件输的可靠性和效率,为用户提供更良好的体验。 ### 回答3: FastDFS是一个分布式文件存储系统,它采用了文件切割、分布式存储和文件索引等技术,可以高效地存储和管理大规模的文件。在Java中,可以使用FastDFS提供的客户端API来实现断点下载功能。 在实现断点下载的过程中,首先需要通过FastDFS客户端API获取文件的元数据信息,包括文件大小和分片信息等。然后,根据已下载的文件大小,确定接下来要从哪个分片开始下载。 接下来,使用Java的IO流技术将分片数据写入本地文件中。为了实现断点功能,可以通过设置HTTP请求的Range头字段来指定下载的起始位置,从而避免重复下载已经下载过的部分。 在下载过程中,可以采用多线程的方式进行并发下载,提高下载速度。可以将文件分成多个连的范围,并为每个范围创建一个线程进行下载。在每个线程下载完成后,将下载的数据写入本地文件中相应的位置。 另外,在断点下载的过程中,需要实时记录已下载的文件大小,并及时保存断点信息。这样,当下载中断时,下次继下载时可以根据已下载的文件大小和分片信息来确定需要继下载的位置,从而实现断点的功能。 总之,通过使用FastDFS的客户端API和Java的IO流技术,可以实现断点下载功能。通过合理地划分分片和利用多线程进行并发下载,可以提高下载速度。并通过记录已下载的文件大小和断点信息,实现下载中断后的断点

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值