ToB企服应用市场:ToB评测及商务社交产业平台

标题: Spring Boot怎样压缩Json并写入redis? [打印本页]

作者: 曂沅仴駦    时间: 2024-8-28 18:19
标题: Spring Boot怎样压缩Json并写入redis?
1.为什么需要压缩json?

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

详建redis模块的docker目录
  1. version: '3'
  2. services:
  3.   redis:
  4.     image: registry.cn-hangzhou.aliyuncs.com/zhengqing/redis:6.0.8                  
  5.     container_name: redis                                                            
  6.     restart: unless-stopped                                                                  
  7.     command: redis-server /etc/redis/redis.conf --requirepass 123456 --appendonly no
  8. #    command: redis-server --requirepass 123456 --appendonly yes
  9.     environment:                        
  10.       TZ: Asia/Shanghai
  11.       LANG: en_US.UTF-8
  12.     volumes:                           
  13.       - "./redis/data:/data"
  14.       - "./redis/config/redis.conf:/etc/redis/redis.conf"  
  15.     ports:                              
  16.       - "6379:6379"
复制代码
3.代码工程

 实行目标

   实行存入redis的json数据压缩和解压缩  pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <parent>
  6.         <artifactId>springboot-demo</artifactId>
  7.         <groupId>com.et</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.     </parent>
  10.     <modelVersion>4.0.0</modelVersion>
  11.     <artifactId>gzip</artifactId>
  12.     <properties>
  13.         <maven.compiler.source>8</maven.compiler.source>
  14.         <maven.compiler.target>8</maven.compiler.target>
  15.     </properties>
  16.     <dependencies>
  17.         <dependency>
  18.             <groupId>org.springframework.boot</groupId>
  19.             <artifactId>spring-boot-starter-web</artifactId>
  20.         </dependency>
  21.         <dependency>
  22.             <groupId>org.springframework.boot</groupId>
  23.             <artifactId>spring-boot-autoconfigure</artifactId>
  24.         </dependency>
  25.         <dependency>
  26.             <groupId>org.springframework.boot</groupId>
  27.             <artifactId>spring-boot-starter-test</artifactId>
  28.             <scope>test</scope>
  29.         </dependency>
  30.         <dependency>
  31.             <groupId>org.projectlombok</groupId>
  32.             <artifactId>lombok</artifactId>
  33.         </dependency>
  34.         <dependency>
  35.             <groupId>org.springframework.boot</groupId>
  36.             <artifactId>spring-boot-starter-data-redis</artifactId>
  37.         </dependency>
  38.         <dependency>
  39.             <groupId>org.apache.commons</groupId>
  40.             <artifactId>commons-pool2</artifactId>
  41.             <version>2.9.0</version>
  42.         </dependency>
  43.     </dependencies>
  44. </project>
复制代码
controller

  1. package com.et.gzip.controller;
  2. import com.et.gzip.model.User;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. import org.springframework.web.bind.annotation.PostMapping;
  7. import org.springframework.web.bind.annotation.RequestBody;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. @RestController
  13. @Slf4j
  14. public class HelloWorldController {
  15.     @Autowired
  16.     private RedisTemplate redisTemplateWithJackson;
  17.     @PostMapping("/hello")
  18.     public User showHelloWorld(@RequestBody User user){
  19.         log.info("user:"+ user);
  20.         return user;
  21.     }
  22.     @PostMapping("/redis")
  23.     public User redis(@RequestBody User user){
  24.         log.info("user:"+ user);
  25.         redisTemplateWithJackson.opsForValue().set("user",user);
  26.         User redisUser = (User) redisTemplateWithJackson.opsForValue().get("user");
  27.         return redisUser;
  28.     }
  29. }
复制代码
redis压缩和解压缩配置

