Facebook的Zstandard(簡稱zstd)壓縮算法逐漸流行,它有以下特點:
1,壓縮、解壓速度快。
下圖是單線程壓縮的性能,橫軸是壓縮比,縱軸是壓縮速度。
- 高壓縮等級時,壓縮比接近lzma。(但解壓更快)
- 低壓縮等級時,速度接近lz4。(zstd和lz4的作者是同一個人)
在各種情況下,性能比zlib好,可以考慮替代zlib。
圖片出自這個網頁,里面還有一些比較圖表。
zstd自帶多線程壓縮,充分利用多核CPU,讓壓縮速度提升數倍。
原理是把數據 等分 成多份,並行壓縮出一個單幀zstd數據,可以設置 每份的大小、重疊部分的大小。
多線程壓縮可以用1秒把1GiB數據壓縮到500MiB,網絡傳輸會快很多。
但不支持多線程解壓。不過解壓速度已經很快了,低壓縮等級時可以比一些SSD快。解壓速度可以看zstd網站首頁的表格。
2,如果使用預先訓練的zstd字典,對於幾KB的小數據,可以大大提高壓縮比。
要壓縮的數據越小,就越難壓縮,這是所有壓縮算法都有的問題,原因是壓縮算法從之前的數據中學習如何壓縮之后的數據,但對於小數據,沒有“之前”可以參考。
為了解決這一問題,zstd提供了訓練模式,針對特定的數據類型訓練字典。訓練是通過提供一些樣本(每個樣本一個文件)來實現的,訓練的結果(字典)存儲在一個文件中,在壓縮和解壓之前必須加載該文件。
使用字典可以大大提高幾KB的小數據的壓縮比,對於1KB以下的小數據有最好效果。
下圖是壓縮1萬條大約1KB的數據,在使用字典時,壓縮比、壓縮速度、解壓速度大大提高。
注意:
- 如果丟失了字典,就不能解壓相應的數據。
- 對於幾MB的大數據,字典的效果微不足道。
除了用樣本訓練字典,還可以手工編寫(或使用專用字典工具構建)一個更高效的字典,然后用一些樣本完成(finalize)這個字典。
比如把JSON文件中的共有部分精心挑選出來,寫到一個文件里,然后用一些JSON樣本完成(finalize)這個字典,這樣得到的字典可能比用樣本訓練的字典更高效。
3,幀(frame)和塊(block)讓使用更靈活,適合各種場景。
zstd數據由1個或多個獨立的幀(frame)組成,解壓后的多幀數據 等於 每幀解壓后再相接。
每幀完全獨立,包括一個幀頭,以及一套解壓參數。
zlib和lzma也有這樣的多幀特性。
每幀包括1個或多個塊(block),塊的尺寸上限是3字節塊頭+128KB,塊的實際最大尺寸取決於幀頭里定義的參數。
和完全獨立的幀不同,在解壓時,塊依賴之前的塊、不依賴之后的塊,完整的塊可以被全部解壓。所以flush塊可以用於通訊場景,接收方可以立刻解壓。
zlib也有類似塊的特性。
Python使用zstd壓縮算法
用了幾個月時間,寫了一個pyzstd模塊,它的API和Python標准庫中的bz2/lzma/zlib模塊相似。
PyPI頁面:https://pypi.org/project/pyzstd/
文檔(英文):https://pyzstd.readthedocs.io/en/latest/
GitHub頁面:https://github.com/animalize/pyzstd
PyPI上還有兩個zstd模塊:
zstd:它太簡單了,只提供很少的基本功能。
zstandard:提供了豐富的API,但是API風格和Python標准庫的bz2/lzma/zlib不同。
zstd雜談
1, 上面提到:在高壓縮等級時,壓縮比接近lzma;在低壓縮等級時,速度接近lz4。
可能有人好奇這是怎么做到的,這是因為zstd內部提供了幾套壓縮代碼,適用於不同的壓縮等級。(但格式是相同的)
缺點就是二進制代碼很大,比較幾種算法的DLL文件,zlib大約110KB,lzma大約150KB,bz2大約80KB,zstd達450KB。
不過zstd的二進制代碼可以裁剪,以下三種功能可以按需留取:壓縮、解壓、訓練字典。壓縮中的多線程壓縮也是可裁剪的。
比如一個APP只需要解壓zstd數據,可以只編譯解壓代碼,編譯后的解壓可執行代碼僅40~70KB。
2, zstd的核心代碼考慮了亂序執行,v1.5使用SIMD(SSE2或Neon),感覺比較“現代”。
3, zstd的C代碼大量使用常量傳播(constant propagation),更智能的編譯器會有更好的內聯優化。
似乎MSVC在這方面較弱,見此文,文中說MSVC會進行改進。目前(2021年1月)MSVC編譯的比GCC編譯的慢6%~10%。
zstd代碼可能也會針對MSVC做些調整。
4, 近來一些庫重寫了DEFLATE算法,比如libdeflate、ISA-L,可以將gzip的壓縮速度、解壓速度提升到zstd的級別。
也許zstd不會替代lzma,lzma能有更高的壓縮比。
相比lzma,zstd有更快的解壓速度,見Linux內核、Arch Linux的報道。
5, 最后貼一張2019年11月做的性能比較。
zstd還處於活躍的開發中(現在是2021年),每個版本可能會有少量性能提升。
zlib/bz2/lzma,這些庫有的已經很久沒有實質更新,有的更新緩慢(只有一個人在開發)。
zstd小組好像有4個員工,還有一些貢獻者參與,很活躍。
活躍的負面效果是可能引入少量邊緣性的bug,可以看更新日志了解一下。