最近终于有时间写一点关于三步上传的东东了,mulitiple upload又称三步上传。三步上传主要针对那些网络环境不好(传着传着就断了),或者上传的文件大于5GB,普通的上传方式满足不了的上传。
aws的s3是直接将multiple upload作为一个函数接口直接提供给开发者,而BOS和阿里的OSS都需要自己实现那三步:
1. 初始化multiple uploadID
2. 上传分块
3. 完成上传
下面详细说明一下这三步,客户端和BOS服务器在做什么。
初始化uploadID:
客户端InitMultiUpload,BOS服务器端根据客户端提供的bucket,object等信息生成在Bucket内唯一的Uploadid,并且将Uploadid返回给客户端;
上传分片:
客户端:上传分片,并提供partNumber。
服务器端:服务器端将文件PartData按照Object的逻辑去存储,并检查当前PartNum为接续块或重新上传的块,每个Part上传时的快照信息保存在PartData Object的Meta数据中。返回给客户端已上传数据的MD5信息,以便校验已上传数据的完整性,断点上传支持最新上传的一块数据的错误重新上传;
注意这里:服务器端是给客户端返回每个分片的MD5的。
结束上传:
客户端提交Bucket、Object、Uploadid、PartList给服务器端。服务器检查每一个已上传的PartData Object的Meta并合并最终的SliceList。如正确,则根据收集到的SliceList、UserMeta信息生成Meta数据写入Meta表。删除PartData Object对应的所有Meta数据。(感觉在这里删除了每个分片的MD5)
整个multipleUpload就是这样的一个处理过程,需要注意的是:最后上传的那个文件是没有content-MD5的,这就是为什么我们说三步上传的文件没有MD5的原因。
理论上,如果每个分片返回的md5值都是对的,那最后合成的文件就是完整并且正确的。以后再说这里怎么去验证。
下面这个部分主要是结合实际的python sdk中的代码,讲一下断点续传。(我也不会python哈,写的比较low,诸位轻批)
这里用到一个pickle库,这货的作用就是持久性地保持对象,用这个货来将我断点发生之前的partlist存到文件里。
用法:
import pickle
写入文件:
f = open("dump.txt", "wb")
partList = [] # then add something into list
pickle.dump(partList, f)
f.close()
从文件读取:
f = open("dump.txt", "rb")
partList = pickle.load(f)
f.close()
# do something with partList
用两个代码来演示一下测试思路:第一个代码client.py模拟我初始化分片,并上传分片,在这个过程中,我用键盘作为中断。这段代码我需要打印出中断时的partNumber,left_size, offset,并且将partlist保存在一个文件b里。
第二个代码resume.py根据uploadID将剩下的分片传到bos上,并且读取文件b中的partlist,完成completeUpload。
client.py的大体思路:
初始化upload,生成uploadID:
upload_id = bos_client.initiate_multipart_upload
计算分块:
offset = 0
part_number = 1
part_list = []
while left_size > 0
进行分片
......
上传part
bos_client.upload_part_from_file
打印left_size
打印offset
#将partlist存储到文件b中:
f1 = open("./b","wb")
pickle.dump(part_list,f1)
f1.close()
演示:
在本该传第28个分片的时候,我键盘中断了这次操作,并且打印了left_size和offset。
接下来我们模拟resume.py。
resume.py的大体思路:
upload_id = "bf3167c31f96036f63bec1d1d70ace09"
#如果不知道uploadID,可以用listmultipleUpload根据bucket name列出来。
f1 = open("./b","rb")
#将文件b里的数据读出来,赋给part_list
part_list = pickle.load(f1)
f1.close
#将上图中打印出来的数据传给left_size,offset, part_number。
left_size = 501506048
offset = 141557760
part_number = 28
#剩下这一块的处理跟client.py中while的处理一样了。
while:
*******
最终,执行完毕之后就可以在控制台看到上传成功的object了:
这两段代码所在github:
https://github.com/tanxiniao/bos/blob/master/client.py
https://github.com/tanxiniao/bos/blob/master/resumable.py
附赠listmultipleUpload的代码:
https://github.com/tanxiniao/bos/blob/master/listmul.py