优雅地实现 TCP 压缩传输

标签: Go | 发表时间:2016-11-04 11:22 | 作者:
出处:http://colobu.com/

集群式、负载均衡的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格式压缩。

定义这几种格式:

     
1
2
3
4
5
6
7
8
9
10
     
type CompressType byte
const (
// CompressNone represents no compression
CompressNone CompressType = iota
// CompressFlate represents zip
CompressFlate
// CompressSnappy represents snappy
CompressSnappy
)

然后定义 CompressConn类型,它嵌入了一个匿名 net.Conn类型的字段,作为 net.Conn的包装,因此它满足 net.Conn接口。
其中的 rw可以实现压缩读写,CompressType定义了压缩类型。

     
1
2
3
4
5
6
     
type CompressConn struct {
net.Conn
r io.Reader
w io.Writer
compressType CompressType
}

覆盖 net.Conn的读写方法:

     
1
2
3
4
5
6
7
     
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是辅助创建方法:

     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
     
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 = r
w := 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 = w
return cc
}

对于 zip格式的写,写完后我们需要立即 Flush,所以也需要对它包装一下:

     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
     
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一样。

相关 [tcp 压缩 传输] 推荐:

优雅地实现 TCP 压缩传输

- - 鸟窝
集群式、负载均衡的RPC框架 rpcx支持多种的序列化库,可以有效的减少消息体的大小,但是对于字符串或者图片的字节slice,明显还可以进一步的压缩,正如fasthttp作者valyala在他的新的开源项目 httpteleport中描述的: 通过1G的带宽传输10G的数据 (夸张). 为了在RPC的传输中减少传输的数据大小,我在不影响rpcx整体框架的基础上,参考了httpteleport的实现,对 net.TCPConn进行了封装,实现了压缩/解压缩功能的 net.Conn,可以有效的减少带宽,节省公司在带宽上的花费, 以下就是具体的实现.

视频面试传输协议到底是 TCP 还是 UDP

- - IT瘾-dev
又是一年一度的秋季校招开始了,以往的校招各个公司都会在公司现场或者学校现场安排学生进行现场面试. 但是今年由于疫情的原因,不允许让同学在现场进行一个面试,所以今年的面试形式就从线下转到了线上,面试形式的转变,但是我们考核学生的方式依旧没有转变. 校招的同学和社招的同学有很大的不同,他们没有丰富的工作经验,没有太多的项目经历,那么我们如何去衡量一个校招的同学呢.

GitHub - cnlh/nps: 一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。

- -
nps是一款轻量级、高性能、功能强大的. tcp、udp流量转发,可支持任何. tcp、udp上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还. 支持内网http代理、内网socks5代理、. p2p等,并带有功能强大的web管理端. 做微信公众号开发、小程序开发等----> 域名代理模式.

tcp/ip调优

- Lucseeker - 在路上
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;. 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;.

浅谈TCP优化

- - 火丁笔记
很多人常常对 TCP优化有一种雾里看花的感觉,实际上只要理解了TCP的运行方式就能掀开它的神秘面纱. Ilya Grigorik 在「 High Performance Browser Networking」中做了很多细致的描述,让人读起来醍醐灌顶,我大概总结了一下,以期更加通俗易懂. 传输数据的时候,如果发送方传输的数据量超过了接收方的处理能力,那么接收方会出现丢包.

TCP报文结构

- - 互联网 - ITeye博客
一、TCP报文结构如下:.  固定首部长度为20字节,可变部分0~40字节,各字段解释:. source port number:源端口,16bits,范围0~65525. target port number:目的端口,16bits,范围同上. sequence number:数据序号,32bits,TCP 连接中传送的数据流中的每一个字节都编上一个序号.

TCP 状态变化

- - 互联网 - ITeye博客
关闭socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况. 前者是指有本地主机主动发起的关闭;而后者则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接. 将关闭部分的状态转移摘出来,就得到了下图:. 通过图上,我们来分析,什么情况下,连接处于CLOSE_WAIT状态呢.

TCP/IP分享——链路层

- Goingmm - 弯曲评论
在张国荣自尽8周年纪念日,也就是愚人节的前几十分钟,终于把第二章弄完了. 首席似乎不是特别有空,我就斗胆在这里自己发了,从前面2期的反响来看,相当热烈,我也是摆出一副要杀要剐,悉听尊便的架势,这可能是受最近流行霸气外露的影响,批评几句又伤不了皮毛,也影响不了我的工作和正常生活,只要给大家带来快乐,我就很开心,似乎历史上很多想法都是在争吵中诞生的.

TFO(tcp fast open)简介

- chenqj - pagefault
原创文章,转载请注明: 转载自pagefault. 本文链接地址: TFO(tcp fast open)简介. 这个是google的几个人提交的一个rfc,是对tcp的一个增强,简而言之就是在3次握手的时候也用来交换数据. 这个东西google内部已经在使用了,不过内核的相关patch还没有开源出来,chrome也支持这个了(client的内核必须支持).

TCP/IP重传超时--RTO

- dennis - 一个故事@MySQL DBA
Shared by 子非鱼 安知余(褚霸). 概述:本文讨论主机在发送一个TCP数据包后,如果迟迟没有收到ACK,主机多久后会重传这个数据包. 主机从发出数据包到第一次TCP重传开始,RFC中这段时间间隔称为retransmission timeout,缩写做RTO. 本文会先看看RFC中如何定义RTO,然后看看Linux中如何实现.