在对象存储服务端实现数据压缩的功能。
在整个云存储系统中,对象存储服务端并不是最适合做数据压缩的地方。最适合做数据压缩的地方是客户端。一个高性能的客户端不仅可以将大量小对象打包成大对象提高存储和传输的效率,也可以在客户机本地进行数据压缩,进一步节省网络带宽和存储空间。云存储系统在设计最初就包含了专门的客户端,那么一定要将数据压缩功能放在客户端,而不是服务端。
如果你的云存储系统中没有一个专门的客户端,或者用户更倾向使用通用的客户端比如浏览器,且用户上传的对象大多数都是一些适合数据压缩的文档,那么你可以考虑在服务端实现数据压缩功能,将客户上传的对象压缩起来再进行存储。
数据的传输也一样可以进行压缩。对于对象的上传来说,由于没有一个专门的客户端,我们没办法限定客户上传的数据。但是对于对象的下载,服务端可以提供一种选择,只要客户端支持,我们的接口服务就可以传输压缩后的数据给客户端。
1.8.1 版本的Go语言原支持的压缩算法包有 bzip2、flate、gzip、lzw 和 zlib 这5种。
- lzw 是 Lempel-Ziv-Welch 压缩算法的简写。这个算法的实现非常简单,甚至可以实现在硬件上,以获得非常高的压缩速度。UNIX 下被广泛使用的文件压缩工具compress 使用的就是这个算法,GIF 图像格式使用的压缩算法也是它。
- zlib 是一个软件库,实现了 RFC1950中介绍的压缩数据格式规范。它包括 LinuxMac OS X以及ioS 在内的很多平台的关键组件,PS4、Wi UXbox One 等游戏主机也使用它。它是后续 DEFLATE 和gzip 等压缩算法的一个抽象。
- flate是RFC1951中介绍的DEFLATE压缩数据格式规范,也是zip 文件使用的压缩算法。它使用了LZ77算法移除重复的字符串,并用 Hufiman 编码进一步压缩比特。DEFLATE的产生是为了代替lzw 以及其他受专利所限的数据压缩算法
- gzip 是 RFC1952中介绍的压缩数据格式规范,也是gz文件使用的压缩算法。它基于 DEFLATE 算法,但是因为 gzip 可以将一个打包文件中的所有文件串联起来进行压缩,所以可以获得比DEFLATE 更高的压缩比。
- bzip2是一个免费且开源的文件压缩项目,使用的是 Burrows-Wheeler 算法,它只能压缩单个文件,且不能处理打包文件。bzip2 是 bz2 文件使用的压缩算法。在单个文件的压缩上,bzip2比DEFLATE和gzip 的压缩率都要高,但是速度也慢得多。
我们采用的压缩算法是 gzip,它不是压缩速度最快的也不是压缩比最高的压缩算法,对于功能的介绍和实现来说,gzip 足够好且足够简单。对于压缩速度和压缩比有要求的可以选择更合适的压缩算法。
用gzip实现对象存储和下载时的数据压缩
存储时的数据压缩
在本章之前,数据服务节点把分片临时对象转正时使用的是 os.Rename
操作,将STORAGE_ROOT/temp/<uuid>.dat
重命名为STORAGE_ROOT/objects/<hash>.X.hash
同样,在读取对象分片时,数据服务节点需要在读取STORAGE_ROOT/obiects<hash>.X.<hash of shard X>
文件的内容后先进行 gzip 解压,然后才作为HTTP 响应的正文输出。
下载时的数据压缩
客户端在下载对象时可以设置Accept-Encoding 头部为 gzip。接口服务在检查到这个头部后会将对象数据流经过 gzip 压缩后写入HTTP 响应的正文。
接口服务的REST接口
GET /objects/<object name>
请求头部
Accept-Encoding:gzip
响应头部
Content-Encoding:gzip
响应正文
gzip压缩后的对象内容
小结
数据的压缩应该尽可能在客户端实现。只有在客户端不受我们控制且大多数对象的数据类型适合压缩的情况下,才建议在服务端实现数据压缩。随机数据不适合压缩而文本数据则比较适合,用 gzip 比大约能有 2:1。
数据压缩可以用于节省存储空间。数据服务节点本地磁盘上的对象文件存储的是压缩后的数据。数据在临时对象转正时压缩,并在对象读取时解压。
数据压缩还可以用于节省网络带宽。客户端可以在 GET 对象时设置 Accept-Encoding 请求头部告诉接口服务将对象的数据进行压缩。如果接口服务收到这样的请求,则需要设置Content-Encoding 响应头部。