【原创】为什么 Redis 重启后没有正确恢复之前的内存数据

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:
安装 Redis 后,默认配置下启动会得到如下日志:  
?
1
2
[3077] 05 Sep 10:01:54.181 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.
To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl .conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
      该输出信息大致的意思是:   overcommit_memory 值目前设置为 0 !在可用内存比较少时,后台执行的 save 命令可能会失败。为了修复该问题,需要添加 'vm.overcommit_memory  = 1' 到 /etc/sysctl.conf 文件中,并   通过   重启系统或执行 'cysctl vm.overcommit_memory=1' 命令使得该配置生效。  

查看系统中的配置如下:  
?
1
2
[root@Betty ~] # sysctl vm.overcommit_memory
vm.overcommit_memory = 0
恩,确实系统配置为 0 。那么 overcommit_memory 该值的含义是什么?可以设置哪些值呢?  

网上相关文章对该参数有如下说明:  

  CommitLimit 和 Committed_As    
?
1
2
3
4
[root@Betty ~] # grep -i commit /proc/meminfo
CommitLimit:     5856624 kB
Committed_AS:     863300 kB
[root@Betty ~] #
在内存信息中可以看到 CommitLimit 和 Committed_As 两个参数。其中  
  • CommitLimit 是内存分配的上限。CommitLimit = 物理内存 * overcommit_ratio/100 + swap
  • Committed_As 是已经分配的内存大小。
  overcommit_memory    

说法一:  
overcommit_memory 参数就是控制内存分配是否可以超过 CommitLimit 值的,其指定了内核针对内存分配的策略,默认是 0 。  
  • 0 表示尽量减少 swap 的使用;
  • 1 表示允许超过 CommitLimit ;
  • 2 表示不允许超过 CommitLimit 。

说法二:  
  • 0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,则允许内存申请;否则,内存申请失败,并把错误返回给应用进程。
  • 1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
  • 2, 表示内核允许分配超过所有物理内存和交换空间总和的内存

说法三:  
vm.overcommit_memory 表示内核在分配内存时候做检查的方式。   这个变量可以取到 0、1、2 三个值。针对取不同的值时的处理方式,定义在内核源码 mm/mmap.c 的 __vm_enough_memory 函数中。  

取 1 时   此时宏为 OVERCOMMIT_ALWAYS,函数直接 return 0,分配成功。  
取 2 时:    此时宏为 OVERCOMMIT_NEVER,内核计算:  
?
1
内存总量*vm.overcommit_ratio /100 + SWAP 的总量
如果申请空间超过此数值,则分配失败。vm.overcommit_ratio 的默认值为 50。  
取 0 时   此时宏为 OVERCOMMIT_GUESS,内核计算:  
?
1
NR_FILE_PAGES 总量 + SWAP总量 + slab 中可以释放的内存总量
如果申请空间超过此数值,则将此数值与空闲内存总量减掉 total reserve_pages(?) 的总量相加。如果申请空间依然超过此数值,则分配失败。  

以上为粗略描述,在实际计算时,   如果非 root 进程,则在计算时候会保留 3% 的空间,而 root 进程则没有该限制    

说法四:  
vm.overcommit_memory    默认值为 0 。   从内核文档里得知,该参数有三个值,分别是:  
  • 0:当用户空间请求更多的的内存时,内核尝试估算出剩余可用的内存;
  • 1:当设这个参数值为 1 时,内核允许超量使用内存直到用完为止,主要用于科学计算;
  • 2:当设这个参数值为 2 时,内核会使用一个决不过量使用内存的算法,即系统整个内存地址空间不能超过 swap + 50% 的 RAM 值50% 参数的设定是在 overcommit_ratio 中设定。
vm.overcommit_ratio    默认值为 50 。   这个参数值只有在 vm.overcommit_memory=2 的情况下,这个参数才会生效。  

说法五:  
Controls overcommit of system memory, possibly allowing processes to allocate (but not use) more memory than is actually available.  
  • 0 - Heuristic overcommit handling. Obvious overcommits of address space are refused. Used for a typical system. It ensures a seriously wild allocation fails while allowing overcommit to reduce swap usage. root is allowed to allocate slighly more memory in this mode. This is the default.
  • 1 - Always overcommit. Appropriate for some scientific applications.
  • 2 - Don't overcommit. The total address space commit for the system is not permitted to exceed swap plus a configurable percentage (default is 50) of physical RAM. Depending on the percentage you use, in most situations this means a process will not be killed while attempting to use already-allocated memory but will receive errors on memory allocation as appropriate.

