一台Redis服务器,4核,16G内存且没有任何硬件上的问题。持续高压运行了大约3个月,保存了大约14G的数据,设置了比较完备的Save参数。而就是这台主机,在一次重起之后,丢失了大量的数据,14G的数据最终只恢复了几百兆而已。

正常情况下,像Redis这样定期回写磁盘的内存数据库,丢失几个数据也是在情理之中,可超过80%数据丢失率实在太离谱。排除了误操作的可能性之后,开始寻找原因。

重启动时的日志:

[26641] 21 Dec 09:46:34 * Slave ask for synchronization

[26641] 21 Dec 09:46:34 * Starting BGSAVE for SYNC

[26641] 21 Dec 09:46:34 # Can’t save in background: fork: Cannot allocate memory

[26641] 21 Dec 09:46:34 * Replication failed, can’t BGSAVE

[26641] 21 Dec 09:46:34 # Received SIGTERM, scheduling shutdown…

[26641] 21 Dec 09:46:34 # User requested shutdown…

很明显的一个问题,系统不能在后台保存,fork进程失败。

翻查了几个月的日志,发觉系统在频繁报错:

[26641] 18 Dec 04:02:14 * 1 changes in 900 seconds. Saving…

[26641] 18 Dec 04:02:14 # Can’t save in background: fork: Cannot allocate memory

系统不能在后台保存,fork进程时无法指定内存。

对源码进行跟踪,在src/rdb.c中定位了这个报错:

int rdbSaveBackground(char *filename) {
pid_t childpid;
long long start; if (server.bgsavechildpid != -1) return REDIS_ERR;
if (server.vm_enabled) waitEmptyIOJobsQueue();
server.dirty_before_bgsave = server.dirty;
start = ustime();
if ((childpid = fork()) == 0) {
/* Child */
if (server.vm_enabled) vmReopenSwapFile();
if (server.ipfd > 0) close(server.ipfd);
if (server.sofd > 0) close(server.sofd);
if (rdbSave(filename) == REDIS_OK) {
_exit(0);
} else {
_exit(1);
}
} else {
/* Parent */
server.stat_fork_time = ustime()-start;
if (childpid == -1) {
redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
strerror(errno));
return REDIS_ERR;
}
redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
server.bgsavechildpid = childpid;
updateDictResizePolicy();
return REDIS_OK;
}
return REDIS_OK; /* unreached */
}

数据丢失的问题总算搞清楚了!

Redis的数据回写机制分同步和异步两种,

  1. 同步回写即SAVE命令,主进程直接向磁盘回写数据。在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的。
  2. 异步回写即BGSAVE命令,主进程fork后,复制自身并通过这个新的进程回写磁盘,回写结束后新进程自行关闭。由于这样做不需要主进程阻塞,系统不会假死,一般默认会采用这个方法。

个人感觉方法2采用fork主进程的方式很拙劣,但似乎是唯一的方法。内存中的热数据随时可能修改,要在磁盘上保存某个时间的内存镜像必须要冻结。冻结就会导致假死。fork一个新的进程之后等于复制了当时的一个内存镜像,这样主进程上就不需要冻结,只要子进程上操作就可以了。

在小内存的进程上做一个fork,不需要太多资源,但当这个进程的内存空间以G为单位时,fork就成为一件很恐怖的操作。何况在16G内存的主机上fork 14G内存的进程呢?肯定会报内存无法分配的。更可气的是,越是改动频繁的主机上fork也越频繁,fork操作本身的代价恐怕也不会比假死好多少。

找到原因之后,直接修改内核参数vm.overcommit_memory = 1

Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。

  1. 如果 vm.overcommit_memory = 1,直接放行
  2. vm.overcommit_memory = 0:则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。
  3. vm.overcommit_memory = 2:则会比较 进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行。

