Spring Boot如何压缩Json并写入redis?

news/2024/9/18 14:46:18/ 标签: java, spring boot, backend, redis, gzip

1.为什么需要压缩json?

由于业务需要,存入redis中的缓存数据过大,占用了10+G的内存,内存作为重要资源,需要优化一下大对象缓存,采用gzip压缩存储,可以将 redis 的 kv 对大小缩小大约 7-8 倍,加快存储、读取速度

2.环境搭建

详建redis模块的docker目录

version: '3'
services:redis:image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:6.0.8                   container_name: redis                                                             restart: unless-stopped                                                                  command: redis-server /etc/redis/redis.conf --requirepass 123456 --appendonly no
#    command: redis-server --requirepass 123456 --appendonly yes environment:                        TZ: Asia/ShanghaiLANG: en_US.UTF-8volumes:                           - "./redis/data:/data"- "./redis/config/redis.conf:/etc/redis/redis.conf"  ports:                              - "6379:6379"

3.代码工程

 实验目标

实验存入redis的json数据压缩和解压缩

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>gzip</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.9.0</version></dependency></dependencies>
</project>

controller

package com.et.gzip.controller;import com.et.gzip.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
@Slf4j
public class HelloWorldController {@Autowiredprivate RedisTemplate redisTemplateWithJackson;@PostMapping("/hello")public User showHelloWorld(@RequestBody User user){log.info("user:"+ user);return user;}@PostMapping("/redis")public User redis(@RequestBody User user){log.info("user:"+ user);redisTemplateWithJackson.opsForValue().set("user",user);User redisUser = (User) redisTemplateWithJackson.opsForValue().get("user");return redisUser;}
}

redis压缩和解压缩配置

压缩类

