Redis之内存
1. 内存消耗
1. 如何查看内存统计
info memory
重点关注指标:used_memory_rss和used_memory以及它们的比值mem_fragmentation_ratio
当mem_fragmentation_ratio>1,说明多出的部分内存没有用于数据存储,而是被内存碎片所消耗,如果两者相差很大,说明碎片率严重。
当mem_fragmentation_ratio<1,这种情况一般出现在操作系统把Redis内存交换到硬盘导致,出现这种情况时要格外关注,由于磁盘速度远远慢于内存,Redis性能会变得很差,甚至僵死。
2. 内存消耗划分
1. 自身内存 忽略不计
2. 对象内存 占用最大
size of keys + size of values
键对象都是字符串,应该避免使用过长的键
值对象包含5种数据类型:字符串,哈希,列表,集合,有序集合
3. 缓冲内存
1. 客户端缓冲 所有接入到Redis服务器TCP连接的输入输出缓冲
1. 输入缓冲
输入缓冲最大1G
2. 输出缓冲
通过参数client-output-buffer-limit控制
client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
1. 普通客户端
normal 0 0 0,如果有大量慢连接客户端接入时这部分内存消耗就不能消耗了,可以设置maxclients做限制
2. 从客户端
slave 268435456 67108864 60 主从节点不要部署在较差的网络环境下,如异地跨机房环境
3. 订阅客户端
2. 复制积压缓冲区
repl-backlog-size 默认为1MB
主节点只有一个,可以修改为较大的缓冲区空间
3. AOF缓冲区
用于在Redis重写期间保存最近的写入命令
4. 内存碎片
1. Redis默认的内存分配器采用jemalloc
小:8byte,16byte,32byte,48byte
大:4KB,8KB,12KB...
巨大:4MB,8MB,12MB...
正常的碎片率在1.03左右
2. 容易产生碎片的场景
1. 频繁做更新操作,例如频繁对已存在的键执行append,setrange等更新操作
2. 大量过期键删除,键对象过期删除后,释放的空间无法得到充分利用,导致碎片率上升
3. 存储的数据长短差异较大
3. 出现高内存碎片的解决方式
数据对齐
数据尽量采用数字类型或者固定长度字符串
安全重启
5. 子进程内存消耗
需要设置sysctl vm.overcommit_memory=1
关闭THP
2. 内存管理
1. 设置内存上限
防止所用内存超过物理内存
通过redis.conf文件配置maxmemory参数
2. 动态设置内存
config set maxmemory
config get maxmemory
3. 内存回收策略
1. 删除到达过期时间的键对象
1. 惰性删除
客户端访问带有过期属性的keys,会执行删除并返回空。但是如果过期keys不访问,就不会被删除。
2. 定时任务删除
2. 内存使用达到maxmemory上限时触发内存溢出控制策略
1) noeviction: 默认策略, 不会删除任何数据, 拒绝所有写入操作并返 回客户端错误信息(error) OOM command not allowed when used memory, 此 时Redis只响应读操作。 2) volatile-lru: 根据LRU算法删除设置了超时属性(expire) 的键, 直 到腾出足够空间为止。 如果没有可删除的键对象, 回退到noeviction策略。 3) allkeys-lru: 根据LRU算法删除键, 不管数据有没有设置超时属性, 直到腾出足够空间为止。 4) allkeys-random: 随机删除所有键, 直到腾出足够空间为止。 5) volatile-random: 随机删除过期键, 直到腾出足够空间为止。 6) volatile-ttl: 根据键值对象的ttl属性, 删除最近将要过期数据。 如果 没有, 回退到noeviction策略。
3. 内存优化
1. 控制字符串长度,减少创建redisObject内存分配次数
2. 缩减键和值的长度
对于key的优化
使用单词简写方式优化内存占用
对于value的优化
过滤不必要的数据:想办法去掉一些不必要的属性
精简数据:比如用户的会员类型:0,1,2,不要用VIP字符串
数据压缩:对数据的内容进行压缩,比如:GZIP,Snappy
使用性能好,内存占用小的序列化方式:protostuff,kryo
3. 共享对象池
4. 字符串优化
5. 编码优化
6. 控制键的数量
7. 碎片优化