解放你的带宽和内存:GZIP在解决Redis大Key方面的应用

2024-09-04 03:04

本文主要是介绍解放你的带宽和内存:GZIP在解决Redis大Key方面的应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首发公众号:赵侠客

引用

目前主流HTTP协议接口都是使用JSON格式做数据交换的,JSON数据格式有着结构简单、可读性高、跨平台,易解析等优点,同时也存在着冗余数据会占用非常多的储存空间的问题,这大大增加了JSON格式数据在存储、传输过程中的性能消耗。所以对JSON格式数据压缩后再传输、存储就变的非常的有价值,如对JSON格式数据使用GZIP压缩算法可以实现90%左右的压缩率,更小的空间可以节省存储成本和降低传输带宽成本,本文介绍GZIP压缩算法在优化Redis使用大KEY字段中的应用,通过简单压缩可以节省88%的内存空间和带宽资源。

HTTP协议开启GZIP

HTTP协议标准中是直接支持GZIP压缩算法的,通过响应头Content-Encoding: gzip来表明响应内容使用了GZIP压缩,当客户端收到数据后会使用GZIP算法对Body内容进行解压。

RFC 1952 - IETF(互联网工程任务组)标准化的Gzip文件格式规范,

RFC 2616 - HTTP 1.1 协议规范,其中包括对 Content-Encoding 头的定义

在Nginx中可以通过 gzip on开启GZIP压缩功能:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

在Springboot中可以通过server.compression.enabled开启GZIP压缩功能:

server:port: 80compression:enabled: truemime-types:  application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plainmin-response-size: 2KB
  • enabled,开启或关闭
  • mime-types,压缩的数据类型
  • min-response-size,最小压缩大小

测试GZIP

为了测试开启GZIP前后的对比效果我们写一个简单的接口:

@GetMapping("/list")
public ResponseEntity<ApiResult> list() {return renderOk(getData());
}

我们返回1000条JSON格式的用户信息:


private List<UserVo> getData() {return IntStream.range(1, 1000).mapToObj(x -> new UserVo(x,x+"+email@q63.com",x+"_公众号",x+"_赵侠客")).collect(Collectors.toList());
}
@Data
@AllArgsConstructor
public class UserVo {private Integer id;private String username;private String email;private String trueName;
}

在未开启GZIP前接口返回数据的大小是92.8KB, Content-Encoding为空,在开启GZIP后接口返回的数据大小为11.5KB,Content-Encoding为gzip,接口返回数量降低了88%。
开启GZIP前后对比

当然我们也可以在接口中通过手动添加content-encoding响应头,然后通过手动调用GZIPOutputStream对返回数据进行GZIP压缩:

@GetMapping("/gzip")
public void gzip(HttpServletResponse response) throws IOException {response.setContentType("application/json;charset=utf-8");response.setHeader("content-encoding", "gzip");try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(response.getOutputStream())) {IOUtils.write(JsonUtils.toJson(getData()), gzipOutputStream);}
}

Redis缓存压缩

为了增加接口的响应速度我们通常会使用Redis当缓存,基本逻辑是先查Redis有没有数据如果有直接返回,如果没有会查数据库,然后再存入Redis,以下是一个简单的使用Redis当缓存的接口:

@Resource
private RedissonClient redissonClient;
public static final String REDIS_KEY = "REDIS_KEY";@GetMapping("/redis")
public void redis(HttpServletResponse response) throws IOException {RBucket<String> bucket = redissonClient.getBucket(REDIS_KEY);String data = bucket.get();if (data == null) {data=JsonUtils.toJson(getData());redissonClient.getBucket(REDIS_KEY).set(data,100L, TimeUnit.SECONDS);}response.setContentType("application/json");IOUtils.write(data, response.getOutputStream());
}

我们分析一下这样个接口的基本数据流:

  • 第一次从数据库服务器查出92.8KB的数据传输到WEB服务器中
  • 将92.8KB的数据从WEB服务器传输到Redis服务器中
  • 后面如果命中缓存将92.8KB数据从Redis服务器传输到WEB服务器
  • 最后将92.8KB数据从WEB服务器返回给用户浏览器

使用Redis当缓存加速接口

使用ZIP优化Redis缓存:


public static final String GZIP_REDIS_KEY = "GZIP_REDIS_KEY";@GetMapping("/gzipRedis")
public void gzipRedis(HttpServletResponse response) throws IOException {RBucket<byte[]> bucket = redissonClient.getBucket(GZIP_REDIS_KEY);byte[] data = bucket.get();if (data == null) {String json=JsonUtils.toJson(getData());try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) {IOUtils.write(json, gzipOutputStream, String.valueOf(StandardCharsets.UTF_8));gzipOutputStream.finish();data= byteArrayOutputStream.toByteArray();redissonClient.getBucket(GZIP_REDIS_KEY).set(data,100L, TimeUnit.SECONDS);}}response.setContentType("application/json");response.setHeader("content-encoding", "gzip");IOUtils.write(data, response.getOutputStream());
}

使用GZIP压缩后的缓存接口

