優雅地實現 TCP 壓縮傳輸

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

叢集式、負載平衡的RPC架構 rpcx支援多種的序列化庫,可以有效減少訊息體的大小,但是對於字串或者圖片的位元組slice,明顯還可以進一步的壓縮,正如fasthttp作者valyala在他的新的開源項目httpteleport中描述的: 通過1G的頻寬傳輸10G的資料 (誇張)。

為了在RPC的傳輸中減少傳輸的資料大小,我在不影響rpcx整體架構的基礎上,參考了httpteleport的實現,對net.TCPConn進行了封裝,實現了壓縮/解壓縮功能的net.Conn,可以有效減少頻寬,節省公司在頻寬上的花費, 以下就是具體的實現。

首先介紹兩種壓縮格式。

zip 是常用的一種壓縮格式,Go標準庫中提供了它的實現。zip原名Deflate,發明者為菲爾·卡茨(Phil Katz),他於1989年1月公布了該格式的資料。ZIP通常使用尾碼名“.zip”,它的MIME格式為application/zip。目前,ZIP格式屬於幾種主流的壓縮格式之一。

snappy(以前稱Zippy)是Google基於LZ77的思路用C++語言編寫的快速資料壓縮與解壓程式庫,並在2011年開源。它的目標並非最大壓縮率或與其他壓縮程式庫的相容性,而是非常高的速度和合理的壓縮率。使用一個運行在64位元模式下的酷睿i7處理器的單個核心,壓縮速度250 MB/s,解壓速度500 MB/s。壓縮率比gzip低20-100%。Golang也提供了snappy的實現。

所以在壓縮比和速度的權衡中你可以選擇zip格式壓縮或者snappy格式壓縮。

定義這幾種格式:

12345678910
type CompressType byteconst (// CompressNone represents no compressionCompressNone CompressType = iota// CompressFlate represents zipCompressFlate// CompressSnappy represents snappyCompressSnappy)

然後定義CompressConn類型,它嵌入了一個匿名net.Conn類型的欄位,作為net.Conn的封裝,因此它滿足net.Conn介面。
其中的rw可以實現壓縮讀寫,CompressType定義了壓縮類型。

123456
type CompressConn struct {net.Connr            io.Readerw            io.WritercompressType CompressType}

覆蓋net.Conn的讀寫方法:

1234567
func (c *CompressConn) Read(b []byte) (n int, err error) {return c.r.Read(b)}func (c *CompressConn) Write(b []byte) (n int, err error) {return c.w.Write(b)}

NewCompressConn是輔助建立方法:

12345678910111213141516171819202122232425262728
func NewCompressConn(conn net.Conn, compressType CompressType) net.Conn {cc := &CompressConn{Conn: conn}r := io.Reader(cc.Conn)switch compressType {case CompressNone:case CompressFlate:r = flate.NewReader(r)case CompressSnappy:r = snappy.NewReader(r)}cc.r = rw := io.Writer(cc.Conn)switch compressType {case CompressNone:case CompressFlate:zw, err := flate.NewWriter(w, flate.DefaultCompression)if err != nil {panic(fmt.Sprintf("BUG: flate.NewWriter(%d) returned non-nil err: %s", flate.DefaultCompression, err))}w = &writeFlusher{w: zw}case CompressSnappy:w = snappy.NewWriter(w)}cc.w = wreturn cc}

對於zip格式的寫,寫完後我們需要立即Flush,所以也需要對它封裝一下:

1234567891011121314
type writeFlusher struct {w *flate.Writer}func (wf *writeFlusher) Write(p []byte) (int, error) {n, err := wf.w.Write(p)if err != nil {return n, err}if err := wf.w.Flush(); err != nil {return 0, err}return n, nil}

這樣我們就實現了一個可以解壓縮/壓縮的讀寫net.Conn對象,你可以通過NewCompressConn方法對一個正常的net.TCPConn進行封裝,而對它的調用就像一個普通的net.Conn一樣。

update: 我增加了 zstd 和 lz4 的支援。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.