发布时间:2025-11-05 02:45:03 来源:创站工坊 作者:IT科技类资讯
目前主流HTTP协议接口都是释放使用JSON格式做数据交换的,JSON数据格式有着结构简单、成的存可读性高、宽大跨平台,和内易解析等优点,解决同时也存在着冗余数据会占用非常多的释放储存空间的问题,这大大增加了JSON格式数据在存储、成的存传输过程中的宽大性能消耗。所以对JSON格式数据压缩后再传输、和内存储就变的解决非常的有价值,如对JSON格式数据使用GZIP压缩算法可以实现90%左右的释放压缩率,更小的成的存空间可以节省存储成本和降低传输带宽成本,本文介绍GZIP压缩算法在优化Redis使用大KEY字段中的宽大应用,通过简单压缩可以节省88%的和内内存空间和带宽资源。
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;1.2.在Springboot中可以通过server.compression.enabled开启GZIP压缩功能:
复制server: port: 80 compression: enabled: true mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain min-response-size: 2KB1.2.3.4.5.6. enabled,开启或关闭mime-types,压缩的数据类型min-response-size,最小压缩大小为了测试开启GZIP前后的对比效果我们写一个简单的接口:
复制@GetMapping("/list") public ResponseEntity<ApiResult> list() { return renderOk(getData()); }1.2.3.4.我们返回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; }1.2.3.4.5.6.7.8.9.10.11.在未开启GZIP前接口返回数据的大小是92.8KB, Content-Encoding为空,在开启GZIP后接口返回的数据大小为11.5KB,Content-Encoding为gzip,接口返回数量降低了88%。
当然我们也可以在接口中通过手动添加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); } }1.2.3.4.5.6.7.8.为了增加接口的响应速度我们通常会使用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()); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.我们分析一下这样个接口的基本数据流:
第一次从数据库服务器查出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 jsnotallow=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()); }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.
使用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/list1.2.3.其中:
-n 100 表示总共请求 100 次。-c 10 表示并发 10 个请求。未压缩走Redis压缩结果:
复制ab -n 100000 -c 10 http://localhost/redis Finished 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] received Connection 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% 10 66% 11 75% 11 80% 12 90% 12 95% 15 98% 27 99% 134 100% 19525 (longest request)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.29.30.31.使用GZIP压缩后走Redis缓存压测结果:
复制ab -n 100000 -c 10 http://localhost/gzipRedis Finished 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] received Connection 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 19613 Percentage of the requests served within a certain time (ms) 50% 4 66% 9 75% 9 80% 9 90% 10 95% 10 98% 11 99% 19 100% 19613 (longest request)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.29.30.31.32.对比使用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是非常高的。
随便看看