小对象压缩

鉴于Redis是纯内存数据库,为了尽可能的节省内存开销避免因为内存不足而崩溃,Redis对一部分数据结构进行了优化。

编译

如果使用32位进行编译,内部所有数据结构所使用的指针空间占用会少一半,如果使用内存不超过4G,可以考虑使用32位进行编译,如果不足还可以通过增加实例的方式来解决。

压缩

这里有个ziplist技术,可以说道说道。当集合数据结构很小的话,那么它会使用紧凑存储形式压缩存储。

ziplist是类似于字节数组结构的压缩列表,列表中每个元素仅仅相邻:

该数组[0]占4字节,标记存储整个ziplist占用的总字节数。

该数组[1]占4字节,标记最后一个entry的偏移量,方便直接定位尾部元素。

该数组[2]占2字节,ziplist中entry的数量。

该数组[length-1]占1字节,内容就是255用来标记结束。

数组其他元素都是entry。

其实,ziplist、 intset为了解除集合数据结构很少的时候而采取的方法。

intset跟ziplist类似,是一个紧凑的整数数组结构,它用于存放元素都是整数的并且元素个数较少的 set 集合。如果整数可以用 uint16 表示,那么 intset 的元素就是 16 位的数组,如果新加入的整数超过了 uint16 的表示范围,那么就使用 uint32 表示,如果新加入的元素超过了 uint32 的表示范围,那么就使用 uint64 表示,Redis 支持 set 集合动态从 uint16 升级到 uint32,再升级到 uint64。

当集合对象的元素不断增加或者某个value值过大,这种小对象存储也会被升级为标准结构。Redis规定在小对象存储结构的限制条件如下:

hash-max-zipmap-entries 512 # hash 的元素个数超过 512 就必须用标准结构存储

hash-max-zipmap-value 64 # hash 的任意元素的 key/value 的长度超过 64 就必须用标准结构存储

list-max-ziplist-entries 512 # list 的元素个数超过 512 就必须用标准结构存储

list-max-ziplist-value 64 # list 的任意元素的长度超过 64 就必须用标准结构存储

zset-max-ziplist-entries 128 # zset 的元素个数超过 128 就必须用标准结构存储

zset-max-ziplist-value 64 # zset 的任意元素的长度超过 64 就必须用标准结构存储

set-max-intset-entries 512 # set 的整数元素个数超过 512 就必须用标准结构存储

说白了,就是Redis可以控制小对象压缩与标准结构存储之间转换。

内存回收

Redis并不总是可以将空闲内存立即归还给操作系统。

原因是操作系统回收内存是以页为单位,如果这个页上只要有一个key还在使用,那么它就不能被回收。key分散到了很多页面中,每个页面都还有其它key存在,这就导致了内存不会立即被回收。

如果执行flushdb,然后再观察内存会发现内存确实被回收了。原因是所有的key都干掉了,大部分之前使用的页面都完全干净了,会立即被操作系统回收。Redis虽然无法保证立即回收已经删除的 key的内存,但是它会重用那些尚未回收的空闲内存。

Redis为了保持自身结构的简单性,在内存分配这里直接让第三方内存分配库去实现。目前 Redis 可以使用 jemalloc(facebook) 库来管理内存,也可以切换到tcmalloc(google)。因为 jemalloc 相比 tcmalloc的性能要稍好一些,所以Redis默认使用了jemalloc。

发布了167 篇原创文章 · 获赞 10 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章