package com.et.gzip.config;import com.et.gzip.model.User;import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import sun.misc.BASE64Encoder;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.SimpleDateFormat;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;@Slf4j
public class CompressRedis extends JdkSerializationRedisSerializer {public static final int BUFFER_SIZE = 4096;private JacksonRedisSerializer<User>  jacksonRedisSerializer;public CompressRedis() {this.jacksonRedisSerializer = getValueSerializer();}@Overridepublic byte[] serialize(Object graph) throws SerializationException {if (graph == null) {return new byte[0];}ByteArrayOutputStream bos = null;GZIPOutputStream gzip = null;try {// serializebyte[] bytes = jacksonRedisSerializer.serialize(graph);log.info("bytes size{}",bytes.length);bos = new ByteArrayOutputStream();gzip = new GZIPOutputStream(bos);// compressgzip.write(bytes);gzip.finish();byte[] result = bos.toByteArray();log.info("result size{}",result.length);//return result;return new BASE64Encoder().encode(result).getBytes();} catch (Exception e) {throw new SerializationException("Gzip Serialization Error", e);} finally {IOUtils.closeQuietly(bos);IOUtils.closeQuietly(gzip);}}@Overridepublic Object deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;}ByteArrayOutputStream bos = null;ByteArrayInputStream bis = null;GZIPInputStream gzip = null;try {bos = new ByteArrayOutputStream();byte[] compressed = new sun.misc.BASE64Decoder().decodeBuffer( new String(bytes));;bis = new ByteArrayInputStream(compressed);gzip = new GZIPInputStream(bis);byte[] buff = new byte[BUFFER_SIZE];int n;// uncompresswhile ((n = gzip.read(buff, 0, BUFFER_SIZE)) > 0) {bos.write(buff, 0, n);}//deserializeObject result = jacksonRedisSerializer.deserialize(bos.toByteArray());return result;} catch (Exception e) {throw new SerializationException("Gzip deserizelie error", e);} finally {IOUtils.closeQuietly(bos);IOUtils.closeQuietly(bis);IOUtils.closeQuietly(gzip);}}private static JacksonRedisSerializer<User> getValueSerializer() {JacksonRedisSerializer<User> jackson2JsonRedisSerializer = new JacksonRedisSerializer<>(User.class);ObjectMapper mapper=new ObjectMapper();jackson2JsonRedisSerializer.setObjectMapper(mapper);return jackson2JsonRedisSerializer;}}

java序列化


package com.et.gzip.config;import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;@Slf4j
public class JacksonRedisSerializer<T> implements RedisSerializer<T> {public static final Charset DEFAULT_CHARSET;private final JavaType javaType;private ObjectMapper objectMapper = new ObjectMapper();public JacksonRedisSerializer(Class<T> type) {this.javaType = this.getJavaType(type);}public JacksonRedisSerializer(JavaType javaType) {this.javaType = javaType;}public T deserialize(@Nullable byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;} else {try {return this.objectMapper.readValue(bytes, 0, bytes.length, this.javaType);} catch (Exception var3) {throw new SerializationException("Could not read JSON: " + var3.getMessage(), var3);}}}public byte[] serialize(@Nullable Object t) throws SerializationException {if (t == null) {return  new byte[0];} else {try {return this.objectMapper.writeValueAsBytes(t);} catch (Exception var3) {throw new SerializationException("Could not write JSON: " + var3.getMessage(), var3);}}}public void setObjectMapper(ObjectMapper objectMapper) {Assert.notNull(objectMapper, "'objectMapper' must not be null");this.objectMapper = objectMapper;}protected JavaType getJavaType(Class<?> clazz) {return TypeFactory.defaultInstance().constructType(clazz);}static {DEFAULT_CHARSET = StandardCharsets.UTF_8;}
}

redis序列化

package com.et.gzip.config;import com.et.gzip.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisWithJacksonConfig {@Bean(name="redisTemplateWithJackson")public RedisTemplate<String, User> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {CompressRedis  compressRedis =  new CompressRedis();//redisTemplateRedisTemplate<String, User> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);RedisSerializer<?> stringSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringSerializer);redisTemplate.setValueSerializer(compressRedis);redisTemplate.setHashKeySerializer(stringSerializer);redisTemplate.setHashValueSerializer(compressRedis);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

application.yaml

spring:redis:host: 127.0.0.1port: 6379database: 10password: 123456timeout: 10slettuce:pool:min-idle: 0max-idle: 8max-active: 8max-wait: -1ms
server:port: 8088compression:enabled: truemime-types: application/json,application/xml,text/html,text/plain,text/css,application/x-javascript

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • https://github.com/Harries/springboot-demo(gzip)

4.测试

  1. 启动spring boot应用
  2. 用postman访问http://127.0.0.1:8088/redis

3

可以看到redis里面存储的是gzip压缩的内容

4

查看控制台日志

2024-08-26 14:37:56.445 INFO 43832 --- [nio-8088-exec-5] com.et.gzip.config.CompressRedis : bytes size371
2024-08-26 14:37:56.445 INFO 43832 --- [nio-8088-exec-5] com.et.gzip.config.CompressRedis : result size58

JSON经过gzip压缩,371-->58, 数据大小减少7-8倍

5.引用

  •  Spring Boot如何压缩Json并写入redis? | Harries Blog™

http://www.ppmy.cn/news/1517095.html

相关文章

如何考取PostgreSQL认证证书?

PostgreSQL数据库炙手可热&#xff0c;国内知名的腾讯云TDSQL、阿里云PolarDB都有PostgreSQL版本的产品&#xff0c;还有人大金仓、华为opengauss、翰高数据库等都跟PostgreSQL有关系&#xff0c;所以考一个PostgreSQL认证非常有必要。要获得PostgreSQL认证&#xff0c;可以从以…

PTA - C语言国庆题集1

目录 7-1 阶梯电价7-2 求矩阵的最大值&#xff08;设惟一&#xff09;7-3 换硬币&#xff08;鸡兔同笼&#xff09;7-4 逆序输出一个整数的各位数字7-5 交换最小值7-6 分段函数27-7 数组中能被5整除的数的和7-8 统计字母出现的次数&#xff08;hash思想&#xff09;7-9 字母三角…

openEluer安装软件提示系统缺少的一些库的解决

mysql客户端相关的坑 问题&#xff1a;mysql: error while loading shared libraries: libncurses.so.5 解决&#xff1a; ln -s /usr/lib64/libncurses.so.6 /usr/lib64/libncurses.so.5 问题&#xff1a;mysql: error while loading shared libraries: libtinfo.so.5 解决…

npm阿里云制品仓库

配置 配置仓库地址&#xff0c;可以再在仓库指南看到 npm config set registryxxxxx#登录&#xff0c;帐户密码可以在仓库指南看到 npm login注意&#xff1a;npm>9的版本npm login目前有问题 verbose web login not supported, trying couch&#xff0c;暂时没试验到解决…

数据结构-递归算法-第四天

参考文献&#xff1a; 华为云 博客园 labuladong 的算法笔记 递归是一种编程技巧&#xff0c;一种解决问题的思维方式&#xff1b;分治算法和动态规划很大程度上是递归思想基础上的&#xff08;虽然动态规划的最终版本大都不是递归了&#xff0c;但解题思想还是离不开递归&…

Linux环境使用docker搭建Navidrome本地个人音乐库并实现远程访问

文章目录 前言1. 安装Docker2. Docker镜像源添加方法3. 创建并启动Navidrome容器 前言 本文和大家分享一款目前在G站有11KStar的开源跨平台音乐服务器Navidrome&#xff0c;如何在Linux环境本地使用Docker部署&#xff0c;并结合cpolar内网穿透工具配置公网地址&#xff0c;实…

入门STM32--按键输入

上一篇博客我们介绍了如何使用GPIO配置跑马灯&#xff0c;根据GPIO的基本结构图&#xff0c;我们能够发现&#xff0c;他肯定不单单有输出的功能&#xff0c;肯定可以检测IO上的电平变化&#xff0c;实际上就是输入的功能。 1.按键 在大多数情况下&#xff0c;按键是一种简单的…

今日算法:蓝桥杯基础题之“切面条”

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注&#xff01;个人知乎 从今天开始&#xff0c;一起了解算法&#xff0c;每日一题&#xff0c;从 JavScript 的技术角度进行解答&#xff0c;如果你对算法也感兴趣&#xff0c;请多多关注哦。 问题描述 一…

15 - FFmpeg 音频混音(过滤器)

过滤器链接流程 -------- auto_aresample_0:default--[48000Hz flt:stereo]--input0| amix |default--[48000Hz flt:stereo]--auto_aresample_2:default auto_aresample_1:default--[48000Hz flt:stereo]--input1| (amix) | …

Linux 数据结构 顺序表 链表

数据结构&#xff1a; 1.衡量一个程序是否优秀&#xff1a; 1.时间复杂度&#xff1a; 数据量增长与程序运行时间的比例关系以函数描述称为时间渐进复杂度函数,简称时间复杂度 O(c) > O(logn) > O(n) > O(nlogn) > O(n^2) > O(n^3) > O…

一个prolog最简单推理示例

假设现在知道一些年轻人&#xff0c;谁喜欢谁&#xff0c;定义为love(x, y)&#xff1b; 定义了一些这样的关系&#xff1b; 如果x喜欢y&#xff0c;y也喜欢x&#xff0c;则定义他们是一对情侣&#xff1b; 规则表示为&#xff1a; lovers(X,Y) :- love(X,Y), love(Y,X). 输入…

UniApp中的Flex布局技巧

随着移动互联网的迅速发展&#xff0c;越来越多的开发者开始使用跨平台技术来开发应用程序。而在跨平台开发里&#xff0c;uniapp是一种非常受欢迎的框架&#xff0c;由于使用uniapp可以快速地开发出同时支持多个平台的应用程序。在uniapp开发中&#xff0c;flex布局是一种非常…

【C++】异常 详解

目录 异常的引出与简介 异常的使用 异常逻辑图解 异常继承体系 异常的重新抛出 异常安全 异常规范 结语 异常的引出与简介 我们可以回忆一下&#xff0c;在C语言时期&#xff0c;我们返回错误的方式只有两个 一个是assert强制返回错误&#xff0c;还有一个就是返回错误…

第三十一章:docker如何部署Nexus

docker如何部署Nexus 目标 掌握 Nexus docker compose安装安装Docker和Docker Compose:确保您的系统已安装Docker和Docker Compose。如果尚未安装,可以参考Docker官方文档进行安装12。 创建Docker Compose文件:在您选择的目录下创建一个名为docker-compose.yml的新文件,并…

GraphRAG论文解读

欢迎一起讨论 论文地址综述介绍部分核心翻译翻译解释重要的信息元素和实体的关系&#xff08;包含和被包含&#xff0c;而非相等&#xff09;Graph Index&#xff08;图索引&#xff09;Community Detection&#xff08;社区检测&#xff09;Query-Focused Summarization&#…

Android studio 升级问题记录-个性化配置迁移

前言 在本次折腾Android studio更新的过程中&#xff0c;遇到了很多问题&#xff0c;包括&#xff1a; 选择直接覆盖更新的话&#xff0c;会发现样式还是老样式旧项目运行不通过&#xff0c;并且会生成一些异常的build无法再支持代码自动补全功能本地没commit的代码丢失&…

【经验】linux下cuda的更换

linux下cuda的更换 查看当前cuda和cudnn的版本 nvcc -Vcudnn版本 cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2下载对应版本的cuda 查看驱动版本535.54.03 下载对应的cuda版本 版本查看https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.htm…

pytest参数化多种用法总结

pytest.mark.parametrize 是 pytest 的一个核心功能&#xff0c;它允许你参数化测试函数&#xff0c;这样你就可以使用不同的参数运行同一个测试函数多次。以下是 pytest.mark.parametrize 的详细用法总结&#xff1a; 基本用法 parametrize 装饰器可以接受一个或多个参数名&…

驱动:mknod-misc 杂项自动

一、杂项设备驱动 #include <linux/init.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/module.h> #include <linux/device.h> #include <asm/io.h> #include <asm/string.h> #include <asm/uaccess.h>…

TinaSDKV2.0 自定义系统开发

TinaSDKV2.0 自定义系统开发 什么是自定义系统&#xff1f; TinaSDK Kconfig界面配置 Tina Linux采用 Kconfig 机制对 SDK 和内核进行配置。 Kconfig 是一种固定格式的配置文件。Linux 编译环境中的 menuconfig 程序可以识别这种格式的配置文件&#xff0c;并提取出有效信息…