1 问题

  术语:压缩率,compression ratio,压缩后的大小/压缩前的大小,越小说明压缩效果越好。

  在使用netty的JdkZlibEncoder进行压缩时,发现了一个问题:它对于短文本(小于2K)的压缩效果很差,压缩率在80%-120%,文本越短,压缩效果越差,甚至可能比没压缩前更大。

  通过研究发现,使用字典可以改进压缩效果。以下详细介绍如何做。

2 提取字典

  我们要传输的文本类似于:

 <?xml version="1.0" encoding="utf-8" ?>
<Event attribute="TRANSIENT">
<outer id="" from="" to="" trunk="" callid=""/>
<ext id=""/>
</Event>

  提取字典的原则:将重复出现的字符串加入到字典。

  可以提取以下字典:

 String[] dictionary = {
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
"Event", "TRANSIENT", "attribute", "outer", "from", "trunk",
"callid", "id", "to", "ext"
};
 

3 测试用例

  使用EmbeddedChannel API来构建测试用例。EmbeddedChannel能够模拟入站和出站的数据流,对于测试ChannelHandler非常有用。

  JdkZlibEncoder的构造函数可以接受一个字典参数:

  下面是测试代码:

 public class GzipTest {

     private String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<Event attribute=\"TRANSIENT\">" +
"<outer id=\"11\" from=\"1005\" to=\"915880056212\" trunk=\"83057387\" callid=\"24587\" />" +
"<ext id=\"1005\" />" +
"</Event>"; private String[] dictionary = {
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
"Event", "TRANSIENT", "attribute", "outer", "from", "trunk",
"callid", "id", "to", "ext"
}; /**
* 不使用字典压缩
*/
@Test
public void test1() {
EmbeddedChannel embeddedChannel = new EmbeddedChannel();
ChannelPipeline pipeline = embeddedChannel.pipeline();
//
pipeline.addLast("gzipDecoder", new JdkZlibDecoder());
pipeline.addLast("gzipEncoder", new JdkZlibEncoder(9));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
//
System.out.println("*******不使用字典压缩*******");
int compressBefore = xml.getBytes(StandardCharsets.UTF_8).length;
System.out.printf("压缩前大小:%d \n", compressBefore);
// 模拟输出
embeddedChannel.writeOutbound(xml);
ByteBuf outboundBuf = embeddedChannel.readOutbound();
int compressAfter = outboundBuf.readableBytes();
System.out.printf("压缩后大小:%d, 压缩率:%d%% \n", compressAfter,
compressAfter * 100 / compressBefore); } /**
* 使用字典压缩
*/
@Test
public void test2() {
EmbeddedChannel embeddedChannel = new EmbeddedChannel();
ChannelPipeline pipeline = embeddedChannel.pipeline();
// 字典
byte[] dictionaryBytes = String.join("", dictionary)
.getBytes(StandardCharsets.UTF_8);
//
pipeline.addLast("gzipDecoder", new JdkZlibDecoder(dictionaryBytes));
pipeline.addLast("gzipEncoder", new JdkZlibEncoder(9, dictionaryBytes));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
//
System.out.println("*******使用字典压缩*******");
int compressBefore = xml.getBytes(StandardCharsets.UTF_8).length;
System.out.printf("压缩前大小:%d \n", compressBefore);
// 模拟输出
embeddedChannel.writeOutbound(xml);
ByteBuf outboundBuf = embeddedChannel.readOutbound();
int compressAfter = outboundBuf.readableBytes();
System.out.printf("压缩后大小:%d, 压缩率:%d%% \n", compressAfter,
compressAfter * 100 / compressBefore);
} }

输出:

*******不使用字典压缩*******

压缩前大小:173

压缩后大小:150, 压缩率:86%

*******使用字典压缩*******

压缩前大小:173

压缩后大小:95, 压缩率:54%

  从输出可以看到,压缩率由86%提升至了54%。

