[deadlock]死锁导致的设备登录无响应问题

server/2024/10/24 9:55:53/

[deadlock]死锁导致的设备登录无响应问题

  • 一、问题现象
  • 二、初步观察
  • 三、继续深挖
    • 查看netlink相关信息
    • 查看warnd进程栈
  • 四、再接再厉
    • 查看warnd 用户栈
  • 后记

一、问题现象

实验室一台压力测试设备突然无法登录,无论web页面,ssh或者telnet登录,都是输入用户名密码后卡在哪里,无法进入管理页面。
如果这样子的话,根本无法调试。幸运的是,有个之前就打开的shell窗口可以使用。这给我们分析调试提供了方便。

二、初步观察

在shell中查看现存和hang住的命令行进程,看看有什么线索。

/var/log# ps | grep cli2812 root      720m S    cli admin 1 admin telnet(10.10.20.11)
15126 root      720m S    cli admin 1 admin telnet(10.10.20.11)
15264 root      720m S    cli admin 0 admin console
21947 root     16448 S    grep cli

这里有3个cli进程,有除了2812是我们当前在使用的,剩下两个都是无响应的。查看进程的内核栈信息。

/var/log# cat /proc/15264/stack
[<ffffffff8080a819>] netlink_attachskb+0x189/0x1d0
[<ffffffff8080a991>] netlink_unicast+0xa1/0x1f0
[<ffffffff8080ad81>] netlink_sendmsg+0x1c1/0x3e0
[<ffffffff80799b8a>] sock_sendmsg+0x1a/0x30
[<ffffffff8079a376>] ___sys_sendmsg+0x1e6/0x200
[<ffffffff8079b404>] SyS_sendmsg+0x44/0x80
[<ffffffff802016d5>] do_syscall_64+0x75/0x2c0
[<ffffffff80c0008d>] entry_SYSCALL_64_after_hwframe+0x59/0xbe
[<ffffffffffffffff>] 0xffffffffffffffff
/var/log# cat /proc/15126/stack
[<ffffffff8080a819>] netlink_attachskb+0x189/0x1d0
[<ffffffff8080a991>] netlink_unicast+0xa1/0x1f0
[<ffffffff8080ad81>] netlink_sendmsg+0x1c1/0x3e0
[<ffffffff80799b8a>] sock_sendmsg+0x1a/0x30
[<ffffffff8079a376>] ___sys_sendmsg+0x1e6/0x200
[<ffffffff8079b404>] SyS_sendmsg+0x44/0x80
[<ffffffff802016d5>] do_syscall_64+0x75/0x2c0
[<ffffffff80c0008d>] entry_SYSCALL_64_after_hwframe+0x59/0xbe
[<ffffffffffffffff>] 0xffffffffffffffff
/var/log# cat /proc/2812/stack
[<ffffffff80255f6a>] do_wait+0x1aa/0x210
[<ffffffff802570f7>] kernel_wait4+0x97/0x120
[<ffffffff802571ef>] SyS_wait4+0x6f/0x80
[<ffffffff802016d5>] do_syscall_64+0x75/0x2c0
[<ffffffff80c0008d>] entry_SYSCALL_64_after_hwframe+0x59/0xbe
[<ffffffffffffffff>] 0xffffffffffffffff

可以发现 15126和15264进程都卡在了 netlink发送等待上。怀疑netlink socket收包队列有积压,导致发送端处于等待发送状态。

三、继续深挖

查看netlink相关信息

/var/log# cat /proc/net/netlink 
sk       Eth Pid    Groups   Rmem     Wmem     Dump     Locks     Drops     Inode
ffff88880b2cb000 0   2851   00000000 0        0        0 2        0        12002   
ffff888806d6e800 0   2707076566 00000000 0        0        0 2        0        12784   
ffff888806d6a000 0   3780   00000551 0        0        0 2        0        12810   
ffff88885a980000 0   0      00000000 0        0        0 2        0        3       
ffff88880a1b6000 0   2825818928 00000111 0        0        0 2        0        20919   
ffff888806d6d800 0   3498   00000111 0        0        0 2        0        12783   
ffff88880c210000 0   3410172620 00000000 0        0        0 2        0        12811   
ffff88880b2cb800 0   2855   00000001 0        0        0 2        0        11851   
ffff88880a5bf800 15  10000038 00000000 33557184 0        0 27       0        1652  --问题socket
//省略部分无关socket

发现socket ffff88880a5bf800 存在大量积压,基本确认是积压导致。

