理解内存
为什么要理解内存呢?redis所有的数据都存在内存中如何高效利用内存,实现用更少的内存存更多的数据,从而降低成本
如何统计内存使用?info memory可以获取内存相关指标,如下:used_memory:redis分配器分配的内存总量used_memory_human:以可读格式返回used_memoryused_memory_rss:从操作系统的角度显示redis占用的物理内存总量used_memory_peak:内存使用的最大值,表示used_memory的峰值used_memory_peak_human:以可读格式返回used_memory_peakused_memory_lua:Lua引擎所消耗的内存大小mem_fragmentation_ratio:used_memory_rss/used_memory比值,表示内存碎片率mem_allocator:redis所使用的内存分配器,默认为jemalloc(注:mem_fragmentation_ratio>1出现内存碎片,mem_fragmentation_ratio<1出现操作系统把redis内存Swap到硬盘现象)
内存消耗自身内存对象内存(sizeof(keys)+sizeof(values))缓冲内存客户端缓冲(所有接入到redis服务器TCP连接的输入输出缓冲,输入缓冲无法控制,最大空间1G,超过将断开连接。输出缓冲通过参数client-output-buffer-limit控制)普通客户端(除了复制和订阅的客户端之外的所有连接)从客户端(主节点会为每个从节点单独建立一条连接用于命令复制)订阅客户端(当使用发布订阅功能时,连接客户端使用单独的输出缓冲区)复制积压缓冲区(一个可重用的固定大小缓冲区用于实现部分复制功能,repl-backlog-size)AOF缓冲区(用于redis重写期间保存最近的写入命令)内存碎片内存分配策略(小,大,巨大)容易出现内存碎片的场景(频繁做更新操作、大量过期键删除)如何解决(数据对齐、安全重启)子进程消耗(执行AOF/RDB重写时redis创建的子进程内存消耗)
内存管理设置内存上限(maxmemory)动态调整内存上限(config set maxmemory 6GB)内存回收策略删除到达过期时间的键对象惰性删除(当客户端读取带有超时属性的键时,如果已经超过键设置的过期时间,会执行删除操作并返回空,节省CPU,存在内存泄漏问题)定时任务删除(自适应算法,键的过期比例、使用快慢两种模式)内存使用达到maxmemory上限时触发内存溢出控制策略(maxmemory-policy控制)noeviction:不会删除任何数据,拒绝所有写入操作并返回客户端错误信息volatile-lru:根据LRU算法删除设置了超时属性的键,直到腾出足够空间为止,如果没有删除的键,回退到noevictionallkeys-lru:根据LRU算法删除所有键,直到腾出足够空间为止allkeys-random:随机删除所有键,直到腾出足够空间为止volatile-random:随机删除过期键,直到腾出足够空间为止volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据,如果没有,回退到noeviction
内存优化首先了解一下RedisObject对象type字段:表示当前对象使用的数据类型encoding字段:表示redis内部编码类型lru字段:记录对象最后一次被访问的时间(object idletime {key}查看键的空闲时间)refcount字段:记录当前对象被引用的次数(object refcount {key}获取当前对象的引用)*ptr字段:与对象的数据内容有关,如果是整数,直接存储数据,否则表示指向数据的指针有哪些具体优化手段?缩减键值对象(key尽可能短,value采用序列化或者压缩算法)共享对象池(redis内部维护[0-9999]的整数对象池)注意:当设置maxmemory并启用LRU相关淘汰策略时,redis禁止使用共享对象池;对于ziplist编码的值对象,即使内部数据为整数也无法使用共享对象池字符串优化SDS(字符串长度、已用长度、未用长度)预分配机制(减少字符串频繁修改操作)字符串重构编码优化什么是编码?具体使用哪种底层数据结构来实现string--rawembstrinthash----hashtableziplist(value<=hash-max-ziplist-value and count(field)<=hash-max-ziplist-entries)list----linkedlistziplist(value<=list-max-ziplist-value and 链表长度<=list-max-ziplist-entries)quicklistset-----hashtableintset(元素为整数 and 集合长度<=set-max-intset-entries)zset----skiplistziplist(value<=zset-max-ziplist-value and 有序集合长度<=zset-max-ziplist-entries)(hashtable、ziplist、linkedlist、quicklist、intset、skiplist)注意:小编码可以转大编码,大不能转小ziplist(所有数据采用线性连续的内存结构,节约内存)zlbytes:记录整个压缩列表所占字节长度,方便重新调整ziplist空间。类型是int-32,长度为4字节zltail:记录距离尾节点的偏移量,方便尾节点弹出操作。类型int-32,4字节zllen:记录压缩链表节点数量,类型是int-16,2字节entry:记录具体的节点prev_entry_bytes_length:记录前一个节点所占空间,用于快速定位上一个节点,可实现列表反向迭代encoding:当前节点编码和长度,前两位表示类型,其余表示长度contents:节点的值zlend:记录列表结尾,1字节intset(存储有序、不重复的整数集)encoding:表示类型length:集合元素个数contents:整数数组,从小到大顺序保存控制键的数量针对自己现在使用的模式,分析其内存消耗和可优化的地方。复制代码