压缩类
  1. package com.et.gzip.config;
  2. import com.et.gzip.model.User;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.tomcat.util.http.fileupload.IOUtils;
  7. import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
  8. import org.springframework.data.redis.serializer.SerializationException;
  9. import sun.misc.BASE64Encoder;
  10. import java.io.ByteArrayInputStream;
  11. import java.io.ByteArrayOutputStream;
  12. import java.text.SimpleDateFormat;
  13. import java.util.zip.GZIPInputStream;
  14. import java.util.zip.GZIPOutputStream;
  15. @Slf4j
  16. public class CompressRedis extends JdkSerializationRedisSerializer {
  17.     public static final int BUFFER_SIZE = 4096;
  18.     private JacksonRedisSerializer<User>  jacksonRedisSerializer;
  19.     public CompressRedis() {
  20.         this.jacksonRedisSerializer = getValueSerializer();
  21.     }
  22.     @Override
  23.     public byte[] serialize(Object graph) throws SerializationException {
  24.         if (graph == null) {
  25.             return new byte[0];
  26.         }
  27.         ByteArrayOutputStream bos = null;
  28.         GZIPOutputStream gzip = null;
  29.         try {
  30.             // serialize
  31.             byte[] bytes = jacksonRedisSerializer.serialize(graph);
  32.             log.info("bytes size{}",bytes.length);
  33.             bos = new ByteArrayOutputStream();
  34.             gzip = new GZIPOutputStream(bos);
  35.             // compress
  36.             gzip.write(bytes);
  37.             gzip.finish();
  38.             byte[] result = bos.toByteArray();
  39.             log.info("result size{}",result.length);
  40.             //return result;
  41.             return new BASE64Encoder().encode(result).getBytes();
  42.         } catch (Exception e) {
  43.             throw new SerializationException("Gzip Serialization Error", e);
  44.         } finally {
  45.             IOUtils.closeQuietly(bos);
  46.             IOUtils.closeQuietly(gzip);
  47.         }
  48.     }
  49.     @Override
  50.     public Object deserialize(byte[] bytes) throws SerializationException {
  51.         if (bytes == null || bytes.length == 0) {
  52.             return null;
  53.         }
  54.         ByteArrayOutputStream bos = null;
  55.         ByteArrayInputStream bis = null;
  56.         GZIPInputStream gzip = null;
  57.         try {
  58.             bos = new ByteArrayOutputStream();
  59.             byte[] compressed = new sun.misc.BASE64Decoder().decodeBuffer( new String(bytes));;
  60.             bis = new ByteArrayInputStream(compressed);
  61.             gzip = new GZIPInputStream(bis);
  62.             byte[] buff = new byte[BUFFER_SIZE];
  63.             int n;
  64.             // uncompress
  65.             while ((n = gzip.read(buff, 0, BUFFER_SIZE)) > 0) {
  66.                 bos.write(buff, 0, n);
  67.             }
  68.             //deserialize
  69.             Object result = jacksonRedisSerializer.deserialize(bos.toByteArray());
  70.             return result;
  71.         } catch (Exception e) {
  72.             throw new SerializationException("Gzip deserizelie error", e);
  73.         } finally {
  74.             IOUtils.closeQuietly(bos);
  75.             IOUtils.closeQuietly(bis);
  76.             IOUtils.closeQuietly(gzip);
  77.         }
  78.     }
  79.     private static JacksonRedisSerializer<User> getValueSerializer() {
  80.         JacksonRedisSerializer<User> jackson2JsonRedisSerializer = new JacksonRedisSerializer<>(User.class);
  81.         ObjectMapper mapper=new ObjectMapper();
  82.         jackson2JsonRedisSerializer.setObjectMapper(mapper);
  83.         return jackson2JsonRedisSerializer;
  84.     }
  85. }
