下面这些redis内存方面的问题是在工作中发现的。可以作为一个工作中的参考
一、redis数据类型的特殊编码形式
在redis2.2以后许多数据类型为了节约内存使用大小,都开启了一个压缩的算法,当数据库中的
元素个数少于配置文件中设置的文件个数时,这些元素最理想的情况下会被压缩到10分之一的大小进行存储,
(一般情况下可以压缩到5分之一),从而节约内存占用。
这些配置对于使用的人来说非常清晰,这些配置其实也是内存 和CPU之间的一个权衡,压缩会占用CPU,不压缩内存使用
就较高。在不同的机器或者应用场景下,开发人员应该进行一个抉择,以下是一些基本的默认配置项:
hash-max-zipmap-entries 512 (hash-max-ziplist-entries for Redis >= 2.6)
hash-max-zipmap-value 64 (hash-max-ziplist-value for Redis >= 2.6)
list-max-ziplist-entries 512
list-max-ziplist-value 64
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
set-max-intset-entries 512
上面的第一个配置和第二个配置的意思,就是说 hashmap 已经压缩的实体数量在少于512个,并且元素的大小低于64的时候就会自动被压缩内存。
注意事项:
1、如果一个经过压缩的元素大于设置的最大元素大小,redis会取消压缩,当存储的数据不是特别大的时候,压缩操作还是比较快的。
2、但是如果你改变了默认的配置,去压缩一下比较大的元素数据,还是非常建议你做一下压力测试,并且检查一下压缩所占用的时间和CPU.
二、32位的操作系统
1、redis在32的机器的上因为指针变量只有四个字节,因此占用的内存相对会更小,但是由于32位的操作系统其最大内存只能支持到4G。
2、RDB和AOF不管是在32位和64位的机器上(包括大端和小端),都是兼容的。
三、bit和byte 不同存储级别操作
如果你要存储ID从 1-1亿 个用户的性别,你可以使用二进制的0和1来表示性别,这样你大概只需要使用12M的内存就可以
存储1个亿的用户的性别数据,而在查询或者设置数据的时候你可以使用GETBIT和SETBIT命令。当然你也可以使用GETRANGE和SETRANGE在byte层面来做一个优化。
四、使用hashmap代替多个key
举个例子,比如在web应用中你有一个user对象包含了
name, surname, email, password等属性
,这个时候你最好使用hashmap,
五、关于hashmap
如果你使用的是string类型,那么它的存取效率是高于memcache的,但是它会比memcache更消耗内存。
一个hasmap存储一个对象,比单个存储对象的属性要更加节约内存,比如
你有一个user对象包含了
name, surname, email, password。当我们使用hashmap的使用,当hashmap中的键值对较少的时候redis会以数组的形式来进行存储,当hashmap中的键值对过多的时候redis才会把它变成真正的hash。
从时间复杂度来说这并不是很好,但是从恒定时间的观点上来看,key- value对的线性数组很好地利用了CPU 的缓存(
它的缓存位置比hash好)。
在hashmap中不能使用expire了,当然多维的也是不允许的,这是redis的设计原则。
hash包含100个字段在cpu和内存之间保存是最理想的。
另外如果你能够使用一个尽量小的数字来作为key或者value,也会非常节约内存。比如一个hashTable,
users > array ('userid:1'=>'json','userid:2'=>'json'),其实你可以直接简化filed为 1,2这种类型
六、redis中的内存分配
1、 redis在启动时会分配用户在配置文件中指定的
maxmemory
内存(可能会有额外的消耗)。
2、当redis在删除一个键的时候,redis不会立即释放内存,熟悉malloc的应该知道分配运算不太容易能释放内存,
通常一个内存页上有的键还存在,有的键则已经删除,那这个页面该如何释放呢。
比如,你的redis有5G的数据,即使你删除了2G的数据,常驻内存的大小(
也被称为RSS,它是内存页的数量消耗
)也仍然接近5G,尽管Redis可能显示的内存使用是3G左右。
3、
前面一点的意思是你需要分配的内存基于你需要用内存的最大值。如果你有时需要10G,那么尽管多数时间只需要5G,你也应该提供10G的内存。
4、
然而分配运算符malloc会很聪明地区重新使用空闲的内存块,因此你的5G 的数据释放2G之后,当你重新添加更多的key时,即使你增加的key数据达到2G,你将看见RSS(常驻内存大小)保持稳定没有增长。分配符主要是去尝试使用之前释放的内存(逻辑上释放的内存)。
5、redis在内存碎片上的整理做得还不够出色,详细可见jmalloc的实现原理,
所以,当你发现你的内存使用比平常大了许多的时候,你就应该注意了
。
碎片率的计算是目前使用的内存(redis执行分配的内存)除以实际分配的物理内存(RSS的值)。由于RSS是最大内存,当很多key/value被释放,就会导致内存的使用率非常低,但是RSS很高,
因此mem_used / RSS就非常高.
6、
如果没有设置
maxmemory
Redis就会一直分配能找到的内存并且逐步地吃光所有的空闲内存。因此一般都要明确地配置限制。你也可以设置maxmemory-policy为noeviction
(在redis以前的一些版本不是默认值).
这可以使当redis的内存使用达到限制值时,返回内存溢出错误。