问题的开始

我司某产品线有这么一个神奇接口 (https://host/path/customQuery)

该接口在预发或线上缓存正常的情况下TTFB为150ms左右(可以认为服务处理时间差不多就是TTFB),不过相比150ms的TTFB,显然数据资源下载时间过长的问题会更引人注意需要100ms左右(当然这也是网络条优秀的情况下,网络一般的话这个下载时间会更夸张)
customQuery请求一次请求的数据响应大概为2.7MB, 压缩后也有超过300KB
下载时间过长看起来就是因为这个响应实体过大了(100Mb的带宽满速,300KB差不多也需要30ms),通过测试可以发现同样的网络条件同一个应用的其他接口,如果响应压缩后小于1KB,其ContentDownLoad时间可以忽略不计(通常都会小于2ms)
因为代理默认开启了gzip,其实数据已经被压缩了近10倍,但是压缩后的数据还是过大。
分析了customQuery响应实体的数据结构。
发现数据每个list中fields节点大量重复出现。

如上图其中field的描述是完全一致的(按一页50条计算,这些数据重复了50遍)
这些数据field描述数据单个都大小大概是50KB(重复50次可以看到2.7MB的数据几乎都是这些重复的数据)

开始秀了

既然已经明确了这些重复描述数据,服务端的同学很自然想到把这些field描述提取出来重新组装数据可以大幅度减小数据传输的大小。
不过自己恰好曾经“看过”DEFLATE压缩(http的gzip正好使用的是DEFLATE)其中使用到的LZ77是会匹配前文相同短语后面的相同短语都会被替换成“标记”。
那我“秀”的时候又到了,当即表示采用这种数据重组的方式并不会带来明显的实际提升,因为数据实际的信息量没有实际变化,只是手动去除了冗余,而之前冗余的数据其实已经被gzip处理过了,所以仅仅单纯去除重复描述数据片段并不能带来预期的收益。
因为我秀的时候如此自信,对方马上就自己不自信了,表示要回去先验证效果后在做打算。

看起来是失败了

果然后面的结果“居然”是我被打脸了

customQuery接口返回的实体大小直接变成了25kb,解压后189kb(之前是327kb,解压后2.7Mb)

那这差距太大了,实体大小减小到了之前的10%不到,当然下载速度ContentDownLoad也有了大幅度的降低。(基本上就是一个RTT的时间)
不过这完全跟我之前的认知不一样啊,一定是哪里出现了问题。(毕竟是以为自己懂了系列)

试图抢救下

为了挽回颜面,我把这2组原始数据下载下来,本地压缩进行分析(还不想承认自己错了,试图找到产生这种结果的其他解释)

如下图老的数据为customQuery_v1(2.7MB),新的为customQuery_v2(190KB)

分别使用zip,gzip,rar对2组数据进行压缩 (gzip即为http默认使用的压缩算法,MAC上直接使用gzip命令可以对文件进行压缩)
可以发现RAR的压缩结果就与我最开始的想法差不多(即使原始数据差了超过10倍,而压缩的结果是几乎一致的,v1为19kb ;v2为17kb)
不过gzip对2组数据的压缩结果与在浏览器上看到的是一样的。(v1为329kb ;v2为25kb)
既然本地压缩也得到了同样的结果,看来真的是自己Too young too naive (大意了,没有闪,秀的时候应该先在本地验证一下的)

默默面对错误分析原因

但是为什么会有这样的结果,按我的理解压缩结果应该与rar一致才对。要搞清楚还要从压缩的方式入手。
一定是我以为的压缩行为与实际存在差异,gzip的基础是DEFLATE,DEFLATE是LZ77哈夫曼编码的一个组合体( https://tools.ietf.org/html/rfc1951
Huffman Coding 只是单纯的字符编码,编码后的大小与编码前的大小直接正相关,肯定不是产生结果的原因。
那剩下就只有是LZ77,只能是LZ77一开始没有把那些重复的fields压缩掉,而为什么LZ77没有把原始数据里大量重复的描述“标记”起来。
LZ77整体是是使用已经出现过的相应匹配数据信息替换当前数据从而实现压缩功能,为了匹配数据需要用到了“滑动窗口”的概念
细细一品,LZ77并不是全文匹配,数据为了可以边发送边压缩会进行分块压缩。通过查阅RFC文档,大概可以明确块的大小被限制在64k内,最大滑动窗口就是64k/2=32k,并且还要求“标记”的最大长度为256字节(当然标记长度这个问题不大,大不了不多用几个标记)。这里的问题在于使用滑动窗口就要求重复的数据必须要“相邻” 而块大小最大为64K,如果重复的2段数据不能出现在一个窗口内是不能被标记的。但是窗口最多是块大小的一半32Kb(实际也不会用这么大的窗口),而我们之前就计算过我们重复的单个field描述就有50Kb,要出现有2个重复的内容,即使2个描述相邻那也至少上100Kb(他们甚至都无法在同一个块里),实际上窗口最大32Kb,所以LZ77根本不能标记出这些重复的field。

以下引至https://tools.ietf.org/html/rfc1951#section-2

Compressed representation overview

A compressed data set consists of a series of blocks, corresponding
to successive blocks of input data. The block sizes are arbitrary,
except that non-compressible blocks are limited to 65,535 bytes.

Each block is compressed using a combination of the LZ77 algorithm
and Huffman coding. The Huffman trees for each block are independent
of those for previous or subsequent blocks; the LZ77 algorithm may
use a reference to a duplicated string occurring in a previous block,
up to 32K input bytes before.

Each block consists of two parts: a pair of Huffman code trees that
describe the representation of the compressed data part, and a
compressed data part. (The Huffman trees themselves are compressed
using Huffman encoding.) The compressed data consists of a series of
elements of two types: literal bytes (of strings that have not been
detected as duplicated within the previous 32K input bytes), and
pointers to duplicated strings, where a pointer is represented as a
pair <length, backward distance>. The representation used in the
"deflate" format limits distances to 32K bytes and lengths to 258
bytes, but does not limit the size of a block, except for
uncompressible blocks, which are limited as noted above.

Each type of value (literals, distances, and lengths) in the
compressed data is represented using a Huffman code, using one code
tree for literals and lengths and a separate code tree for distances.
The code trees for each block appear in a compact form just before
the compressed data for that block.

总结

最终也还是自己错了,也没有什么好总结的

要是什么都不知道也不出问题,要是知道的很清楚也不会出问题,就是在“以为自己知道”的情况下就各种问题。

 

被自己以为的GZIP秀到了的更多相关文章

  1. Linux常见压缩命令 - gzip,zcat,bzip2,bzcat

    几个常见的压缩文件扩展名 *.Z compress 程序压缩的文件: *.gz gzip 程序压缩的文件: *.bz2 bzip2 程序压缩的文件: *.tar tar 程序打包的数据,并没有压缩过: ...

  2. Android总结之Gzip/Zip压缩

    前言: 做过Android网络开发的都知道,在网络传输中我们一般都会开启GZIP压缩,但是出于刨根问底的天性仅仅知道如何开启就不能满足俺的好奇心的,所以想着写个demo测试一下比较常用的两个数据压缩方 ...

  3. 易企秀微场景2016最新完整版V10.5,小编亲测修复众多错误

    易企秀V10.5更新说明1.修复拨号英文错误2.修复转送场景问题3.修复设置场景密码乱码问题4.修复前台批量删除客户图片5.修复数据收集分页问题6.修复图片分类错乱问题7.修复音乐和特效冲突问题8.修 ...

  4. Android GZIP压缩IO流,优化APP数据传输(一)

    我是小搬运工,今天讲解流的压缩传输 在我们安卓开发中,通常伴随着大量的数据传输,在此,楼主给出一个简单的压缩流的数据进行操作. public void GZIPCpf(String path) { / ...

  5. ASP.NET MVC 3 网站优化总结(一) 使用 Gzip 压缩

    网站开启 Gzip 压缩的好处相信很多人都已经清楚,这样做可以提高网站的性能.那么为什么很多网站没有开启 Gzip 压缩功能呢?原因有4点:防病毒软件.浏览器 bug.网站代理和服务器未配置. 使用 ...

  6. 压缩和解压文件:tar gzip bzip2 compress(转)

    tar[必要参数][选择参数][文件] 压缩:tar -czvf filename.tar.gz targetfile解压:tar -zxvf filename.tar.gz参数说明: -c 建立新的 ...

  7. Linux下的压缩和解压缩命令——gzip/gunzip

    gzip命令 gzip命令用来压缩文件.gzip是个使用广泛的压缩程序,文件经它压缩过后,其名称后面会多处".gz"扩展名. gzip是在Linux系统中经常使用的一个对文件进行压 ...

  8. php关于ob_start('ob_gzhandler')启用GZIP压缩的bug

    如果使用ob_start("ob_gzhandler"); 则ob_clean()后面的输出将不显示,这是个bug,可以用ob_end_clean();ob_start(" ...

  9. 使用HttpClient来异步发送POST请求并解析GZIP回应

    .NET 4.5(C#): 使用HttpClient来异步发送POST请求并解析GZIP回应 在新的C# 5.0和.NET 4.5环境下,微软为C#加入了async/await,同时还加入新的Syst ...

随机推荐

  1. 无需付费,教你IDEA社区版中开发Web项目(SpringBoot\Tomcat)

    1.IDEA 版本介绍 最近有小伙伴私信我说 IDEA 破解怎么总是失效?难道就没有使用长一点的吗... 咳咳,除了给我留言「激活码」外,或许社区版可能完全满足你的需求. 相信有挺多小伙伴可能不清楚或 ...

  2. 原创题目 白银之春 Problem and Solution

    白银之春 Solution 比赛用题面.题解.标程和数据生成器都挂在 git@github.com:sun123zxy/spring.git 上. Problem 白银之春 (spring.cpp/. ...

  3. PyQt(Python+Qt)学习随笔:Qt Designer中部件的autoFillBackground属性

    autoFillBackground属性可以确认部件背景是否自动填充,如果自动填充,Qt会在调用Paint事件之前填充部件的背景.使用的颜色由部件调色板中的QPalette.window 角色定义(关 ...

  4. 写了一个类似与豆瓣的电影的flask小demo

    先展示页面 基本的功能是都已经实现了,更多那个地方是可以点的.只不过视频上面还用的宏,哎呀,感觉麻烦.有多麻烦呢,需要先定义一个宏,然后进行引用.我们才能是用,以我的观点,还不如直接是一个循环完事.. ...

  5. SQL Server 批量插入数据方案 SqlBulkCopy 的简单封装,让批量插入更方便

    一.Sql Server插入方案介绍 关于 SqlServer 批量插入的方式,有三种比较常用的插入方式,Insert.BatchInsert.SqlBulkCopy,下面我们对比以下三种方案的速度 ...

  6. jsonp使用post方法

    来源https://www.jb51.net/article/68980.htm

  7. 【题解】Generator(UVA1358)

    感觉我字符串和期望都不好-- 题目链接 题意 有 \(n\) 种字符,给定一个模式串 \(S\) ,一开始字符串为空,现在每次随机生成一个 1~n 的字符添加到字符串末尾,直到出现 \(S\) 停止, ...

  8. 三、java多线程核心技术(笔记)——线程的优先级

    概论: 在操作系统中,线程可以划分优先级,优先级高的获得的CPU资源较多,也就是CPU优先执行优先级较高的线程.在JAVA中线程的优先级 分1~~10个10个等级.大于或者小于会报异常. 一.线程优先 ...

  9. nginx根据http请求,将JSON的请求转发到后端,将非JSON请求,转发到前端

    nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; defaul ...

  10. Java8新特性探索之新日期时间库

    一.为什么引入新的日期时间库 Java对日期,日历及时间的处理一直以来都饱受诟病,尤其是它决定将java.util.Date定义为可修改的以及将SimpleDateFormat实现成非线程安全的. 关 ...