将数据压缩为GZIP格式存入redis再取出解压
在存入redis的数据过大的情况下,为了优化性能可以把数据进行压缩后再存入,在需要使用的时候再取出进行解压缩。这样做的优点是:1 压缩会减少redis存储数据量,增加redis的吞吐量2 压缩会较少网络带宽但是缺点就是在压缩与解压缩的时候会增加CPU消耗因此要根据项目具体情况决定是否使用首先创建序列化(压缩)和反序列化(解压缩)的工具类import com.fasterxml.jackson.an
·
在存入redis的数据过大的情况下,为了优化性能可以把数据进行压缩后再存入,在需要使用的时候再取出进行解压缩。
这样做的优点是:
1 压缩会减少redis存储数据量,增加redis的吞吐量
2 压缩会较少网络带宽
但是缺点就是在压缩与解压缩的时候会增加CPU消耗
因此要根据项目具体情况决定是否使用
首先创建序列化(压缩)和反序列化(解压缩)的工具类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* @Package: GZIP压缩与解压缩
* @ClassName: CompressRedis
* @Author: CH
* @CreateTime: 2021/7/12
* @Description:
*/
@Slf4j
public class CompressRedis extends JdkSerializationRedisSerializer {
public static final int BUFFER_SIZE = 4096;
// 序列化器
private RedisSerializer<Object> innerSerializer;
public CompressRedis() {
this.innerSerializer = getValueSerializer();
}
@Override
public byte[] serialize(Object graph) throws SerializationException {
if (graph == null) {
return new byte[0];
}
ByteArrayOutputStream bos = null;
GZIPOutputStream gzip = null;
try {
// 先序列化
byte[] bytes = innerSerializer.serialize(graph);
bos = new ByteArrayOutputStream();
gzip = new GZIPOutputStream(bos);
// 再压缩
gzip.write(bytes);
gzip.finish();
byte[] result = bos.toByteArray();
return result;
} catch (Exception e) {
throw new SerializationException("Gzip Serialization Error", e);
} finally {
IOUtils.closeQuietly(bos);
IOUtils.closeQuietly(gzip);
}
}
@Override
public 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();
bis = new ByteArrayInputStream(bytes);
gzip = new GZIPInputStream(bis);
byte[] buff = new byte[BUFFER_SIZE];
int n;
// 先解压
while ((n = gzip.read(buff, 0, BUFFER_SIZE)) > 0) {
bos.write(buff, 0, n);
}
// 再反序列化
Object result = innerSerializer.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 RedisSerializer getValueSerializer() {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
return jackson2JsonRedisSerializer;
}
}
在存取的时候要不能使用RedisTemplate进行存储,因为取出时是object类型,需要进行toString再转为byte数组,这个过程会破坏byte数组的头部信息,使GZIP数据出现格式错误,无法反序列化的情况出现,因此使用jedis进行存储
//压缩数据
byte[] bytes = new CompressRedis().serialize(data);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(bytes);
//写入 Redis
Jedis jedis = new Jedis();
jedis.set((key.getBytes(), baos.toByteArray());
//关闭流
oos.close();
// 读取 Byte格式 存入的数据
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(jedis.get(key.getBytes()));
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
byte[] o = (byte[]) objectInputStream.readObject();
//解压数据
Object object = new CompressRedis().deserialize(p);
这样就能成功取出并解压数据了
更多推荐
已为社区贡献3条内容
所有评论(0)