Redis崩溃调试

背景

Redis的代码质量一直被业内人士称赞,在极高的业务压力下也能有很好的稳定性。但是极端情况下,Redis也是有可能会Crash的。有时候因为种种原因,系统配置问题,磁盘空间写满了,进程权限不够等等,我们可能不会运气那么好,有一个core文件可以拿去调试。这个时候,Redis提供了几种异常崩溃情况下的Crash Report,很多时候我们基于Crash Report,再加上一定的分析就可以直接定位问题了。

Crash Report

在异常崩溃时,Redis会通过设置的signal handler来生成Crash Report,目前Redis为生成Crash Report捕获的异常信号主要有以下几种:

  • SIGSEGV
  • SIGFPE
  • SIGILL
  • SIGBUS

这4种信号应该能包含大部分程序异常崩溃情况了,最常见的就是SIGSEGV段错误了,除0异常SIGFPE有时候也会遇到。

当Redis收到上面4种信号之一时,会在设置的sigsegvHandler()函数中生成Crash Report,如下,

=== REDIS BUG REPORT START: Cut & paste starting from here ===
[19179] 12 Apr 18:47:42.599 #     Redis 2.8.19 crashed by signal: 11
[19179] 12 Apr 18:47:42.599 #     Failed assertion: <no assertion failed> (<no file>:0)
[19179] 12 Apr 18:47:42.599 # --- STACK TRACE
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(logStackTrace+0x4a)[0x7f5be2d6895a]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(debugCommand+0x1b0)[0x7f5be2d69ad0]
/lib64/libpthread.so.0(+0xf500)[0x7f5be3c1a500]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(debugCommand+0x1b0)[0x7f5be2d69ad0]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(call+0x8a)[0x7f5be2d2f12a]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(processCommand+0x5dd)[0x7f5be2d3017d]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(processInputBuffer+0x4d)[0x7f5be2d3b86d]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(readQueryFromClient+0xf0)[0x7f5be2d3cb70]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(aeProcessEvents+0x13d)[0x7f5be2d2804d]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(aeMain+0x2b)[0x7f5be2d2833b]
/home/dejun.xdj/kvs-kernel/src/libredis-server.so(runRedis+0x4f)[0x7f5be2d31eaf]
/home/dejun.xdj/kvs-kernel/src/redis-server /home/dejun.xdj/local/redis/conf/redis_7071.conf *:1071(main+0x180)[0x405db0]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x3d4ac1ecdd]
/home/dejun.xdj/kvs-kernel/src/redis-server /home/dejun.xdj/local/redis/conf/redis_7071.conf *:1071[0x4055e9]
[19179] 12 Apr 18:47:42.599 # --- INFO OUTPUT
...
...
[19179] 12 Apr 18:47:42.599 # --- CLIENT LIST OUTPUT
[19179] 12 Apr 18:47:42.599 # id=2 addr=127.0.0.1:30494 fd=5 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=debug read=0 write=0 type=admin next_opid=-1

[19179] 12 Apr 18:47:42.599 # --- CURRENT CLIENT INFO
[19179] 12 Apr 18:47:42.599 # client: id=2 addr=127.0.0.1:30494 fd=5 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=debug read=0 write=0 type=admin next_opid=-1
[19179] 12 Apr 18:47:42.600 # argv[0]: 'debug'
[19179] 12 Apr 18:47:42.600 # argv[1]: 'segfault'
[19179] 12 Apr 18:47:42.600 # --- REGISTERS
...
...
=== REDIS BUG REPORT END. Make sure to include from START to END. ===

       Please report the crash by opening an issue on github:

           http://github.com/antirez/redis/issues

  Suspect RAM error? Use redis-server --test-memory to verify it.

Crash Report主要包括4部分,

  • STACK TRACE,崩溃时的调用栈信息
  • INFO OUTPUT,崩溃时的Redis info命令输出
  • CLIENT OUTPUT,包括崩溃时的CURRENT CLIENT,这个可以看到崩溃时客户端执行的命令
  • REGISTERS,寄存器信息

其中对于调试最有帮助的就是STACK TRACE信息了,我们直接以上面的Crash Report来说明一下如何调试。

调试

Redis提供了debug segfault命令用于调试,我们直接给Redis发送这个命令,就可以在日志中生成类似于上面的崩溃报告(请不要在生产环境使用这个命令!!!)。

实际调试之前先说明一下,如果编译时没有加上-g选项,可执行文件中没有调试符号信息,是无法进行后面的调试的,考虑到性能的影响很小,Redis默认编译是带有-g选项的。

上面的STACK TRACE信息直接告诉我们了,出core的点在libredis-server.so中,简单分析可以知道是在执行debugCommand时出现段错误,函数后面的+号带的地址是函数内的代码偏移,我们只要知道函数的起始地址就可以获取出core的函数内代码地址了,进而可以通过addr2line获取地址对应的具体的源文件名和行号。

通过nm工具获取函数起始地址,

$nm -l /home/dejun.xdj/kvs-kernel/src/libredis-server.so  | grep debugCommand
000000000006d920 T debugCommand /home/dejun.xdj/kvs-kernel/src/debug.c:255
000000000007f3f0 T pfdebugCommand       /home/dejun.xdj/kvs-kernel/src/hyperloglog.c:1455

我们可以看到debugCommand的起始地址是0x6d920(十六进制),加上偏移0x1b0,可以知道出core的具体地址是0x6dad0,那么我们就可以很方便的获取到具体的行号了,

$addr2line -e /home/dejun.xdj/kvs-kernel/src/libredis-server.so 0x6dad0
/home/dejun.xdj/kvs-kernel/src/debug.c:304