说法六(可以认为是上面英文比较准确的翻译):  
  • 0:默认值,由 Linux 内核通过一些启发式算法来决定是否超售和超售的大小,一般允许轻微的超售,拒绝一些明显不可能提供的请求,同时做一些规则限制,比如不同用户 overcommit 的大小也不一样。 
  • 1:允许,不做限制的超售,当然这个也不是无限大,还受到寻址空间的限制,32 位系统最大可能只有 4G,64 位系统大概 16T 左右。 
  • 2:禁止,禁止超售,系统能够分配的内存不会超过 swap + 实际物理内存 * overcommit_ratio,该值可以通过 /proc/sys/vm/overcommit_ratio设置,默认 50% 。


说了半天,这个和 Redis 上面给出的输出信息有什么关系呢?  
         目前我认为比较正确的解释是这样的:Redis 在执行 bgsave 的时候需要 fork 出一个子进程,一般情况下我们认为子进程所需内存空间的量等于父进程内存空间使用量,但由于 Linux 中 COW 的原因,子进程在刚刚运行时可能并不需要占用等同于父进程使用的内存量。但是尽管如此,若系统当前可用内存量较少,且在 overcommit_memory = 0 的情况下,就可能会出现由于判定内存不足导致分配失败的情况(虽然实际上可能并不真正需要那么多内存)。所以 overcommit = 1 这种设置对于 Redis 这种缓存系统显得更为有意义。  
      关于    overcommit 本身,其实还有很多可以研究的地方,以上只是本人粗浅的理解,后续将继续学习相关知识。  

=== 我是华丽的分隔线 ===  

      什么是 overcommit?overcommit 中文翻译为“超售”。   在某些操作系统中(如 Solaris),malloc 函数返回为 null 则表示系统没有可分配的内存空间。但 Linux 的内存分配采取的是一种更加积极的分配策略,它假设应用申请了内存空间后并不会立即去使用它,所以允许一定量的超售,当应用真的需要使用它的时候,操作系统可能已经通过回收了其他应用的内存空间而变得有能力去满足这个应用的需求,简单的说,就是允许应用申请比实际可分配空间(包括物理内存和 Swap)更多的内存,这个特性称为 OverCommit 。  
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
7天前
|
缓存 NoSQL 关系型数据库
13- Redis和Mysql如何保证数据⼀致?
该内容讨论了保证Redis和MySQL数据一致性的几种策略。首先提到的两种方法存在不一致风险:先更新MySQL再更新Redis,或先删Redis再更新MySQL。第三种方案是通过MQ异步同步以达到最终一致性,适用于一致性要求较高的场景。项目中根据不同业务需求选择不同方案,如对一致性要求不高的情况不做处理,时效性数据设置过期时间,高一致性需求则使用MQ确保同步,最严格的情况可能涉及分布式事务(如Seata的TCC模式)。
31 6
|
7天前
|
NoSQL Redis
05- Redis的数据淘汰策略有哪些 ?
Redis 提供了 8 种数据淘汰策略:挥发性 LRU、LFU 和 TTL(针对有过期时间的数据),挥发性随机淘汰,以及全库的 LRU、LFU 随机淘汰,用于在内存不足时选择删除。另外,还有不淘汰策略(no-eviction),允许新写入操作报错而非删除数据。
9 1
|
9天前
|
NoSQL 安全 Redis
redis内存限制与淘汰策略
Redis内存管理包括限制和淘汰策略。`maxmemory`配置参数决定内存上限,无设置时64位系统默认不限制,可能导致系统资源耗尽,生产环境建议设定合理值。当内存满时,未设置淘汰策略会导致写入错误。Redis提供8种淘汰策略,如LRU(最近最少使用)和LFU(最不经常使用),以及随机或基于过期时间的删除。需根据数据重要性、访问频率和一致性选择合适策略。
13 0
|
9天前
|
存储 C语言
数据在内存中的存储2
数据在内存中的存储2
|
9天前
|
存储 编译器
数据在内存中的存储1
数据在内存中的存储
|
14天前
|
NoSQL 安全 网络安全
保护Redis:建立铁壁般的安全防线,守护你的数据财富
保护Redis:建立铁壁般的安全防线,守护你的数据财富
|
14天前
|
消息中间件 存储 NoSQL
Redis Stream: 实时消息处理的利器,让你的数据流畅又可靠!
Redis Stream: 实时消息处理的利器,让你的数据流畅又可靠!
|
14天前
|
存储 缓存 NoSQL
Redis 服务器指南:高性能内存数据库的完整使用指南
Redis 服务器指南:高性能内存数据库的完整使用指南
|
28天前
|
存储 JSON 监控
Higress Controller**不是将配置信息推送到Istio的内存存储里面的**。
【2月更文挑战第30天】Higress Controller**不是将配置信息推送到Istio的内存存储里面的**。
14 1
|
1月前
|
存储 C语言
C语言--------数据在内存中的存储
C语言--------数据在内存中的存储
26 0