Redis崩溃调试

转载翻译,便于整理和归类,源文地址 https://blog.csdn.net/weixin_34290000/article/details/90587202
英文原文地址:http://antirez.com/news/43

背景

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 VS Code 中调试 Redis,可以使用以下步骤: 1. 安装 Redis 扩展:打开 VS Code,点击左侧的扩展图标,搜索并安装 Redis 扩展。该扩展提供了 Redis调试功能。 2. 配置调试器:在 VS Code 中打开要调试Redis 配置文件。在侧边栏的调试视图中,点击齿轮图标打开 `launch.json` 文件。 3. 添加调试配置:在 `launch.json` 文件中,添加一个新的调试配置。可以根据你的需要选择不同的启动配置,例如使用默认配置启动 Redis 或者指定自定义的配置文件。 下面是一个示例的 `launch.json` 文件配置: ```json { "version": "0.2.0", "configurations": [ { "type": "redis", "request": "launch", "name": "Launch Redis", "program": "redis-server", "args": ["--port", "6379"], "cwd": "${workspaceRoot}" } ] } ``` 在上述配置中,指定了 Redis 服务器的启动命令为 `redis-server`,并传递了参数 `--port 6379` 来指定端口号。`${workspaceRoot}` 表示当前工作区的根目录。 4. 启动调试:保存 `launch.json` 文件后,点击调试视图中的播放按钮,或者使用快捷键 F5 启动 Redis 调试会话。VS Code 将会启动 Redis 服务器,并连接到调试器。 5. 调试 Redis:一旦 Redis 服务器启动并连接到调试器,你可以在调试控制台中输入 Redis 命令,以及使用调试器提供的其他功能,如断点、查看变量等。 请注意,确保你已经正确安装了 Redis 并配置了正确的路径和参数。此外,调试 Redis 时要小心,避免在生产环境中进行调试操作,以免造成数据丢失或其他损坏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值