根据Eth 15 和Pid 10000038 ,对照代码发现是发送和接收告警信息的socket,负责接收处理的进程是warnd。

查看warnd进程栈

/var/log# ps | grep warnd2849 root     2325m S    /bin/warnd
22135 root     16448 S    grep warnd
/var/log# cat /proc/2849/stack
[<ffffffff802bfe03>] futex_wait_queue_me+0xc3/0x120
[<ffffffff802c01e2>] futex_wait+0x102/0x230
[<ffffffff802c275e>] do_futex+0x14e/0xc30
[<ffffffff802c32ab>] SyS_futex+0x6b/0x140
[<ffffffff802016d5>] do_syscall_64+0x75/0x2c0
[<ffffffff80c0008d>] entry_SYSCALL_64_a

发现warnd在等待futex 锁,是那个操作导致的呢,这就需要查看用户态的调用栈了。

四、再接再厉

查看warnd 用户栈

用gdb attach上warnd进程,查看当前栈

/var/log# gdb
GNU gdb (GDB) 11.2
Copyright (C) 2022 Free Software Foundation, Inc.
//省略无关部分
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) attach 2849
Attaching to process 2849
[New LWP 2945]
[New LWP 2946]
[New LWP 2947]
//省略无关部分
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
0x00007fcab97e4059 in ?? () from /lib/libc.so.6
(gdb) info threadId   Target Id                                 Frame 
* 1    Thread 0x7fcab8929800 (LWP 2849) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.62    Thread 0x7fcab8924640 (LWP 2945) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.63    Thread 0x7fcab8123640 (LWP 2946) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.64    Thread 0x7fcab7922640 (LWP 2947) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.6
//省略无关部分34   Thread 0x7fcaa802b640 (LWP 8217) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.635   Thread 0x7fcaa782a640 (LWP 8238) "warnd" 0x00007fcab9868add in sendmsg () from /lib/libc.so.636   Thread 0x7fcaa7029640 (LWP 8245) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.637   Thread 0x7fcaa611f640 (LWP 8260) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.638   Thread 0x7fcaa590d640 (LWP 8267) "warnd" 0x00007fcab97e4059 in ?? () from /lib/libc.so.639   Thread 0x7fcaa510c640 (LWP 8268) "warnd" 0x00007fcab9867196 in epoll_wait () from /lib/libc.so.6

除了线程35和39外,其他线程全部卡在相同的位置。

查看线程1,可以知道系统调用线程读写锁的写锁时因为得不到调度进入了休眠。那么这个锁被那个线程占有了呢?

(gdb) thread 1
[Switching to thread 1 (Thread 0x7fcab8929800 (LWP 2849))]
#0  0x00007fcab97e4059 in ?? () from /lib/libc.so.6
(gdb) bt full
#0  0x00007fcab97e4059 in ?? () from /lib/libc.so.6
No symbol table info available.
#1  0x00007fcab97ed4f1 in pthread_rwlock_wrlock () from /lib/libc.so.6
No symbol table info available.
#2  0x000000000040d5d3 in ?? ()
No symbol table info available.
#3  0x0000000000404ad9 in ?? ()
No symbol table info available.
#4  0x00007fcab978b1f7 in ?? () from /lib/libc.so.6
No symbol table info available.
#5  0x00007fcab978b2ac in __libc_start_main () from /lib/libc.so.6
No symbol table info available.
#6  0x0000000000404b01 in ?? ()
No symbol table info available.

我们再查看看35线程。通过查看代码发现,在sendmsg之前,线程已经持通过pthread_rwlock_wrlock 持有了写锁。也就是其他线程都在等待35线程释放写锁。那么35线程为什么不释放写锁呢?

  (gdb) thread 35
[Switching to thread 35 (Thread 0x7fcaa782a640 (LWP 8238))]
#0  0x00007fcab9868add in sendmsg () from /lib/libc.so.6
(gdb) bt full
#0  0x00007fcab9868add in sendmsg () from /lib/libc.so.6
No symbol table info available.
#1  0x00007fcab967f81d in fun_nl_sendto0 () from /lib/libfun_nl_ipc.so
No symbol table info available.
#2  0x00007fcab9b2a61a in send_warn () from /lib/libwarnapi.so
No symbol table info available.
#3  0x00000000004159d0 in ?? ()
No symbol table info available.
#4  0x0000000000415dbc in ?? ()
No symbol table info available.
#5  0x000000000040c9c5 in ?? ()
No symbol table info available.
#6  0x00007fcab9b62067 in ?? () from /lib/libevent.so
No symbol table info available.
#7  0x00007fcab9b62314 in ?? () from /lib/libevent.so
No symbol table info available.
#8  0x00007fcab9b62568 in ?? () from /lib/libevent.so
No symbol table info available.
#9  0x000000000040ca8e in ?? ()
No symbol table info available.
#10 0x00007fcab97e731a in ?? () from /lib/libc.so.6
No symbol table info available.
#11 0x00007fcab9866db0 in clone () from /lib/libc.so.6

