从Redis的数据丢失说起(转)
碰到一个悲催的事情:一台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的数据回写机制分同步和异步两种,
- 同步回写即SAVE命令,主进程直接向磁盘回写数据。在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的。
- 异步回写即BGSAVE命令,主进程fork后,复制自身并通过这个新的进程回写磁盘,回写结束后新进程自行关闭。由于这样做不需要主进程阻塞,系统不会假死,一般默认会采用这个方法。
个人感觉方法2采用fork主进程的方式很拙劣,但似乎是唯一的方法。内存中的热数据随时可能修改,要在磁盘上保存某个时间的内存镜像必须要冻结。冻结就会导致假死。fork一个新的进程之后等于复制了当时的一个内存镜像,这样主进程上就不需要冻结,只要子进程上操作就可以了。
在小内存的进程上做一个fork,不需要太多资源,但当这个进程的内存空间以G为单位时,fork就成为一件很恐怖的操作。何况在16G内存的主机上fork 14G内存的进程呢?肯定会报内存无法分配的。更可气的是,越是改动频繁的主机上fork也越频繁,fork操作本身的代价恐怕也不会比假死好多少。
找到原因之后,直接修改内核参数vm.overcommit_memory = 1
Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。
- 如果 vm.overcommit_memory = 1,直接放行
- vm.overcommit_memory = 0:则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。
- vm.overcommit_memory = 2:则会比较 进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行。
从Redis的数据丢失说起(转)的更多相关文章
- Redis持久化-数据丢失及解决(转载)
本文转载自 Redis持久化-数据丢失及解决 感谢原作者 Redis的数据回写机制 Redis的数据回写机制分同步和异步两种, 同步回写即SAVE命令,主进程直接向磁盘回写数据.在数据 ...
- Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方
Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方案 >>>>>>>>>>>>>> ...
- Redis持久化-数据丢失及解决
Redis的数据回写机制 Redis的数据回写机制分同步和异步两种, 同步回写即SAVE命令,主进程直接向磁盘回写数据.在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的. 异步回写即BGSA ...
- redis-内存异常 Redis is configured to save RDB snapshots解决
连接reids获取数据时提示 Redis is configured to save RDB snapshots, but is currently not able to persist on di ...
- Redis详解(一)------ redis的简介与安装
工作中一直在用 Redis,但是一直没有进行系统的总结,这个系列的博客将整体的介绍 Redis 的用法. 1.Redis 的简介 Redis:REmote DIctionary Server(远程字典 ...
- Redis学习01_redis安装部署(centos)
原文: http://www.cnblogs.com/herblog/p/9305668.html Redis学习(一):CentOS下redis安装和部署 1.基础知识 redis是用C语言开发的 ...
- Redis集群方案<转>
为什么集群? 通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取.Redis是一个很好的Cache工具.大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿,在 ...
- redis集群与分片(1)-redis服务器集群、客户端分片
下面是来自知乎大神的一段说明,个人觉得非常清晰,就收藏了. 为什么集群? 通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取.Redis是一个很好的Cache工具.大型 ...
- Redis学习(一):CentOS下redis安装和部署
1.基础知识 redis是用C语言开发的一个开源的高性能键值对(key-value)数据库.它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止redis支持的键值数据类型如下字符串.列表 ...
随机推荐
- shell邮件发送功能实现
本文中以163邮箱为例,测试shell邮件发送功能.常见的工具有:mailx.sendmail.mutt等. 1.设置邮件客户端 (1)启用pop3.smtp服务,以支持第三方客户端支持 (2)设置授 ...
- centos7,php7 安装mysqli扩展
首先安装MySQL https://www.cnblogs.com/manzb/p/9560403.html php7安装后没有安装mysqli扩展的话: 安装mysqli扩展 1.到php文件e ...
- hdu GuGuFishtion 6390 数论 欧拉函数
题目:http://acm.hdu.edu.cn/showproblem.php?pid=6390 直接开始证明: 我们设…………………………………….....…...............………… ...
- Mini Twitter
Implement a simple twitter. Support the following method: postTweet(user_id, tweet_text). Post a twe ...
- Linux硬盘的检测(原创)
http://czmmiao.iteye.com/blog/1058215 概述 随着硬盘容量.速度的快速发展,硬盘的可靠性问题越来越重要,今天的单块硬盘存储容量可轻松达到1TB,硬盘损坏带来的影响非 ...
- trove远程连接mongodb
创建数据库 <pre> [root@a581c7388dca /]# trove database-create e50f3b40-5165-4ccc-af9f-c121089fd902 ...
- How to fix Eclipse Tomcat startup timeout in 45 seconds?
命题:怎么修复 Eclipse 里启动 Tomcat 时, 默认启动超时时间为 45 秒的问题? 在 Eclipse 的 J2EE 项目里启动 Tomcat 来调试 Servlet 之类的,断点以后, ...
- html复习之标签整理
<body>标签,网页上显示的内容放在这里开始学习<p>标签,添加段落<hx>标签,为网页添加标题加入强调语气,使用<strong>加粗和<em& ...
- kali linux2.0安装vega
1.到官网下载安装包(选择版本:我这里以Linux64位为例) vega下载地址:https://subgraph.com/vega/download/ 2.解压到指定目录: unzip VegaBu ...
- 多继承下的super()指向的不一定是直接父类
常规情况 class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super ...