redis存储大量hash内存占用优化

工作中无意发现线上redis内存占用过高,每天差不多30W的hset操作吧,占用了将近200Mredis内存,于是编写测试代码,简单测试了一下,发现还是有地方可以优化的

1、SPRING-DATA-REDIS: SERIALIZER实例

spring-data-redis提供了多种serializer策略,这对使用jedis的开发者而言,实在是非常便捷。sdr提供了4种内置的serializer:

  • JdkSerializationRedisSerializer:使用JDK的序列化手段(serializable接口,ObjectInputStrean,ObjectOutputStream),数据以字节流存储
  • StringRedisSerializer:字符串编码,数据以string存储
  • JacksonJsonRedisSerializer:json格式存储
  • OxmSerializer:xml格式存储

其中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的序列化策略,其中“JacksonJsonRedisSerializer”与“OxmSerializer”都是基于stirng存储,因此它们是较为“高级”的序列化(最终还是使用string解析以及构建java对象)。

RedisTemplate中需要声明4种serializer,默认为“JdkSerializationRedisSerializer”:

1) keySerializer :对于普通K-V操作时,key采取的序列化策略
2) valueSerializer:value采取的序列化策略
3) hashKeySerializer: 在hash数据结构中,hash-key的序列化策略
4) hashValueSerializer:hash-value的序列化策略

通过对int、string、object进行序列化测试,发现默认的JdkSerializationRedisSerializer序列化后的字节流占用空间是最大的, GenericJackson2JsonRedisSerializer次之,StringRedisSerializer最小,但StringRedisSerializer只可以对string进行序列化

JdkSerializationRedisSerializer
int     >>>>>>>>>>  81
string     >>>>>>>>>>  10
object  >>>>>>>>>>  113

GenericJackson2JsonRedisSerializer
int     >>>>>>>>>>  3
string     >>>>>>>>>>  5
object  >>>>>>>>>>  27

StringRedisSerializer
string     >>>>>>>>>>  3

参考:https://www.cnblogs.com/yueguanguanyun/p/8283127.html

2、HASH存储什么数据节省内存

通过测试发现数字要比存储字符串要节省内存占用,随意能用数字的尽量使用数字

2.1、Jedis的hset重载方法

java操作redis的底层实现,保存hash到redis是有两个方法的:

2.1.1、JedisCommands接口下的

  • Long hset(String key, String field, String value);

2.1.2、BinaryJedisCommands接口下的

  • Long hset(byte[] key, byte[] field, byte[] value);

2.2、测试

分别对应字符串和字符流,spring data redis封装的RedisTemplate,只提供了字符流的实现,但是通过调用底层Jedis的实现发现,在插入30W条相同数据,测试结果如下:

HASH subKey 存储一个code = 123 的枚举类型,调用实现BinaryJedisCommands接口
>>>>>>>>>>>>>>>>begin
# Memory
used_memory:713224
used_memory_human:696.51K
used_memory_rss:655416
used_memory_peak:72374824
used_memory_peak_human:69.02M
used_memory_lua:36864
mem_fragmentation_ratio:0.92
mem_allocator:jemalloc-3.6.0

>>>>>>>>>>>>>>>>after
# Memory
used_memory:162700776
used_memory_human:155.16M
used_memory_rss:162599336
used_memory_peak:162700776
used_memory_peak_human:155.16M
used_memory_lua:36864
mem_fragmentation_ratio:1.00
mem_allocator:jemalloc-3.6.0

执行时间: time = 25609 ms




HASH subKey 存储字符串"123",调用实现BinaryJedisCommands接口的方法
>>>>>>>>>>>>>>>>begin
# Memory
used_memory:713224
used_memory_human:696.51K
used_memory_rss:655416
used_memory_peak:72374824
used_memory_peak_human:69.02M
used_memory_lua:36864
mem_fragmentation_ratio:0.92
mem_allocator:jemalloc-3.6.0

>>>>>>>>>>>>>>>>after
# Memory
used_memory:71500776
used_memory_human:68.19M
used_memory_rss:71265080
used_memory_peak:72374824
used_memory_peak_human:69.02M
used_memory_lua:36864
mem_fragmentation_ratio:1.00
mem_allocator:jemalloc-3.6.0

执行时间: time = 23076 ms





HASH subKey 存储字符串"123",调用实现JedisCommands接口的方法
>>>>>>>>>>>>>>>>begin
# Memory
used_memory:713224
used_memory_human:696.51K
used_memory_rss:655416
used_memory_peak:72374824
used_memory_peak_human:69.02M
used_memory_lua:36864
mem_fragmentation_ratio:0.92
mem_allocator:jemalloc-3.6.0

>>>>>>>>>>>>>>>>after
# Memory
used_memory:52300776
used_memory_human:49.88M
used_memory_rss:52273928
used_memory_peak:72374824
used_memory_peak_human:69.02M
used_memory_lua:36864
mem_fragmentation_ratio:1.00
mem_allocator:jemalloc-3.6.0

执行时间: time = 24877 ms

占用内存从155.16M减小到49.88M,节省的内存还是挺多的。

结论

在保存数据的时候尽量调用实现JedisCommands接口的hset方法,不进行序列化操作。

你可能感兴趣的:(redis)