基于文件语义实现S3接口语义的注意事项
本文标题中提到的文件语义,指的是POSIX规范。
S3指的是AWS提供的对象存储服务以及相关接口。为方便描述,下文中以对象语义替代S3接口语义。
文件语义和对象语义存在比较多的差异。
对象语义不支持文件语义的部分特性,比如:
- 目录的操作,创建、删除、修改名称。
- 文件的部分操作,追加写、随机写、修改名称等。
- 文件的元数据,比如:
- 时间字段,即crtime/ctime/mtime/atime。
- 用户和组,即uid/gid。
- 权限,即UGO和ACL。
- 文件的扩展属性。
- 硬链接。
- 软链接。
- 锁。
文件语义不支持对象语义的部分特性,比如:
- Etag,文件语义中没有定义相关信息。
- 生命周期管理。
- 桶策略。
- 多版本。
- 对象的元数据,即:
- 系统元数据,即标准HTTP头部。
- 用户自定义元数据,即命名为
x-amz-meta-*
的HTTP头部。 - 对象tagging,即命名为
x-amz-tagging
的HTTP头部。
部分存在差异的语义,比如:
- WORM,文件语义和对象语义的实现,由于前述差异,具体实现和保护范围可能存在一定的差异。
- 文件的创建。依据对象语义,保存对象的操作是一个原子行为,包含数据、元数据一并写入,要么成功、要么失败,只要上传对象的接口返回了成功,即表示对象创建成功。而依据文件语义,保存文件的操作,涉及打开、写入数据、写入元数据、关闭文件等操作,并不是原子行为,写入数据的过程中可能会被中断,但由于文件打开成功,因此会出现数据不一致的现象。
- 目录,对象语义对目录的支持非常有限,而文件语义则提供了丰富的API。
对象语义中,使用对象来表示客户的数据,在存储和管理对象时,放弃了目录的概念,所有的对象均以展平的形式存储,在使用文件语义实现对象语义时,需要对目录做特殊的处理。
在文件语义中,/
有特殊含义,表示目录的分隔符,因此一般不允许在目录名或者文件名中使用。
而AWS S3定义的规范中,/
是普通字符,允许在对象名中使用。
做个实验,登录Linux环境的控制台,执行如下命令,输出如下:
$ ll a.py
-rw-r--r-- 1 jackie docker 138 3月 29 21:47 a.py
$ mkdir a.py
mkdir: cannot create directory ‘a.py’: File exists
$ mkdir a.py/
mkdir: cannot create directory ‘a.py/’: File exists
依据对象语义,a.py
和a.py/
是不同的对象,但在文件语义下,a.py
存在,则阻塞目录a.py
的创建操作。
依据文件语义,删除目录即类似rm -rf /path/to/delete
时,目录和目录下的所有的文件、目录均会被删除。
考虑到本操作并不是一个原子操作,因此使用文件语义实现对象语义的删除操作时,会有比较多的注意事项。
思考点
- 删除目录时,目录下的对象,需要一并删除。假如对象数量比较多时,则删除操作将比较耗时。
- 目录下假如存在未合并的多段对象,是否一并删除。
- 目录下假如仅有一个对象,使用对象语义的删除接口,将该对象删除时,目录是否需要被删除。
- 先上传目录,上传一个对象至该目录下,使用对象语义的删除接口,将该对象删除时,目录是否需要被删除。
- 手工上传的目录,在列举对象时,是否作为一个对象在列举结果中出现。
- 如前所述,文件主义并不支持对象主义的Etag,因此在实现上传对象的操作时,需要计算并保留Etag值。
- 保存对象的数据的操作,计算MD5值的操作,二者需要保持进度一致,避免MD5值计算结果不正确,或者耗时过久,影响上传操作的性能。
- Etag保存的位置。
- 对象元数据的保存位置,依据语义,需要和数据一起保存。
- 元数据保存的位置。
- 操作的原子性。
- 对象语义写入对象时,文件的元数据,应当如何填值。如前述,不支持的元数据,如下:
- 时间字段,即crtime/ctime/mtime/atime。
- 用户和组,即uid/gid。
- 权限,即UGO和ACL。
本文来自博客园,作者:jackieathome,转载请注明原文链接:https://www.cnblogs.com/jackieathome/p/18117058