参考源文件我们可以发现debug.c的304行存在非法地址访问,

*((char*)-1) = 'x';

总结

以上只是为了说明调试流程,举的一个简单例子,有时候定位了出core的点,可能还需要更为细致的分析,结合info输出和client输出。在没有core文件的场景下,Crash Report确实能够提供很大的帮助,上面的流程,有兴趣的同学可以直接做成一个脚本,直接分析日志,自动化的获取出core点的信息。

参考:http://antirez.com/news/43

诚聘英才:阿里云-技术专家-KVstore

时间: 2024-07-31 15:18:56

Redis崩溃调试的相关文章

iOS崩溃调试

在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题.简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的. 现在网上有很多关于解析崩溃信息的博客,但是大多质量参差不齐,或者有些细节没有注意到.今天写一篇博客总结一下我对崩溃调试的使用和技巧,如果有哪些错误或遗漏,还请指点,谢谢! 获取崩溃信息 在iOS中获取崩溃信息的方式有很多,比较常见的是使用友盟.百度等第三方分析工具,或者自己收集崩溃信息并上传公司服务器.下面列举一些我们

iOS中崩溃调试的使用和技巧总结 韩俊强的博客

 每日更新关注:http://weibo.com/hanjunqiang  新浪微博 在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题.简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的. 现在网上有很多关于解析崩溃信息的博客,但是大多质量参差不齐,或者有些细节没有注意到.今天写一篇博客总结一下我对崩溃调试的使用和技巧,如果有哪些错误或遗漏,还请指点,谢谢! 获取崩溃信息 在iOS中获取崩溃信息的方式有很多,比较常见的是

iOS崩溃调试的使用和技巧总结

 每日更新关注:http://weibo.com/hanjunqiang  新浪微博 在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题.简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的. 现在网上有很多关于解析崩溃信息的博客,但是大多质量参差不齐,或者有些细节没有注意到.今天写一篇博客总结一下我对崩溃调试的使用和技巧,如果有哪些错误或遗漏,还请指点,谢谢! 获取崩溃信息 在iOS中获取崩溃信息的方式有很多,比较常见的是

wince 崩溃 调试-wince5.0长时间老化程序崩溃,能否获取崩溃信息

问题描述 wince5.0长时间老化程序崩溃,能否获取崩溃信息 小弟主要是做android,最近接手wince5.0上面做的一个用于老化板子的程序,包含了产品的各个功能,比如指纹.rfid.串口.gprs等,遇到的问题是长时间跑,会不定期的崩溃,少则1个多小时,多则一两天.用codesnitch监测内存分配和释放的情况,已经排除了内存泄露的可能.由于是多线程,单步debug也很难重现问题,不知有没有其他调试这种崩溃的方法,先谢过各位了!

《Redis官方文档》Redis调试指南

原文链接      译者:Adeline Redis开发过程中十分注重其稳定性:我们尽一切努力来保证每一个版本的稳定,不出现突然崩溃等情况.但是即使在我们百分百的努力下,仍然没办法保证百分百的无bug. Redis出现崩溃时,会生成一个详细的报告来描述当时的情景,但是有时候只看报告还不够,而且Redis的核心开发团队可能也没办法独立重现你出现崩溃时候的场景:在这种情况下,我们需要用户能够重现这个情景来帮助我们. 这个指南讲解了如何使用GDB来获得Redis开发者可能用到的信息. GDB是什么?

Redis开发与运维. 3.2 Redis Shell

3.2 Redis Shell Redis提供了redis-cli.redis-server.redis-benchmark等Shell工具.它们虽然比较简单,但是麻雀虽小五脏俱全,有时可以很巧妙地解决一些问题. 3.2.1 redis-cli详解 第1章曾介绍过redis-cli,包括-h.-p参数,但是除了这些参数,还有很多有用的参数,要了解redis-cli的全部参数,可以执行redis-cli -help命令来进行查看,下面将对一些重要参数的含义以及使用场景进行说明. 1.?-r -r(

Redis的缓存策略和主键失效机制

作为缓存系统都要定期清理无效数据,就需要一个主键失效和淘汰策略. >>EXPIRE主键失效机制 在Redis当中,有生存期的key被称为volatile, 在创建缓存时,要为给定的key设置生存期,当key过期的时候(生存期为0),它可能会被删除. (1)影响生存时间的一些操作 生存时间可以通过使用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令覆盖原来的数据, 也就是说,修改key对应的value和使用另外相同的key和value来覆盖以后,当前数据的生存时间

Redis性能问题排查解决手册(七)

阅读目录: 性能相关的数据指标 内存使用率used_memory 命令处理总数total_commands_processed 延迟时间 内存碎片率 回收key 总结 性能相关的数据指标 通过Redis-cli命令行界面访问到Redis服务器,然后使用info命令获取所有与Redis服务相关的信息.通过这些信息来分析文章后面提到的一些性能指标. info命令输出的数据可分为10个类别,分别是: server clients memory persistence stats replication

Redis开发与运维. 1.6 Redis重大版本

1.6 Redis重大版本 Redis借鉴了Linux操作系统对于版本号的命名规则:版本号第二位如果是奇数,则为非稳定版本(例如2.7.2.9.3.1),如果是偶数,则为稳定版本(例如2.6.2.8.3.0.3.2).当前奇数版本就是下一个稳定版本的开发版本,例如2.9版本是3.0版本的开发版本.所以我们在生产环境通常选取偶数版本的Redis,如果对于某些新的特性想提前了解和使用,可以选择最新的奇数版本. 介绍一门技术的版本是很多技术图书的必备内容,通常读者容易忽略,但随着你对这门技术深入学习后