如何将Redis内存使用量降低一半? - DEV


在本文中,我将尝试解释如何将数据占用的存储空间减少50%以上。
我们的2.5GB Redis ElastiCache几乎快满了,如果以某种方式达到其极限,我们的系统将开始出现故障。Redis可能会成为瓶颈。

基础设定:
使用最新版本的Spring Boot,有两个主要依赖项- Spring Boot Web和Spring Data Reactive Redis,Spring Data Reactive Redis将用于连接和使用Redis的内部应用程序。从本质上讲,Redis依赖项默认使用Lettuce Redis客户端,并且受最新版本的Spring Boot支持。

完整的代码可以在我的Github上找到redis-util

降低内存使用量使用MessagePack,您需要一种“转换”机制。如果翻译是专家,并且将您的英语翻译成尽可能少的单词怎么办?MessagePack工作原理是一样的!将需要在pom.xml文件中添加两个以上的依赖项。

<dependency>
        <groupId>org.msgpack</groupId>
        <artifactId>msgpack-core</artifactId>
        <version>0.8.20</version>
    </dependency>
    <dependency>
        <groupId>org.msgpack</groupId>
        <artifactId>jackson-dataformat-msgpack</artifactId>
        <version>0.8.20</version>
    </dependency>

我们创建了一个名为控制器MsgPackController:

class MsgPackRedisSerializer<T> implements RedisSerializer<T> {
    public static final Charset DEFAULT_CHARSET;
    private final JavaType javaType;
    private ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory())
            .registerModules(new Jdk8Module(), new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .setSerializationInclusion(JsonInclude.Include.NON_NULL);

    public MsgPackRedisSerializer(Class<T> type) {
        this.javaType = JavaTypeHandler.getJavaType(type);
    }

    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 ex) {
                throw new SerializationException("Could not read MsgPack JSON: " + ex.getMessage(), ex);
            }
        }
    }

    public byte[] serialize(@Nullable Object value) throws SerializationException {
        if (value == null) {
            return new byte[0];
        } else {
            try {
                return this.objectMapper.writeValueAsBytes(value);
            } catch (Exception ex) {
                throw new SerializationException(
"Could not write MsgPack JSON: " + ex.getMessage(), ex);
            }
        }
    }

    static {
        DEFAULT_CHARSET = StandardCharsets.UTF_8;
    }

}

实例MessagePackFactory被传递到中ObjectMapper。这将充当Redis和我们的Spring Boot应用程序之间数据的二进制格式和字符串格式之间的桥梁。
测试: 比较dataset.bytes当前内存与先前记录的内存。15976字节对32840字节,已经减少了近50%!

但是,等等,我们可以进一步减少它。压缩!Snappy
之后的第一个问题是:压缩和解压缩需要时间。这对生产有害吗?Snappy也有答案。

它不旨在最大程度地压缩,也不旨在与任何其他压缩库兼容。相反,它的目标是非常高的速度和合理的压缩。

使用Snappy就像在中添加依赖项一样简单pom.xml,并且几行代码更改。只需Snappy.compress在序列化和Snappy.decompress反序列化时添加即可。

<dependency>
        <groupId>org.xerial.snappy</groupId>
        <artifactId>snappy-java</artifactId>
        <version>1.1.7.3</version>
    </dependency>

清理和重组数据,并利用上述技术,我们将内存使用量从2GB降低到了不到500MB。