我们再分析一下以上使用GZIP压缩后的数据传输:

  • 第一次从数据库服务器查出92.8KB的数据传输到WEB服务器中
  • 将11.5KB的GZIP数据从WEB服务器传输到Redis服务器中
  • 后面命中缓存将11.5KB数据从Redis服务器传输到WEB服务器
  • 最后将11.KB数据从WEB服务器返回给用户浏览器

GZIP压缩后的Redis缓存

单次接口请求好像感觉不到这个 GZIP压缩带来的好处,接下来我们压测一下看看会不会有差距。

压力测试

压测可以使用ab (Apache Benchmark) 工具,ab工具是 Apache HTTP server 的一部分,在 macOS使用Homebrew包管理器可以快速安装上ab :

brew install httpd
ab -V
ab -n 100 -c 10 http://localhost/list

其中:

  • -n 100 表示总共请求 100 次。
  • -c 10 表示并发 10 个请求。

未压缩走Redis压缩结果:


ab -n 100000 -c 10 http://localhost/redisFinished 100000 requests
Document Length:        92476 bytes
Concurrency Level:      10
Time taken for tests:   194.917 seconds
Complete requests:      100000
Failed requests:        0
Total transferred:      9258100000 bytes
HTML transferred:       9247600000 bytes
Requests per second:    513.04 [#/sec] (mean)
Time per request:       19.492 [ms] (mean)
Time per request:       1.949 [ms] (mean, across all concurrent requests)
Transfer rate:          46384.34 [Kbytes/sec] receivedConnection Times (ms)min  mean[+/-sd] median   max
Connect:        0    8 249.5      0   19514
Processing:     4   12  19.8     10     754
Waiting:        4   11  19.8     10     754
Total:          4   19 250.4     10   19525
Percentage of the requests served within a certain time (ms)50%     1066%     1175%     1180%     1290%     1295%     1598%     2799%    134100%  19525 (longest request)

使用GZIP压缩后走Redis缓存压测结果:

ab -n 100000 -c 10 http://localhost/gzipRedisFinished 100000 requests
Document Length:        11091 bytes
Concurrency Level:      10
Time taken for tests:   194.927 seconds
Complete requests:      100000
Failed requests:        0
Total transferred:      1122000000 bytes
HTML transferred:       1109100000 bytes
Requests per second:    513.01 [#/sec] (mean)
Time per request:       19.493 [ms] (mean)
Time per request:       1.949 [ms] (mean, across all concurrent requests)
Transfer rate:          5621.09 [Kbytes/sec] receivedConnection Times (ms)min  mean[+/-sd] median   max
Connect:        0   12 410.4      0   19608
Processing:     3    7  20.0      4     802
Waiting:        3    7  19.9      4     801
Total:          3   19 410.9      4   19613Percentage of the requests served within a certain time (ms)50%      466%      975%      980%      990%     1095%     1098%     1199%     19100%  19613 (longest request)

总结

对比使用GZIP压缩我们可以得出以下几点:

  • 测试中10万请求在194S完成,缓存时间是100S,服务器端只做了二次查数据库和GZIP压缩然后存数Redis
  • 两次GZIP和之后的数据传输消耗资源可以忽略不计
  • 未压缩10万请求从Redis传输了8.6GB数据到WEB服务器,又从WEB服务器传输8.6GB给用户浏览器,
  • 压缩10万请求从Redis传输了1GB数据到WEB服务器,又从WEB服务器传输1GB给用户浏览器,节省数据传输15.2GB,节省率88%
  • 未压缩数据传输速度达到45M/S,压缩后5.4M/S,节省带宽88%
  • 如果Redis中大JSON都使用GZIP压缩理论上可以节省Redis内存达到88%
  • 因为直接使用gzip返回,所有解压计算在用户浏览器端完成,不消耗服务器CPU资源

请求10万次数据传输流程

综合上所述如里你的Redis缓存中存在大量的大Key,可能先达到瓶颈的不是Redis的读写性能,很可能是你的带宽,此时只需要简单的使用GZIP压缩就能你给不仅节省88%的Redis内存空间还大大减少了数据的传输量和节省了带宽资源,而且还能使用的C端用户的资源来解压,这个ROI是非常高的。

这篇关于解放你的带宽和内存:GZIP在解决Redis大Key方面的应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134817

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

如何解决线上平台抽佣高 线下门店客流少的痛点!

目前,许多传统零售店铺正遭遇客源下降的难题。尽管广告推广能带来一定的客流,但其费用昂贵。鉴于此,众多零售商纷纷选择加入像美团、饿了么和抖音这样的大型在线平台,但这些平台的高佣金率导致了利润的大幅缩水。在这样的市场环境下,商家之间的合作网络逐渐成为一种有效的解决方案,通过资源和客户基础的共享,实现共同的利益增长。 以最近在上海兴起的一个跨行业合作平台为例,该平台融合了环保消费积分系统,在短

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

AI行业应用(不定期更新)

ChatPDF 可以让你上传一个 PDF 文件,然后针对这个 PDF 进行小结和提问。你可以把各种各样你要研究的分析报告交给它,快速获取到想要知道的信息。https://www.chatpdf.com/