第8章 理解内存

高效利用Redis内存需要理解内存消耗在哪里,然后在管理内存,优化内存。

内存消耗分析、管理内存的原理和方法、内存优化技巧

8.1 内存消耗

    想理解Redis内存,首先要知道Redis内存消耗在哪些方面。可以通过参数调整和合理使用来规避内存浪费。内存消耗可以分为进程自身消耗和子进程消耗

    8.1.1 内存使用统计

        1 通过执行info memory获取内存相关指标

      

        需要重点关注的指标有:used_memory_rss和used_memory以及它们的比值mem_fragmentation_radio

        当mem_fragmentation_radio>1时,说明used_memory_rss-used_memory多出的部分内存没有用于数据存储,而是被内存碎片所消耗,如果两者相差很大,说明碎片率严重

        当mem_fragmentation_radio<1时,操作系统把Redis内存交换(Swap)到硬盘导致。

    8.1.2 内存消耗划分

        

        自身内存+对象内存+缓冲内存+内存碎片

        1 对象内存

            占用内存最大的一块,存储用户所有数据。内存消耗=sizeof(keys)+sizeof(values)

             注意:避免使用过长的键和合理预估并监控value对象占用情况,避免内存溢出

        2 缓冲内存

            客户端缓冲、复制积压缓冲区、AOF缓冲区

            客户端缓冲:所有接入到Redis服务器TCP连接的输入输出缓冲。

            普通客户端:除了复制和订阅的客户端之外的所有连接?不明白

            从客户端:主结点为每个结点单独建立一条连接用于命令复制

            订阅客户端:当使用发布订阅功能时,连接客户端使用单独的输出缓冲区

            输入输出缓冲区在大流量的场景中容易失控,造成Redis内存的不稳定,需要重点监控

         复制积压缓冲区

           可重用的固定大小缓冲区用于实现部分复制功能

         AOF缓冲区

            这部分空间用于在Redis重写期间保存最近写入命令

        3 内存碎片

            内存分配器采用jemalloc,有可选的。内存分配器为了更好的管理和重复利用内存,分配内存策略一般采用固定范围的内存块进行分配

             出现高内存碎片问题解决方式:

                数据对齐和安全重启

    8.1.3 子进程内存消耗

        Redis产生的子进程并不需要消耗1倍的父进程内存,实际消耗根据期间写入命令量决定,但是依然要预出一些内存防止溢出

        需要设置sysctl vm.overcommit_memory=1允许内核可以分配所有的物理内存,防止Redis进程执行fork时因系统剩余内存不足而失败

        排查当前系统是否支持并开启THP,如果开启建议关闭,防止Copy-on-write期间内存过度消耗

8.2 内存管理

    通过控制内存上限和回收策略实现内存管理

    8.2.1 设置内存上限

        限制内存使用的目的:

        用于缓存场景,当超出内存上限maxmemory时使用LRU等删除策略释放空间

        防止所用内存超过服务器物理内存

    8.2.2 动态调整内存上限

        config set maxmemory进行动态修改,即修改最大可用内存。

        Redis默认无限使用服务器内存,为防止极端情况,建议所有的Redis进程都要设置maxmemory,在保证物理内存可用的情况下,系统中所有Redis实例可以调整maxmemory参数来达到自由伸缩内存的目的

    8.2.3 内存回收策略

        1 删除过期键对象

            惰性删除和定时任务删除

            2 内存溢出控制策略

       建议线上内存工作在maxmemory>used_memory状态下,避免频繁内存回收开销           

8.3 内存优化

    8.3.1 redisObject对象

        

    高并发写入场景中,在条件允许的情况下,建议字符串长度控制在39字节以内,减少创建redisObject内存分配次数,从而提高性能

    8.3.2 缩减键值对象

        减少key长度和减少value长度

    8.3.3 共享对象池

        

    8.3.4 字符串优化

        所有的键都是字符串类型。

        1 字符串结构

            内部简单实现动态字符串

            

        2 预分配机制

        3 字符串重构

            不一定把每份数据作为字符串整体存储,

    8.3.5 编码优化

        1 了解编码

            所谓编码,就是具体使用哪种底层数据结构来实现 object encoding 获取编码类型

            多种编码类型:是想通过不同编码实现效率和空间的平衡

        2 控制编码类型

            输入写入的时候自动完成,不可逆

        3 ziplist编码

        4 inset编码

            集合set类型编码的一种,内部表现为存储有序、不重复的整数集。            

    

        1 encoding:整数表示类型,根据集合内最长整数值确定类型,整数类型划分为三种:int-16、int-32、int-64

        2 length 表示集合元素个数

        3 contents 整数数组,按从小到大顺序保存

        intset保存的整数类型根据长度划分,保存的整数类型超出当前类型时,将自动触发升级不回退,升级操作将会导致重新申请内存空间,把原有数据拷贝到新数组。

    8.3.6 控制键的数量

        对于存储相同数据内容利用Redis的数据结构降低外层键的数量,可以节省大量内存。  

          

    hash结构降低键数量分析

        根据键规模在客户端通过分组映射到一组hash对象中

        hash的field可用于记录原始key字符串,方便哈希查找

        hash的value保存原始值对象,确保不要超过hash-max-ziplist-value限制

8.4 本章重点回顾


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值