# 1.优化内存占用

了解redis的内存模型,对优化redis内存占用有很大帮助。下面介绍几种优化场景。

- 1)利用jemalloc特性进行优化

上一小节所讲述的90000个键值便是一个例子。由于jemalloc分配内存时数值是不连续的,因此key/value字符串变化一个字节,可能会引起占用内存很大的变动;在设计时可以利用这一点。

例如,如果key的长度如果是8个字节,则SDS为17字节,jemalloc分配32字节;此时将key长度缩减为7个字节,则SDS为16字节,jemalloc分配16字节;则每个key所占用的空间都可以缩小一半。

- 2)使用整型/长整型

如果是整型/长整型,Redis会使用int类型(8字节)存储来代替字符串,可以节省更多空间。因此在可以使用长整型/整型代替字符串的场景下,尽量使用长整型/整型。

- 3)共享对象

利用共享对象,可以减少对象的创建(同时减少了redisObject的创建),节省内存空间。目前redis中的共享对象只包括10000个整数(0-9999);可以通过调整``REDIS_SHARED_INTEGERS``参数提高共享对象的个数;例如将REDIS_SHARED_INTEGERS调整到20000,则0-19999之间的对象都可以共享。

考虑这样一种场景:论坛网站在redis中存储了每个帖子的浏览数,而这些浏览数绝大多数分布在0-20000之间,这时候通过适当增大REDIS_SHARED_INTEGERS参数,便可以利用共享对象节省内存空间。

- 4)避免过度设计

然而需要注意的是,不论是哪种优化场景,都要考虑内存空间与设计复杂度的权衡;而设计复杂度会影响到代码的复杂度、可维护性。

如果数据量较小,那么为了节省内存而使得代码的开发、维护变得更加困难并不划算;还是以前面讲到的90000个键值对为例,实际上节省的内存空间只有几MB。但是如果数据量有几千万甚至上亿,考虑内存的优化就比较必要了。

# 2.关注内存碎片率

内存碎片率是一个重要的参数,对redis 内存的优化有重要意义。

如果内存碎片率过高(jemalloc在1.03左右比较正常),说明内存碎片多,内存浪费严重;这时便可以考虑重启redis服务,在内存中对数据进行重排,减少内存碎片。

如果内存碎片率小于1,说明redis内存不足,部分数据使用了虚拟内存(即swap);由于虚拟内存的存取速度比物理内存差很多(2-3个数量级),此时redis的访问速度可能会变得很慢。因此必须设法增大物理内存(可以增加服务器节点数量,或提高单机内存),或减少redis中的数据。

要减少redis中的数据,除了选用合适的数据类型、利用共享对象等,还有一点是要设置合理的数据回收策略(maxmemory-policy),当内存达到一定量后,根据不同的优先级对内存进行回收。

# 3.内存增长排查

## 3.1 Redis内存分析

### 3.1.1 内存组成

```bash

redis> info memory

"# Memory

used_memory:29020136

used_memory_human:27.68M

used_memory_rss:15560704

used_memory_peak:45295152

used_memory_peak_human:43.20M

used_memory_lua:36864

mem_fragmentation_ratio:0.54

mem_allocator:jemalloc-3.6.0

"

```

属性名属性说明

used_memory Redis 分配器分配的内存量,也就是实际存储数据的内存总量used_memory_human 以可读格式返回 Redis 使用的内存总量used_memory_rss 从操作系统的角度,Redis进程占用的总物理内存used_memory_peak 内存分配器分配的最大内存,代表used_memory的历史峰值used_memory_peak_human 以可读的格式显示内存消耗峰值used_memory_lua Lua引擎所消耗的内存mem_fragmentation_ratio used_memory_rss /used_memory比值,表示内存碎片率mem_allocator Redis 所使用的内存分配器。默认: jemalloc

---

计算公式如下:

```

used_memory = 自身内存+对象内存+缓冲内存+lua内存

used_rss = used_memory + 内存碎片

```

如下图所示:

![](https://ghost.oss.sherlocky.com/7/e9/424ebf6d90efcb0796ec856f0e4d0.png)

### 3.1.2 内存分析

- 1) 自身内存:一个空的Redis占用很小,可以忽略不计

- 2) kv内存:key对象 + value对象

- 3) 缓冲区:客户端缓冲区(普通 + slave伪装 + pubsub)以及aof缓冲区(比较固定,一般没问题)

- 4) Lua:Lua引擎所消耗的内存

### 3.1.3. 内存突增常见问题

- 1) kv内存:bigkey、大量写入

- 2) 客户端缓冲区:一般常见的有普通客户端缓冲区(例如monitor命令)或者pubsub客户端缓冲区

## 3.2 可能出现的问题排查

- 1) bigkey?

> redis --bigkeys:可以对redis整个 keyspace 进行统计(数据量大时采样,调用 scan 命令),寻找每种数据类型较大的 keys,给出数据统计

``redis-cli --bigkeys -i 0.1 -h 127.0.0.1``

- 2) 键值个数增加?

- 3) 客户端缓冲区

> 如果是因为缓冲区问题,会从``info clients``找到明显问题。重点观察是否明显的``omem``大于0的情况。

- 4) Redis的kv哈希表做了 rehash

## 3.4 rehash

### 3.4.1 Redis的kv存储结构

如下图所示,Redis的所有kv保存在dict中,其中ht对应两个哈希表ht[0]和ht[1],平时一个空闲,一个用于存储数据,只有当需要rehash时,ht[1]才会用到。

