gzip压缩率,如何优化很长的 JSON 数据
gzip压缩率,如何优化很长的 JSON 数据详细介绍
本文目录一览: Android 网络框架解压缩(gzip)浅谈
六谈这个话题,是因为很多时间都忽略了这个因素,网络传输数据的压缩很少有人去关注,然而有时间提到这个问题的时间却一时不知道怎么回答,或者已经忘掉了这个概念...
进入正题,首先来聊聊Gzip。
Gzip是GNUZip的缩写,他是一个GNU自由软件的文件圧缩程序。
我们在进行网络传输数据时,经常用到json、xml等格式的数据,这些数据在传输前可以进行压缩,这时候就会涉及到一种压缩格式—Gzip。Gzip的压缩比率非常大,有的甚至能达到99.9%以上,可以大大减少传输内容,提高用户的传输速度,进而提高用户的体验。
http://tool.chinaz.com/Gzips/
https://gzip.51240.com/
比如我们通过第一个链接看一下“开源中国的新闻页”,网址如下:
http://www.oschina.net/action/api/news_list?catalog=1&pageIndex=0&pageSize=20
结果显示,这个网页没有进行压缩,源文件大小为12KB,而压缩后,文件可减小到0.01KB,可以节省99.92%的传输控件。这是什么概念呢?相当于100MB的数据经过压缩后不到1MB。
说道这里,我们先说一下Http中的Gzip技术细节
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。一般服务器中都安装有这个功能模块的,服务器端不需做改动,当浏览器支持gzip 格式的时候, 服务器端会传输gzip格式的数据。具体讲就是 http request 头中 有 "Accept-Encoding", "gzip" ,response 中就有返回头Content-Encoding=gzip ,我们现在从浏览器上访问玩啥网站都是gzip格式传输的。
同样的的道理,我们可以在android 客户端 request 头中加入 "Accept-Encoding", "gzip" ,来让服务器传送gzip 数据。
首先,客户端发请求给服务端,会带上请求头:Accept-Encoding:gzip。第二步,服务端接收到请求头后,可以选择压缩或不压缩。第三步,服务端选择压缩后,文件明显变小,同时在响应头加上Content-Encoding:gzip。第四步,客户端接收到响应后,根据响应头中是否带有Content-Encoding:gzip,判断文件是否被压缩,如果压缩就进行解压,如果没有压缩,就按照正常方式读取数据即可。
OKhttp3.4.0开始将这些逻辑抽离到了内置的interceptor中,看起来较为方便
在 BridgeInterceptor.java 这个类里边可以看到
如果header中没有Accept-Encoding,默认自动添加 ,且标记变量transparentGzip为true。
针对返回结果,如果同时满足以下三个条件:
移除 Content-Encoding、Content-Length,并对结果进行解压缩。
可以看到以上逻辑完成了,由此我们通过OkHttp源码得出以下结论:
由于引用太多源码就不写了,直接针对以上6点做结果分析
? ? ? ?? Android’s HTTP Clients
? ? ? ?? HttpURLConnection
? ? ? ?? HTTP 协议中的 Transfer-Encoding
深入理解gzip原理
gzip 使用deflate算法进行压缩。gzip 对于要压缩的文件,首先使用LZ77算法的一个变种进行压缩,对得到的结果再使用Huffman编码的方法
如果文件中有两块内容相同的话,那么只要知道前一块的位置和大小,我们就可以确定后一块的内容。所以我们可以用(两者之间的距离,相同内容的长度)这样一对信息,来替换后一块内容。由于(两者之间的距离,相同内容的长度)这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。
举一个例子
有一个文件的内容如下 http://jiurl.yeah.net http://jiurl.nease.net
其中有些部分的内容,前面已经出现过了,下面用()括起来的部分就是相同的部分。 http://jiurl.yeah.net ( http://jiurl.)nease(.net ) 我们使用 (两者之间的距离,相同内容的长度) 这样一对信息,来替换后一块内容。(22,13)中,22为相同内容块与当前位置之间的距离,13为相同内容的长度。(23,4)中,23为相同内容块与当前位置之间的距离,4为相同内容的长度。由于(两者之间的距离,相同内容的长度)这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。
LZ77算法使用"滑动窗口"的方法,来寻找文件中的相同部分,也就是匹配串.
解压缩: 从文件开始到文件结束,每次先读一位标志位,通过这个标志位来判断下面是一个(之间的距离,匹配长度) 对,还是一个没有改动的字节。如果是一个(之间的距离,匹配长度)对,就读出固定位数的(之间的距离,匹配长度)对,然后根据对中的信息,将匹配串输出到当前位置。如果是一个没有改动的字节,就读出一个字节,然后输出这个字节。
LZ77压缩时需要做大量的匹配工作,而解压缩时需要做的工作很少,也就是说解压缩相对于压缩将快的多。这对于需要进行一次压缩,多次解压缩的情况,是一个巨大的优点。
深入理解 要理解这种算法,我们先了解3个关键词:短语字典,滑动窗口和向前缓冲区。 前向缓冲区 每次读取数据的时候,先把一部分数据预载入前向缓冲区。为移入滑动窗口做准备 滑动窗口 一旦数据通过缓冲区,那么它将移动到滑动窗口中,并变成字典的一部分。
短语字典 从字符序列S1...Sn,组成n个短语。比如字符(A,B,D) ,可以组合的短语为{(A),(A,B),(A,B,D),(B),(B,D),(D)},如果这些字符在滑动窗口里面,就可以记为当前的短语字典,因为滑动窗口不断的向前滑动,所以短语字典也是不断的变化。
LZ77的主要算法逻辑就是,先通过前向缓冲区预读数据,然后再向滑动窗口移入(滑动窗口有一定的长度),不断的寻找能与字典中短语匹配的最长短语,然后通过标记符标记。
当压缩数据的时候,前向缓冲区与移动窗口之间在做短语匹配的是后会存在2种情况:
短语标记包含三部分信息:(滑动窗口中的偏移量(从匹配开始的地方计算)、匹配中的符号个数、匹配结束后的前向缓冲区中的第一个符号)。
我们采用图例来看:
1、开始
2、滑动窗口中没有数据,所以没有匹配到短语,将字符A标记为A
3、滑动窗口中有A,没有从缓冲区中字符(BABC)中匹配到短语,依然把B标记为B
4、缓冲区字符(ABCB)在滑动窗口的位移6位置找到AB,成功匹配到短语AB,将AB编码为(6,2,C)
5、缓冲区字符(BABA)在滑动窗口位移4的位置匹配到短语BAB,将BAB编码为(4,3,A)
6、缓冲区字符(BCAD)在滑动窗口位移2的位置匹配到短语BC,将BC编码为(2,2,A)
7、缓冲区字符D,在滑动窗口中没有找到匹配短语,标记为D
8、缓冲区中没有数据进入了,结束
解压类似于压缩的逆向过程,通过解码标记和保持滑动窗口中的符号来更新解压数据。
我们还是采用图例来看下: 1、开始
2、符号标记A解码
3、符号标记B解码
4、短语标记(6,2,C)解码
5、短语标记(4,3,A)解码
6、短语标记(2,2,A)解码
7、符号标记D解码
大多数情况下LZ77压缩算法的压缩比相当高,当然了也和你选择滑动窗口大小,以及前向缓冲区大小有关系。其压缩过程是比较耗时的,因为要花费很多时间寻找滑动窗口中的短语匹配,不过解压过程会很快,因为每个标记都明确告知在哪个位置可以读取了。
哈夫曼树也叫最优二叉树(哈夫曼树)
问题:什么是哈夫曼树?
例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。
判别树:用于描述分类过程的二叉树。
如果每次输入量都很大,那么应该考虑程序运行的时间
如果学生的总成绩数据有10000条,则5%的数据需 1 次比较,15%的数据需 2 次比较,40%的数据需 3 次比较,40%的数据需 4 次比较,因此 10000 个数据比较的
次数为: 10000 (5%+2×15%+3×40%+4×40%)=31500次
此种形状的二叉树,需要的比较次数是:10000 (3×20%+2×80%)=22000次,显然:两种判别树的效率是不一样的。
问题:能不能找到一种效率最高的判别树呢?
那就是哈夫曼树
树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记作:
其中,n表示叶子结点的数目,wi和li分别表示叶子结点ki的权值和树根结点到叶子结点ki之间的路径长度。 赫夫曼树(哈夫曼树,huffman树)定义: 在权为w1,w2,…,wn的n个叶子结点的所有二叉树中,带权路径长度WPL最小的二叉树称为赫夫曼树或最优二叉树。
例:有4 个结点 a, b, c, d,权值分别为 7, 5, 2, 4,试构造以此 4 个结点为叶子结点的二叉树。
WPL=7′2+5′2+2′2+4′2= 36
WPL=7′3+5′3+2′1+4′2= 46
哈夫曼树的构造(哈夫曼算法) 1.根据给定的n个权值{w1,w2,…,wn}构成二叉树集合F={T1,T2,…,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树为空. 2.在F中选取两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左右子树根结点的权值之和. 3.在F中删除这两棵树,同时将新的二叉树加入F中. 4.重复2、3,直到F只含有一棵树为止.(得到哈夫曼树)
哈夫曼树的应用很广,哈夫曼编码就是其在电讯通信中的应用之一。广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。在电讯通信业务中,通常用二进制编码来表示字母或其他字符,并用这样的编码来表示字符序列。
例:如果需传送的电文为 ‘ABACCDA’,它只用到四种字符,用两位二进制编码便可分辨。假设 A, B, C, D 的编码分别为 00, 01,10, 11,则上述电文便为 ‘00010010101100’(共 14 位),译码员按两位进行分组译码,便可恢复原来的电文。
能否使编码总长度更短呢?
实际应用中各字符的出现频度不相同,用短(长)编码表示频率大(小)的字符,使得编码序列的总长度最小,使所需总空间量最少
数据的最小冗余编码问题
在上例中,若假设 A, B, C, D 的编码分别为 0,00,1,01,则电文 ‘ABACCDA’ 便为 ‘000011010’(共 9 位),但此编码存在多义性:可译为: ‘BBCCDA’、‘ABACCDA’、‘AAAACCACA’ 等。
译码的惟一性问题
要求任一字符的编码都不能是另一字符编码的前缀,这种编码称为前缀编码(其实是非前缀码)。 在编码过程要考虑两个问题,数据的最小冗余编码问题,译码的惟一性问题,利用最优二叉树可以很好地解决上述两个问题
以电文中的字符作为叶子结点构造二叉树。然后将二叉树中结点引向其左孩子的分支标 ‘0’,引向其右孩子的分支标 ‘1’; 每个字符的编码即为从根到每个叶子的路径上得到的 0, 1 序列。如此得到的即为二进制前缀编码。
编码: A:0, C:10,B:110,D:111
任意一个叶子结点都不可能在其它叶子结点的路径中。
用哈夫曼树设计总长最短的二进制前缀编码
例:如果需传送的电文为 ‘ABACCDA’,即:A, B, C, D 的频率(即权值)分别为 0.43, 0.14, 0.29, 0.14,试构造哈夫曼编码。
编码: A:0, C:10, B:110, D:111 。电文 ‘ABACCDA’ 便为 ‘0110010101110’(共 13 位)。
译码 从哈夫曼树根开始,对待译码电文逐位取码。若编码是“0”,则向左走;若编码是“1”,则向右走,一旦到达叶子结点,则译出一个字符;再重新从根出发,直到电文结束。
电文为 “1101000” ,译文只能是“CAT”
nginx gzip 压缩比 多少好
随着压缩率的提高,所消耗的CPU也会越来越多,建议值是4,但是DavidYin的建议是直接用5。因为每提高一级压缩,数据就减少大约2到3KB,而从5到6,只有减少大约0.5KB,再之后也几乎没有什么变化了。所以就直接设置 gzip_comp_level 5
对于CPU的消耗,我觉得还是不是那么的厉害,毕竟静态文件,还可以设置过期头,让它的有效缓存期长一点,比如设置成半年一年的。实际上CPU的压力在这上面是没有那么大的。
压缩算法的比较
压缩对象是一个大小为1.7M的csv文件,总共6829行,每行74列,即一行大小为261byte
使用全Double类型(一个Double为8字节)保存一行数据的话,一行为592byte
使用更适合的数据类型时(-125-124用Byte保存,浮点型用Float保存,其余用short保存,各别较大的整数用int保存),一行为143byte
由上图可知当压缩行数为40行时,bzip压缩比例达到11,gzip压缩比例达到9
由上图知,当压缩行数为150时,gzip压缩比例为10并收敛,而bzip压缩比例在行数为500时达到18(行数为1000时压缩比例为20,此处不画出)
由上图知,除bzip外,其余算法压缩时间变化不大,且远下于bzip,bzip算法随着压缩行数增加,压缩时间减少但仍然高于gzip
根据数据以及以上两图,gzip的压缩性价比最好,bzip随着压缩行数增加,性价比提高,但仍比gzip差
压缩能力Bzip > Gzip ≈ Snappy ≈ Lz4 ≈ Lzo
耗费时间 Bzip > Gzip ≈ Snappy ≈ Lz4 ≈ Lzo
压缩性价比 Gzip > Snappy ≈Lz4 ≈ Lzo >Bzip
由上图可知,bzip压缩比例最好,在500行时达到5(不会再变化),gzip次之,在30行时达到3并收敛
由上图可知,bzip压缩耗时最多,并随着压缩行数增加而减少,但仍高于gzip
由上图可知,gzip与snappy压缩性价比相近,而bzip压缩性价比在行数达到150时接近bzip并收敛
如何优化很长的 JSON 数据
1,开启gzip,压缩率很高,即便是很长的文本,在网络中传输量也很小2,不建议分次请求,除非是业务需要。连接次数过多,加大了并发的压力。3,提醒用户点击的做法可以通过按钮反馈或loading条来做4,如果有可能,考虑提前预读你可以这样,在一个隐藏的 iframe 里面请求服务器,返回值是这样的:较长的JSON也没什么问题,现在主要都是靠JSON传输,但是得注意一个问题,别有特殊符号,有特殊符号,很容易出现问题,解析不了,常见的有 \n、\t之类的都有影响。推荐2个解析工具给您。查询数据的时候使用分页查询,减小json的数据量
我们知道,JSON作为一种轻量级的数据交换格式,现在被广泛应用,特别是在API层,返回数据格式基本上都是JSON。但是,JSON字符串如果过长,那在网络传输中也存在耗时的,站在性能角度我们需要合理优化JSON。
JSON优化建议
1、服务器端开启GZip压缩
主流的服务端都支持GZip压缩,对于一般的纯文本内容GZip压缩率在35%以上,这样做的好处也很明显:
减少JSON输出大小,网络传输速度更快;
节省带宽。
2、键名缩短
对于结果集而言,数据都是查询循环输出的,所以当我们把键名缩短也变相压缩了JSON文本长度。比如原本的 {"name":"张三"} 我们可以写为 {"a":"张三"}
3、JSON中的中文避免被转为Unicode编码
现在也有不少人喜欢将JSON中的汉字转为Unicode编码,此时JSON文本内容就会变得很长,如果避免汉字转码,可以控制文本长度。
以上就是我的观点,对于这个问题大家是怎么看待的呢?欢迎在下方评论区交流 ~ 我是科技领域创作者,十年互联网从业经验,欢迎关注我了解更多科技知识!
网页弄个gzip压缩 好还是不好
网站启用Gzip压缩:Gzip开启以后会将输出到用户浏览器的数据进行压缩的处理,这样就会减小通过网络传输的数据。Gzip可以极大的加速网站,有时压缩比率高到80%。
当然好啊,可以减小空间的使用量啊,不过如果你的空间够大,压缩不压缩都可以
gzip 能够压缩文本,减小网页的html代码体积,加快传输到用户浏览器的速度。
虽然压缩会耗用服务器一点资源,但从各方面来说,开起来总是会好点的。
如果你的网站整体有很多图片,开起来效果不明显。
如何在 apache 中开启 gzip 压缩服务
服务器设置 gzip 压缩是 web 开发里很普遍的做法。假设你要请求一个 100k 的文件,网络传输速度为 50k/s,需要 2s 才能得到数据,但是如果在服务器设置了 gzip 压缩,将服务端的文件压缩到了 50k(实际上的压缩率往往小于 50%),这时候只需 1s 就能得到数据,然后在客户端解压即可。
可以对比下同一个文件在开启 gzip 前后的大小。
gzip 压缩前:
gzip 压缩后:
那么如何在服务端开启 gzip 服务呢?这里以 apache 为例简单介绍下。
打开 apache 的 "httpd.conf" 文件,比如我的是在 "C:\wamp\bin\apache\Apache2.2.21\conf" 目录下。找到以下这一行,将它前面的注释(#)去掉:
很多参考文件都提到同时要对 LoadModule headers_module modules/mod_headers.so 去掉注释,说 "如果不开启这个,那网站就不能正常显示了" ,不过我在测试过程中没有去掉也没有问题。
接着再添上以下代码:
这样就能对所有文件进行 gzip 压缩了。压缩等级是个 1-9 之间的整数,取值范围在 1(最低) 到 9(最高)之间,不建议设置太高,虽然有很高的压缩率,但是占用更多的CPU资源。(本地测试了下 1 和 9 压缩率差不了多少...)
实际开发中我们并不需要对所有文件进行压缩,比如我们无需对图片文件进行 gzip 压缩,因为图片文件(一般为 jpg、png等格式)本身已经压缩过了,再进行 gzip 压缩可能会适得其反(详见 图片要启用gzip压缩吗?绝对不要!,背景图片千万不要gzip压缩,尤其是PNG),类似的还有 PDF 以及音乐文件。所以我们可以设置过滤指定文件或者对指定文件进行压缩。
比如我们要对图片等特殊文件不进行 gzip 压缩处理:
或者指定文件格式进行压缩:
修改好后,保存 httpd.conf 文件,记得重启 apache,再刷新浏览器看请求,应该已经生效了!
把纯文本字符串用Gzip压缩再转换为Base64能有多少压缩率
其实具体多大压缩率要看源文件的内容,一般来说重复的单词越多,压缩率越高。
下面是把/usr/share/dict/words压缩的测试程序
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.codec.binary.Base64;
public class GzipBase64Tests {
public static void main(String[] args) throws Exception {
File input = new File("/Users/matianyi/input.txt");
File output = new File("/Users/matianyi/output.txt");
if (!input.exists()) {
System.out.println("input file not exists!");
return;
}
if (output.exists()) {
output.delete();
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
GZIPOutputStream gout = new GZIPOutputStream(buffer);
FileInputStream in = new FileInputStream(input);
long t1 = System.currentTimeMillis();
byte[] buf = new byte[1024];
int total=0;
int rd;
while ((rd = in.read(buf)) != -1) {
total += rd;
gout.write(buf,0, rd);
}
gout.close();
in.close();
byte[] result = buffer.toByteArray();
long t2 = System.currentTimeMillis();
String base64 = Base64.encodeBase64String(result);
long t3 = System.currentTimeMillis();
System.out.printf("raw %d -> gzip %d -> base64 %d, time1 %dms, time2 %dms", total, result.length, base64.length(), t2-t1, t3-t2);
}
}
输出为: raw 2493109 -> gzip 753932 -> base64 1005244, time1 225ms, time2 43ms
压缩了50%。
跪求!ZIP.GZIP.TAR有啥区别?那个压缩的程度大?急!
tar没有怎样压缩,压缩率100%,主要是永远打包,
zip压缩率看文件类型,jpg就没怎么压缩率,但bmp很高
gzip一般比zip高
tar是打包,不是压缩,只是把一堆文件打成一个文件而已GZIP用在HTTP协议上是一种用来改进WEB应用程序性能的技术,将网页内容压缩后再传输。zip就不用说了,主流的压缩格式。zip最新的压缩算法还是很好的,建议还是用zip格式化,全平台通用。