开源节流——小对象压缩
Redis是非常耗内存的数据库,所有数据放在内存里。为了优化数据结构的内存占用,增加了非常多的优化点,以牺牲代码的可读性为代价
32bit VS 64bit
Redis如果使用32bit进行编译,内部所有的数据结构使用的指针空间将会少一半,可以考虑使用32bit进行编译,能够节约大量内存
小对象
小对象压缩存储
如果Redis内部管理的集合数据结构很小,它会使用紧凑存储形式压缩存储
ziplist
Redis的ziplist是一个紧凑的字节数组结构,每个元素之间都是紧挨着的。
如果存储的是hash结构,那么key和value会作为两个entry被相邻存储
如果存储的是zset结构,那么value和score会作为两个entry被相邻存储
intset
Redis的intset是一个紧凑的整数数组结构,用于存放元素都是整数且元素个数较小的set集合
如果整数可以用uint16表示,那么intset的元素就是16位的数组,如果新加入的整数超过了uint16的表示范围,那么就使用uint32表示,如果新加入的元素超过了uint32的表示范围,那么就使用uint64表示。Redis支持set集合动态从uint16升级到uint32,再升级到uint64
如果set里存储的是字符串,那么sadd立即升级为hashtable结构
小对象升级为标准结构
- hash的元素个数超过512就必须使用标准结构存储
- hash的任意元素的key/value的长度超过64就必须用标准结构存储
- list 的元素个数超过512就必须用标准结构存储
- list的任意元素的长度超过64就必须用标准结构存储
- zset的元素个数超过128就必须用标准结构存储
- zset的任意元素的长度超过64就必须用标准结构存储
- set的整数元素个数超过512就必须用标准结构存储
内存回收机制
Redis并不总是将空闲内存立即归还给操作系统
当前Redis内存有10GB,当删除1GB的key时,内存变化不会太大。因为操作系统是以页为单位来回收内存的,这个页上只要还有一个key在使用,那么就不能被回收。虽然删除了1GB的key,但是这些key分散到很多的页面上,每个页面仍然还有其他key存在,这就导致内存不会被立即回收。
Redis会重新使用那些尚未回收的空闲内存
内存分配算法
Redis为了保持自身结构的简单,直接由jemalloc(facebook)库来管理内存,比tcmalloc(google)性能更好