![](https://ghost.oss.sherlocky.com/1/2c/b8ce4bb1f0d5576fd95549fe3a9a4.png)

### 3.4.2 Redis的字典rehash

为了保证哈希表的负载,当哈希表的元素个数等于哈希表槽数时候,会进行rehash扩容。扩容后h[1]的容量等于第一个大于等于ht[0].size*2的2n,例如hash表的初始化容量是4,那么下一次扩容就是8,以此类推。

## 3.5 总结

由于哈希表的特性,Redis 中键值数量大,不会对存取造成性能影响,但是会出现内存增长的情况。

控制键个数有几个建议:

- 无用的键值设置过期时间或者定期删除

- 优化键值设计:例如可以使用 ziplist hash合并优化部分字符串类型。-

- 未来改进:内核层面支持 rehash 的审计日志以及增强 rehash 的速度

参考:

[精讲Redis内存模型](https://my.oschina.net/u/3779583/blog/1829617)

[一次 Redis 内存诡异增长的排查过程](https://mp.weixin.qq.com/s/eXKkfhdG8VyS9OmKZOkeEw)

redis 内存不足 排查_Redis——内存占用优化相关推荐

  1. redis 内存不足 排查_Redis内存溢出问题排查

    Redis内存溢出问题排查 最近生产环境服务器上的redis内存波动,导致了一次OOM,查询/var/log/messages后发现原本只会在1~2G大小之间波动的Redis内存竟然达到8G,然后OO ...

  2. redis 内存不足 排查_Redis 系统学习之 redis 内存模型

    关注:架构师学习路线,每日更新互联网最新技术文章与你不断前行,实战资料,笔试面试 前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并 ...

  3. java内存问题怎么排查,java占内存高排查 java应用占用内存过高排查的解决方案...

    想了解java应用占用内存过高排查的解决方案的相关内容吗,zhaixing_0307在本文为您仔细讲解java占内存高排查的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:java,占内存过 ...

  4. linux 内存溢出排查_java 内存溢出 栈溢出的原因与排查方法

    1. 内存溢出的原因是什么? 内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出.如果出现这种现象可行代码排查: 一)是否应用中的类中和引用变量过多使用了Static修饰 ...

  5. redis 内存不足 排查_redis莫名数据被清问题排查记录

    新版系统刚发布,前端反馈redis中的值经常被清空,第一反应怀疑谁的代码里面执行了flushall或者flushdb操作 通过redis的monitor追踪一波, redis-cli -a " ...

  6. Linux用户态进程监控内存写排查踩内存

    高铁北京回杭州的路上,想到一个简单的话题. 在一个复杂的程序中,发生踩内存是一件非常恶心的事情,很难通过什么线索直到谁在哪个函数中往哪个地址写了什么,比方说数组越界写什么的. 去年,我曾经长篇大论了一 ...

  7. redis存储对象_redis内存优化总结

    本文主要参考<>一书,主要分为以下六个部分: 1.redisObject对象 2.缩减键值对象 3.共享对象池 4.字符串优化 5.编码优化 6.控制key的数量 一. redisObje ...

  8. redis 内存不足 排查_一文深入了解 Redis 内存模型,Redis 的快是有原因的!

    前言 一.Redis内存统计 二.Redis内存划分 1.数据 2.进程本身运行需要的内存 3.缓冲内存 4.内存碎片 三.Redis数据存储的细节 1.概述 2.jemalloc 3.redisOb ...

  9. gin redis 链接不上_内存优化,Redis是如何实现的!

    点击上方"小罗技术笔记",关注公众号 第一时间送达实用干货 各位朋友新年开工好,今年由于特殊情况好多小伙伴今天在家开启远程办公模式(一直很向往),不过在这真想吐槽一下现有的远程办公 ...

最新文章

  1. 为什么说 TCP/IP 是一个不确定性网络
  2. mysql5.0修改字符集,查看mysql字符集及修改表结构
  3. 一颗椰子糖机器人_孩子编程启蒙机器人玩了不下10个,最推荐哪个呢?
  4. 使用pytorch的相关问题总结
  5. QualityCenter的备份
  6. php16进制密钥签名对接支付,简单理解rsa的加密和签名-PHP实现
  7. Jquery实现定时器实例
  8. JAVA责任链设计模式
  9. 相机模型-Extended Unified Camera Model
  10. 用python写论文_[文章] 编写高质量 Python 的 6 个技巧
  11. 《算法设计与分析基础》第2版
  12. 在Linux下安装GmSSL
  13. mmdetection 绘制PR曲线
  14. 加州大学戴维斯计算机博士生,关于加州大学戴维斯分校博士研究生CSC奖学金信息分享会的通知...
  15. 手机摄影技巧总结——永远拍出美美的照片
  16. 计算机上计算器不见,win10系统自带的计算器不见了的处理教程
  17. 计算机文化基础(高职高专版 第十一版)第一章答案
  18. rem和vw,vh的介绍
  19. 在12306的程序猿面前,没人敢说委屈
  20. 奋斗(2)第15集剧情介绍

热门文章

  1. 【Python】使用生成器(yield from)和装饰器封装函数
  2. vue+element 创建Cron表达式生成器组件 [带最近五次执行时间]
  3. 域控锁定计算机和用户,AD域账户锁定时间
  4. Oracle数据库常用函数总结
  5. 数据结构 - 串的模式匹配
  6. 如何不浪费青春,让游戏快速上架 Steam
  7. 【Java】判断电话号码所属的运营商
  8. 【观察】数智驱动+知识封装,鼎捷软件如何炼就“雅典娜”这个“新物种”?...
  9. 第四章第8节 网络中的网络(NiN)
  10. linux中tr的功能多多