Redis一次数据丢失的更多相关文章

  1. Redis一次数据丢失(转)

    一台Redis服务器,4核,16G内存且没有任何硬件上的问题.持续高压运行了大约3个月,保存了大约14G的数据,设置了比较完备的Save参数.而就是这台主机,在一次重起之后,丢失了大量的数据,14G的 ...

  2. 04 AOF日志:宕机了,Redis如何避免数据丢失

    接下来两篇将记录Redis持久化存储两大技术:AOF日志.RDB快照 本篇重点 "AOF日志实现""AOF日志三种写回策略""AOF重写--避免日志过 ...

  3. centos重启redis后,数据丢失

    编辑/etc/sysctl.conf ,改vm.overcommit_memory=1, 然后sysctl -p 使配置文件生效 T

  4. Linux中python3,django,redis以及mariab的安装

    1. Linux中python3,django,redis以及mariab的安装 2. CentOS下编译安装python3 编译安装python3.6的步骤 1.下载python3源码包 wget ...

  5. linux安装redis ,mariadb

    linux下安装软件方法 1 rpm (不推荐使用) 2 yum 安装(非常方便快捷) 3 编译安装(需要自定制的时候才使用) 安装mariadb(mysql) 1 使用官方源安装mariadb vi ...

  6. Redis系列(一):Redis的简介与安装

    原文链接(转载请注明出处):Redis系列(一):Redis的简介与安装 什么是 Redis Redis 是一个使用ANSI C 编写的开源.支持网络协议.基于内存.可选持久性的键值对数据库,它是一个 ...

  7. redis参数改进建议

    1.修改stop-writes-on-bgsave-error为no当前配置为yes,分别修改redis.conf和当前实例#redis.confstop-writes-on-bgsave-error ...

  8. Java实现排行榜基于Redis

    访问我的博客 前言 排行榜作为互联网应用中几乎必不可少的一个元素,其能够勾起人类自身对比的欲望,从而来增加商品的销量.排行榜的实现方式基本大同小异,大部分都基于 Redis 的有序集合 sorted ...

  9. # 深入理解Redis(二)——内存管理的建议与技巧

    引语 随着使用Redis的深入,我们不可避免的需要深入了解优化Redis的内存,本章将重点讲解Redis的内存优化之道,同时推荐大家阅读memory-optimization一文. 想要高效的使用Re ...

随机推荐

  1. plsql连接oracle数据库,不用配置任何东西(转)

    在软件开发的过程中,对于使用oracle的朋友们来说,使用plsql工具操作oracle数据库是非常方便的,可是plsql连接oracle数据库的方式有很多种,今天就给大家介绍一种最简单的连接方式,只 ...

  2. Spark2.3(三十四):Spark Structured Streaming之withWaterMark和windows窗口是否可以实现最近一小时统计

    WaterMark除了可以限定来迟数据范围,是否可以实现最近一小时统计? WaterMark目的用来限定参数计算数据的范围:比如当前计算数据内max timestamp是12::00,waterMar ...

  3. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(三十):使用flatMapGroupsWithState替换agg

    flatMapGroupsWithState的出现解决了什么问题: flatMapGroupsWithState的出现在spark structured streaming原因(从spark.2.2. ...

  4. Gson解析第三方提供Json数据(天气预报,新闻等)

    之前都是自己写后台,自己的server提供数据给client. 近期在看第三方的数据接口,訪问其它站点提供的信息.比方.我们可能自己收集的数据相当有限.可是网上提供了非常多关于天气预报.新闻.星座运势 ...

  5. python实现模拟登录

    本文主要用python实现了对网站的模拟登录.通过自己构造post数据来用Python实现登录过程.   当你要模拟登录一个网站时,首先要搞清楚网站的登录处理细节(发了什么样的数据,给谁发等...). ...

  6. zabbix监控k8s出现的pod error status

    配置zabbix客户端配置文件 vim /etc/zabbix/zabbix_agentd.conf 添加  Include=/etc/zabbix/zabbix_agentd.d/ #!/bin/b ...

  7. WPF显示图片

    1.WPF显示图片内部一部分 <Rectangle Height="> <Rectangle.Fill > <ImageBrush ImageSource=&q ...

  8. win8下C盘不能读写的解决方案[zz]

    做系统安全的时候发现了这个/setintegritylevel参数,没有找到更多资料,找到此文,看来这个参数有点神奇哟!我一个同事遇到了这个问题,主要症状:1.C 盘文件不能修改2.C 盘不能新建文件 ...

  9. IIS发布的网站常见的问题汇总

    1.安装.NET4.0时缺少WIC导致不能装上.NET4.0,下载安装后即可,下载地址如下,根据系统版本选择对应软件 32位版:https://www.microsoft.com/zh-cn/down ...

  10. 每日英语:How To Survive The Windows XPiration Date

    The default background for Microsoft's Windows XP operating system -- a perfect blue sky full of cot ...