当前位置:   article > 正文

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

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.测试

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

3

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

4

查看控制台日志

  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.引用

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/1021488
推荐阅读
相关标签
  

闽ICP备14008679号