snappy试玩
背景
今天在看nsq源码的时候,发现client_v2.go里面有一段代码引起了我的注意
func (c *clientV2) UpgradeSnappy() error {
c.Reader = bufio.NewReaderSize(snappystream.NewReader(conn, snappystream.SkipVerifyChecksum), defaultBufferSize)
c.Writer = bufio.NewWriterSize(snappystream.NewWriter(conn), c.OutputBufferSize)
...
}
我大概知道它是用于对我的数据在传输前进行压缩的,我之前了解过LZ4, 但,snappy我了解甚少,于是我顺着snappystream,找到了一个库 go-snappystream
里面是这样定义的:
This package wraps snappy-go and supplies a Reader and Writer for the snappy framed stream format.
这个库是nsq的作者mreiferson基于google的snappy进行封装的工具。
Snappy 介绍
Snappy(以前称Zippy)是Google基于LZ77 的思路用C++语言编写的快速数据压缩与解压程序库,并在2011年开源。它的目标并非最大压缩率或与其他压缩程序库的兼容性, 而是非常高的速度和合理的压缩率。使用一个运行在64位模式下的酷睿i7处理器的单个核心, 压缩速度250 MB/s,解压速度500 MB/s。压缩率比gzip低20-100%
Snappy广泛应用在Google的项目,例如BigTable、MapReduce和Google内部RPC系统的压缩数据。 它可在开源项目中使用,例如Cassandra、Hadoop、LevelDB、MongoDB、RocksDB和Lucene。 解压缩时会检测压缩流中是否存在错误。Snappy不使用内联汇编并且可移植。
Snappy是一个C++的库,你可以在产品中使用,不过也有一些其他语言的版本,例如Haskell、Java、Perl、Python和Ruby。
golang版snappy可以查看这里
使用
先看第一个例子,我们采用snappy+gob来处理我们的文件
package main
import (
"encoding/gob"
"fmt"
"github.com/mreiferson/go-snappystream"
"os"
)
type FileCompress struct {
Classifier interface{}
}
func (t *FileCompress) SaveFile(filename string) error {
fi, err := os.Create(filename)
if err != nil {
return err
}
defer fi.Close()
fs := snappystream.NewBufferedWriter(fi)
encoder := gob.NewEncoder(fs)
err = encoder.Encode(t.Classifier)
if err != nil {
return err
}
err = fs.Close()
if err != nil {
return err
}
return nil
}
func main() {
obj := FileCompress{Classifier: "it works"}
err := obj.SaveFile("test.sz")
if err != nil {
fmt.Println(err)
}
}
第二个例子 ,我们写一个命令交互的工具 snappy2.go,它介绍我们的输入并进行snappy处理
package main
import snap "github.com/mreiferson/go-snappystream"
import "os"
import "io"
import "flag"
type Options struct {
Encode bool
Decode bool
}
func check(err error) {
if err != nil {
panic(err)
}
}
var en = flag.Bool("encode", false, "encode stdin (the default)")
var de = flag.Bool("decode", false, "decode stdin")
func main() {
flag.Parse()
opts := &Options{
Decode: *en,
Encode: *de,
}
if opts.Decode {
decode()
} else {
encode()
}
}
func encode() {
_, err := io.Copy(snap.NewWriter(os.Stdout), os.Stdin)
check(err)
}
func decode() {
_, err := io.Copy(os.Stdout, snap.NewReader(os.Stdin, snap.VerifyChecksum))
check(err)
}
我们可以再终端输入命令进行使用
go run snappy2.go < test.txt | go run snappy2.go --decode
总的来说,snappy对比其它压缩算法的工具,具备以下的特定:
- 快
- 稳定
- 鲁棒性强
- 开源
下面附加一份我机器上用go-snappy的一个基准测试报告,仅供参考
BenchmarkWordsDecode1e1-4 50000000 25.6 ns/op 390.89 MB/s
BenchmarkWordsDecode1e2-4 20000000 96.5 ns/op 1036.03 MB/s
BenchmarkWordsDecode1e3-4 2000000 822 ns/op 1216.36 MB/s
BenchmarkWordsDecode1e4-4 200000 9008 ns/op 1110.06 MB/s
BenchmarkWordsDecode1e5-4 10000 205258 ns/op 487.19 MB/s
BenchmarkWordsDecode1e6-4 1000 1644589 ns/op 608.05 MB/s
BenchmarkWordsEncode1e1-4 100000000 21.5 ns/op 465.78 MB/s
BenchmarkWordsEncode1e2-4 10000000 217 ns/op 459.67 MB/s
BenchmarkWordsEncode1e3-4 1000000 2038 ns/op 490.50 MB/s
BenchmarkWordsEncode1e4-4 50000 29909 ns/op 334.35 MB/s
BenchmarkWordsEncode1e5-4 5000 355186 ns/op 281.54 MB/s
BenchmarkWordsEncode1e6-4 500 3387786 ns/op 295.18 MB/s
BenchmarkRandomEncode-4 10000 107681 ns/op 9737.75 MB/s
BenchmarkExtendMatch-4 200000 10816 ns/op
PASS