一文详尽解析Redis的设计原理( 五 )


5.4 集合对象
集合对象支持INTSET和HT两种编码方式
INTSET编码方式
如果集合对象保存的所有元素都是整数同时元素的数量不超过512个,那么Redis将会使用INTSET编码方式 。

一文详尽解析Redis的设计原理

文章插图
 
HT编码方式
如果集合对象保存的元素并不是整数或元素的数量超过512个,那么Redis将会使用HASHTABLE编码方式 。
一文详尽解析Redis的设计原理

文章插图
 
编码转换
如果集合对象保存的元素并不是整数或元素的数量超过512个,那么Redis将会使用HASHTABLE编码方式 。
可以通过set-max-intset-entries参数调整集合对象INTSET编码方式最多可以保存元素的数量 。
5.5 有序集合对象
有序集合对象支持ZIPLIST和SKIPLIST两种编码方式 。
ZIPLIST编码方式
如果有序集合对象保存的所有元素的字符串长度都小于64个字节同时元素的数量不超过128个,那么Redis将会使用ZIPLIST编码方式 。
一文详尽解析Redis的设计原理

文章插图
 
SKIPLIST编码方式
如果有序集合对象保存的元素的字符串长度大于64个字节或元素的数量超过128个,那么Redis将会使用SKIPLIST编码方式 。
一文详尽解析Redis的设计原理

文章插图
 
编码转换
如果有序集合对象保存的元素的字符串长度大于64个字节或元素的数量超过128个,那么Redis将会使用SKIPLIST编码方式 。
可以通过zset-max-ziplist-value和zset-max-ziplist-entries参数调整有序集合对象ZIPLIST编码方式所允许保存的元素的最大值以及最多可以保存元素的数量 。
6.Redis内存分配器Redis提供了jemalloc、libc、tcmalloc内存分配器,默认使用jemalloc,需要在编译时指定 。
Jemalloc内存分配器
jemalloc内存分配器将内存划分为小、大、巨大三个范围,每个范围又包含多个大小不同的内存单元 。
一文详尽解析Redis的设计原理

文章插图
 
DictEntry、RedisObject以及对象在初始化时,Redis内存分配器都分配一个合适的内存大小 。
如果频繁修改Value,且Value的值相差很大,那么Redis内存分配器需要重新为对象分配内存,然后释放掉对象之前所占用的内存(编码转换或者数组越界)
7.Redis内存监控可以使用info memory命令查看Redis内存的使用情况
一文详尽解析Redis的设计原理

文章插图
 
used_memory:redis有效数据占用的内存大小(包括使用的虚拟内存)
uesd_memory_rss:redis有效数据占用的内存大小(不包括使用的虚拟内存)、redis进程所占用的内存大小、内存碎片(与TOP命令查看的内存一直)
mem_fragmentation_ratio(内存碎片率) = used_memory_rss / used_memory
mem_allocator:redis内存分配器,可选jemalloc(默认)、libc、tcmalloc
  • max_memory配置的是Redis有效数据最大可使用的内存大小,不包括内存碎片,因此Redis实际占用的内存大小最终一定会比max_memory要大 。
内存碎片率
1.当内存碎片率 < 1时,表示redis正在使用虚拟内存 。
2.当内存碎片率严重 > 1,表示redis存在大量的内存碎片 。
  • 内存碎片率在1~1.1之间是比较健康的状态 。
有可能产生内存碎片的操作:频繁更新Value且Value的值相差很大(重新为对象分配内存,释放之前的内存)、Redis的内存淘汰机制 。
产生内存碎片的根本原因:Redis释放的内存无法被操作系统所回收 。
解决内存碎片的方法
1.重启Redis服务,会重新读取RDB文件进行数据的恢复,重新为对象分配内存 。
2.Redis4.0提供了清除内存碎片的功能
#运行期自动清除activedefrag yes#手动执行命令清除memory purge手动执行命令清除8.Redis监视器
一文详尽解析Redis的设计原理

文章插图
 
客户端向服务器发送命令请求时,服务器除了会执行相应的命令以外,还会将关于这条命令请求的信息转发给所有的监视器 。
通过执行monitor命令,客户端可以将自己变成一个监视器,实时接收服务器当前正在执行的命令请求的相关信息 。




推荐阅读