复制代码
java序列化
  1. package com.et.gzip.config;
  2. import com.fasterxml.jackson.databind.JavaType;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import com.fasterxml.jackson.databind.type.TypeFactory;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.data.redis.serializer.RedisSerializer;
  7. import org.springframework.data.redis.serializer.SerializationException;
  8. import org.springframework.lang.Nullable;
  9. import org.springframework.util.Assert;
  10. import java.nio.charset.Charset;
  11. import java.nio.charset.StandardCharsets;
  12. @Slf4j
  13. public class JacksonRedisSerializer<T> implements RedisSerializer<T> {
  14.     public static final Charset DEFAULT_CHARSET;
  15.     private final JavaType javaType;
  16.     private ObjectMapper objectMapper = new ObjectMapper();
  17.     public JacksonRedisSerializer(Class<T> type) {
  18.         this.javaType = this.getJavaType(type);
  19.     }
  20.     public JacksonRedisSerializer(JavaType javaType) {
  21.         this.javaType = javaType;
  22.     }
  23.     public T deserialize(@Nullable byte[] bytes) throws SerializationException {
  24.         if (bytes == null || bytes.length == 0) {
  25.             return null;
  26.         } else {
  27.             try {
  28.                 return this.objectMapper.readValue(bytes, 0, bytes.length, this.javaType);
  29.             } catch (Exception var3) {
  30.                 throw new SerializationException("Could not read JSON: " + var3.getMessage(), var3);
  31.             }
  32.         }
  33.     }
  34.     public byte[] serialize(@Nullable Object t) throws SerializationException {
  35.         if (t == null) {
  36.             return  new byte[0];
  37.         } else {
  38.             try {
  39.                 return this.objectMapper.writeValueAsBytes(t);
  40.             } catch (Exception var3) {
  41.                 throw new SerializationException("Could not write JSON: " + var3.getMessage(), var3);
  42.             }
  43.         }
  44.     }
  45.     public void setObjectMapper(ObjectMapper objectMapper) {
  46.         Assert.notNull(objectMapper, "'objectMapper' must not be null");
  47.         this.objectMapper = objectMapper;
  48.     }
  49.     protected JavaType getJavaType(Class<?> clazz) {
  50.         return TypeFactory.defaultInstance().constructType(clazz);
  51.     }
  52.     static {
  53.         DEFAULT_CHARSET = StandardCharsets.UTF_8;
  54.     }
  55. }
复制代码
redis序列化
  1. package com.et.gzip.config;
  2. import com.et.gzip.model.User;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7. import org.springframework.data.redis.serializer.RedisSerializer;
  8. import org.springframework.data.redis.serializer.StringRedisSerializer;
  9. @Configuration
  10. public class RedisWithJacksonConfig {
  11.     @Bean(name="redisTemplateWithJackson")
  12.     public RedisTemplate<String, User> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
  13.         CompressRedis  compressRedis =  new CompressRedis();
  14.         //redisTemplate
  15.         RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
  16.         redisTemplate.setConnectionFactory(lettuceConnectionFactory);
  17.         RedisSerializer<?> stringSerializer = new StringRedisSerializer();
  18.         redisTemplate.setKeySerializer(stringSerializer);
  19.         redisTemplate.setValueSerializer(compressRedis);
  20.         redisTemplate.setHashKeySerializer(stringSerializer);
  21.         redisTemplate.setHashValueSerializer(compressRedis);
  22.         redisTemplate.afterPropertiesSet();
  23.         return redisTemplate;
  24.     }
  25. }
复制代码
application.yaml

  1. spring:
  2.   redis:
  3.     host: 127.0.0.1
  4.     port: 6379
  5.     database: 10
  6.     password: 123456
  7.     timeout: 10s
  8.     lettuce:
  9.       pool:
  10.         min-idle: 0
  11.         max-idle: 8
  12.         max-active: 8
  13.         max-wait: -1ms
  14. server:
  15.   port: 8088
  16.   compression:
  17.     enabled: true
  18.     mime-types: application/json,application/xml,text/html,text/plain,text/css,application/x-javascript
复制代码
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库


4.测试



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

查看控制台日记
  1. 2024-08-26 14:37:56.445 INFO 43832 --- [nio-8088-exec-5] com.et.gzip.config.CompressRedis : bytes size371
  2. 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.引用



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4