查代码发现35线程sendmsg就是向 已经积压的netlink socket 发送warn消息。因为netlink socket积压,导致35线程进入休眠等待。

分析到这里,基本逻辑差不多通顺了。

  1. 压力测试导致netlink socket积压
  2. 35线程获取写锁后,向netlink socket发送消息。因为积压导致休眠。
  3. 其他线程包括netlink socket消息接受处理的线程因为获取不到写锁,导致休眠。
  4. 此时:线程35发送消息持有写锁,等待netlink socket buffer空闲。处理netlink socket消息的线程,等待写锁。–根因
  5. cli命令行进程会向warnd发送netlink消息,因为netlink socket消息积压(消息没有得到及时处理),导致发送进程进入等待休眠。

后记

warnd进程主要处理其他进程发来的warn消息,自己也发送warn消息。在锁的处理上不够完善,导致压力测试下,socket接收队列打满后,形成了死锁


http://www.ppmy.cn/server/134412.html

相关文章

跳表(Skip List)介绍

跳表&#xff08;Skip List&#xff09;介绍 跳表是一种用于有序数据的高效数据结构&#xff0c;结合了链表和分层结构的优点&#xff0c;主要用于快速查找、插入和删除操作。跳表由William Pugh在1989年提出&#xff0c;作为一种简单而有效的替代平衡树的数据结构&#xff0c…

oracle 数据库 迁移到 pgsql,防止出现重大bug 回滚到 oracle,需要同步数据如何处理?

oracle 数据库 迁移到 pgsql&#xff0c;防止出现重大bug 回滚到 oracle&#xff0c;需要同步数据如何处理&#xff1f; 用工具 &#xff0c; 出现大问题&#xff0c; 直接把pgsql 数据库同步到新的oracle 数据库

深入理解 WPF 数据绑定机制

一、引言 在现代软件开发中&#xff0c;创建具有良好用户体验的图形用户界面&#xff08;GUI&#xff09;至关重要。WPF 作为一种先进的 GUI 技术&#xff0c;提供了强大的数据绑定机制&#xff0c;使得开发人员能够轻松地将数据与用户界面元素进行关联&#xff0c;实现数据的…

Spark广播变量(类似小表广播)

广播变量&#xff1a; 举例&#xff1a;取前十的学生信息&#xff0c;处理学生分数信息得到前十学生的学号的数组&#xff0c;通过广播将这个变量广播出去 代码展示如下&#xff1a; import org.apache.spark.broadcast.Broadcast import org.apache.spark.rdd.RDD import o…

AUTOSAR_EXP_ARAComAPI的6章笔记(3)

☞返回总目录 相关总结&#xff1a;AutoSar AP CM实例说明符的使用方法的总结 6.3 在多绑定上下文中的使用 以下部分修改了在 6.2.1 中展示的示例&#xff0c;描述了如何在应用程序和实例清单中为单个 PPortPrototype 定义多个网络绑定&#xff0c;而无需更改自适应应用程序…

MongoDB快速入门

MongoDB 概念 什么是 MongoDB MongoDB 是在2007年由DoubleClick公司的几位核心成员开发出的一款分布式文档数据库&#xff0c;由C语言编写。 目的是为了解决数据大量增长的时候系统的可扩展性和敏捷性。MongoDB要比传统的关系型数据库简单很多。 在MongoDB中数据主要的组织…

深入解析 Jenkins 自动化任务链:三大方法实现任务间依赖与状态控制

文章目录 前言1. 使用 “Build Trigger”&#xff08;构建触发器&#xff09;2. 使用 Jenkins Pipeline 实现任务触发3. 使用 Jenkins 的 “Parameterized Trigger Plugin” 插件例子1&#xff1a;任务 A 成功后自动执行任务 B例子2&#xff1a;任务 A 成功后自动执行 Pipeline…

基于SpringBoot+Vue+uniapp的C语言在线评测系统的详细设计和实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…