4 进一步

  如果觉得手工提取字典效率太低,还可以试一下zstd。zstd是由facebook提供的一个压缩库,它提供了自动提取字典的工具。命令如下:

 zstd --train ./dictionary/* -o ./dict.bin

5 参考资料

zstd github

文本压缩算法的对比和选择

netty 使用字典提升短文本的压缩效果的更多相关文章

  1. redis底层数据结构--简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表

    1.动态字符串 redis中使用c语言的字符床存储字面量,默认字符串存储采用自己构建的简单动态字符串SDS(symple dynamic string) redis包含字符串的键值对都是用SDS实现的 ...

  2. 【redis】redis底层数据结构原理--简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表等

    redis有五种数据类型string.list.hash.set.zset(字符串.哈希.列表.集合.有序集合)并且自实现了简单动态字符串.双端链表.字典.压缩列表.整数集合.跳跃表等数据结构.red ...

  3. APK瘦身记,如何实现高达53%的压缩效果

    作者:非戈@阿里移动安全 1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式,关于这个话题其实是一个老生常谈的题目,不论是公司内部,还是外部网络,前人前辈已经总结出很多方法和规律. ...

  4. APK瘦身记,怎样实现高达53%的压缩效果

    作者:非戈@阿里移动安全,很多其它技术干货.请訪问阿里聚安全博客 1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式.关于这个话题事实上是一个老生常谈的题目.不论是公司内部.还是外 ...

  5. nginx_gzip压缩提升网站的传输速度

    gzip on; gzip_min_length 1k; gzip_buffers 16k; #gzip_http_version 1.0; gzip_comp_level ; gzip_types ...

  6. Netty 系列之 Netty 高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用 Netty4 + Thrift 压缩二进制编解码技术,他们实现了 10 W TPS(1 K 的复杂 POJO 对象)的跨 ...

  7. Netty系列之Netty高性能之道

    转载自http://www.infoq.com/cn/articles/netty-high-performance 1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Ne ...

  8. Netty高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用.相比于 ...

  9. 转:Netty系列之Netty高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用 ...

随机推荐

  1. 且谈 Apache Spark 的 API 三剑客:RDD、DataFrame 和 Dataset

    作者:Jules S. Damji 译者:足下 本文翻译自 A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets ,翻译已 ...

  2. Docker入门(1):概述

    1.摘要 在这篇文章中,我将介绍一下为什么需要虚拟化的环境. 然后我将介绍耳熟能详的虚拟化技术:虚拟机,并大致的介绍一下虚拟机的原理,希望能够让你知道虚拟机的优劣. 在之后,针对虚拟机存在的问题,引出 ...

  3. jquery入门(3)

    4.jQuery中的事件绑定 4.1.事件绑定 on方法绑定 $('#box').on('click',function(){ alert(1); }) 直接绑定 $("#box" ...

  4. 001_Linux常用命令之ls命令

    1. 认识Linux系统目录结构 /bin 可执行文件所在目录 /media 挂载设备媒体,u盘,光驱等 /mnt 该目录主要是为了让用户挂在别的文件系统(挂在自己的u盘) /usr unix sys ...

  5. C# 做的Windows 应用程序 服务

    运行服务: ,cmd下进入目录 cd C:\Windows\Microsoft.NET\Framework\v4.0.30319\ ,安装服务 installutil F:\中原集团\天津CCHR\t ...

  6. 利用 Nginx 实现限流

    在当下互联网高并发时代中,项目往往会遇到需要限制客户端连接的需求.我们熟知的 Nginx 就提供了有这样的功能,可以简单的实现对客户端请求频率,并发连接和传输速度的限制…. Nginx 限流 Ngin ...

  7. scala数据结构(一)

    一.概述 1,特点 )Scala同时支持不可变集合和可变集合 )两个主要的包: 不可变集合:scala.collection.immutable 可变集合: scala.collection.muta ...

  8. CentOS7下安装Docker《超详细新手教程》

    1.使用 root 权限登录 Centos.确保 yum 包更新到最新. sudo yum update 2.卸载旧版本(如果安装过旧版本的话) sudo yum remove docker dock ...

  9. UiAutomator源码学习(2)-- UiAutomationBridge

    从上一章对UiDevice的学习,可以看出几乎所有的操作都离不开 UiAutomationBridge.重新看一下UIDevice的构造方法: private UiDevice(Instrumenta ...

  10. vue 仿掘金评论列表

    先来个最终效果 代码: template代码: <template> <div class="main"> <div class="titl ...