处于ESTABLISHED 状态的socket 却没有进程信息
接《一次docker中的nginx进程响应慢问题定位记录》
在排查这个问题的时候,我先使用netstat 去查看,看到底是内核协议栈的连接请求没给到进程,还是进程accept链路慢了,或者recv数据慢了,记录如下:
- netstat -anpl |grep -i 57372
- tcp 0 0 127.0.0.1:57372 127.0.0.1:7010 ESTABLISHED 15044/curl
- tcp 86 0 127.0.0.1:7010 127.0.0.1:57372 ESTABLISHED -
可以看到,curl发送的请求,内核协议栈是已经接受了,但是对应的链路有个小小的细节,那就是establish状态的链接,进程号查不到。
我以前没有看过netstat的源码,只是通过strace大概知道netstat是去读取 /proc/net/tcp (或者/proc/net/tcp6) 来获取链接信息的,
- cat /proc/net/tcp
- sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
- 0: 00000000:18A7 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31915 1 ffff88057f2b9000 100 0 0 10 0
- 1: 0100007F:158E 00000000:0000 0A 00000000:00000000 00:00000000 00000000 2000 0 24924 1 ffff8800acf58000 100 0 0 10 0
- 2: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 9479 1 ffff880182c80000 100 0 0 10 0
- 3: 00000000:18B0 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31914 1 ffff88057f2b8800 100 0 0 10 0
- 4: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 17065 1 ffff88056d3d8000 100 0 0 10 0
- 5: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 28681 1 ffff8802b8bd8000 100 0 0 10 0
- 6: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 26547 1 ffff88057f2b8000 100 0 0 10 0
- 7: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 30024 1 ffff88058e678000 100 0 0 10 0
但是netstat -anpl怎么关联最后一列的进程信息不清楚,下载一份netstat源码,发现它是在循环遍历/proc下的进程,然后读取/proc/进程/fd/xx ,
- (gdb) p readlink(line, lname, sizeof(lname) - 1)
- $34 = 14
- (gdb) p lname
- $35 = "socket:[31915]\000erfd]\000d\000\000\000\000\000\000\000"
然后通过调用extract_type_1_socket_inode 之类的来隔离出上面的 socket 的fd为 31915 ,读取之后,将对应的进程和进程名格式化,然后和socket的inode 存在一个map中。
遍历所有的/proc下的进程,这个过程太重,存在map之后,通过读取 /proc/net/tcp 中符合要求的socket,将其fd那一列的数字作为索引到 map 中去查找进程号,然后打印出来。
- Breakpoint 2, finish_this_one (uid=0, inode=31915, timers=0x7fffffffc010 "") at netstat.c:593
- 593 {
- (gdb) bt
- #0 finish_this_one (uid=0, inode=31915, timers=0x7fffffffc010 "") at netstat.c:593
- #1 0x0000000000406eb7 in tcp_do_one (lnr=lnr@entry=1,
- line=line@entry=0x7fffffffc190 " 0: 00000000:18A7 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31915 1 ffff88057f2b9000 100 0 0 10 0", ' ' <repeats 21 times>, "\n", prot=prot@entry=0x41413f "tcp") at netstat.c:1056
- #2 0x000000000040728f in tcp_info () at netstat.c:1061
- #3 0x0000000000402956 in main (argc=2, argv=<optimized out>) at netstat.c:2172
- (gdb) fr 1
- #1 0x0000000000406eb7 in tcp_do_one (lnr=lnr@entry=1,
- line=line@entry=0x7fffffffc190 " 0: 00000000:18A7 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31915 1 ffff88057f2b9000 100 0 0 10 0", ' ' <repeats 21 times>, "\n", prot=prot@entry=0x41413f "tcp") at netstat.c:1056
- 1056 finish_this_one(uid,inode,timers);
- (gdb) p line
- $46 = 0x7fffffffc190 " 0: 00000000:18A7 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 31915 1 ffff88057f2 b9000 100 0 0 10 0", ' ' <repeats 21 times>, "\n"
- (gdb) p inode
- $47 = 31915
知道了这个关联的原理之后,基本就可以确定,我们应用进程 并没有及时来 accept 。
我们知道,accept的调用原理是:accept() -> sys_accept4() -> inet_accept() -> inet_csk_accept()
可以看到,accept作用是返回一个已经建立连接的socket(即经过了三次握手),这个过程和协议栈是异步的,accept()并不亲自去处理三次握手过程,而只是监听icsk_accept_queue队列,当有socket经过了三次握手,它就会被加到icsk_accept_queue中,所以accept要做的就是等待队列中插入socket,然后被唤醒并返回这个socket。而三次握手的过程完全是协议栈本身去完成的。
所以我们看到了上面的,已经establish的链路,由于业务进程没有及时去accept 导致可以看到 没有进程关联的链路。
对于阻塞的socket,accept是一直等待的,则会在下面的 sk_state_change 中被唤醒。
- case TCP_SYN_RECV:
- if (!acceptable)
- return 1;
- /* Once we leave TCP_SYN_RECV, we no longer need req
- * so release it.
- */
- if (req) {
- synack_stamp = tcp_rsk(req)->snt_synack;
- tp->total_retrans = req->num_retrans;
- reqsk_fastopen_remove(sk, req, false);
- } else {
- synack_stamp = tp->lsndtime;
- /* Make sure socket is routed, for correct metrics. */
- icsk->icsk_af_ops->rebuild_header(sk);
- tcp_init_congestion_control(sk);
- tcp_mtup_init(sk);
- tp->copied_seq = tp->rcv_nxt;
- tcp_init_buffer_space(sk);
- }
- smp_mb();
- tcp_set_state(sk, TCP_ESTABLISHED);//设置为establish,注意这个时候,还没通知用户accept
- sk->sk_state_change(sk);//这个sk是新创建的sock,而不是listen的sk,唤醒等待在 sk->sk_wq 上的进程
而对于非阻塞的socket,则需要在poll之类的异步收请求函数中去调用对应listen socket 去 accept 这个连接。这个nginx没有及时去accept链路的原因是,调用的lua模块出现大的死循环。
结论:
1.不要使用netstat,太重,大家一定要使用ss替代。
2.在accept的调用之前,已经处于establish状态的socket的inode也是没有关联到进程的。
处于ESTABLISHED 状态的socket 却没有进程信息的更多相关文章
- 让SQL SERVER自动清理掉处于SLEEPING状态超过30分钟的进程(转)
原文地址:http://www.itpub.net/thread-809758-1-1.html use master go ) drop procedure [dbo].[p_killspid] G ...
- Linux 中进程有哪几种状态?在 ps 显示出来的信息中,分别用什么符号表示的?
(1)不可中断状态:进程处于睡眠状态,但是此刻进程是不可中断的.不可中断,指进程不响应异步信号. (2)暂停状态/跟踪状态:向进程发送一个 SIGSTOP 信号,它就会因响应该信号 而进入 TASK_ ...
- Linux 中进程有哪几种状态?在 ps 显示出来的信息中, 分别用什么符号表示的?
1.不可中断状态:进程处于睡眠状态,但是此刻进程是不可中断的.不可中断, 指进程不响应异步信号. 第 441 页 共 485 页2.暂停状态/跟踪状态:向进程发送一个 SIGSTOP 信号,它就会因响 ...
- [转贴] C++ 判断主机是否处于联网状态下
直接让本机访问一个网站,如果成功的话,就说明成功联网,没有访问成功,则说明没有联网!!! #include<iostream> #include <WINSOCK2.H> #p ...
- SQLServer无法删除登录名'***',因为该用户当前正处于登录状态解决方法
问题描述: sqlserver在删除登录名的时候提示删除失败 标题: Microsoft SQL Server Management Studio -------------------------- ...
- 无法删除登录名 '***',因为该用户当前正处于登录状态。 (Microsoft SQL Server,错误: 15434)
问题描述: 当删除数据库用户时,有时会得到这样的提示: 无法删除登录名 '***',因为该用户当前正处于登录状态. (Microsoft SQL Server,错误: 15434) 解决办法: 1.首 ...
- Windows 2008 - 由于管理员设置的策略,该磁盘处于脱机状态
http://blog.sina.com.cn/s/blog_59cc90640102x8m4.html 查看原文:https://www.bxl.me/9279.html准备使用云主机挂机的时候呢出 ...
- 虚拟机启动linux系统报错,此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态
在使用虚拟机启动linux的时候报错,如下: 已将该虚拟机配置为使用 64 位客户机操作系统.但是,无法执行 64 位操作. 此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态. ...
- Oracle 违反协议 OALL8 处于不一致状态
http://blog.sina.com.cn/s/blog_a45aac720100yu3h.html ERROR-util.JDBCExceptionReporter>: 违反协议ERROR ...
随机推荐
- CyclicBarrier循环屏障相关
简介 CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会 ...
- angular4+中的数据绑定
1,基本的属性绑定,下面的两种形式是一样的 2.dom属性和html属性 3.两者关系的进一步总结 4.dom属性绑定 5.html属性绑定
- windows 日志解决方法
1.sql server 2012 报错 MSSQLSERVER 服务无法使用当前配置的密码以 .\MSSQL_SF_A9JGSK 身份登录,错误原因如下: 此帐户的密码已过期. 要确保服务配置正确, ...
- vue事件深入
事件对象: @click="show($event)" ev.clientX---接收 事件冒泡: 阻止冒泡: 1. ev.cancelBubble=true; 2.@click. ...
- 3-自己动手写HashMap 增加哈希算法
public class HashMap { //存储元素数组 private Entry[] entry = null; //记录map个数 private int size; //构造器 publ ...
- javascript-关于赋值的那点事
var ary1=[3,4]; var ary2=ary1; ary2[0]=1; ary2=[6,5] console.log(ary1) console.log(ary2) 个人测试出的结果是:更 ...
- python学习之----导航树
findAll 函数通过标签的名称和属性来查找标签 .但是如果你需要通过标签在文档中的位 置来查找标签,该怎么办?这就是导航树(Navigating Trees)的作用.在第1 章里,我们 看过用单一 ...
- 图算法之——dijkstra算法
一.算法特点 目标:找出加权图中前往X的最短路径 适用于:无环有向加权图,且各边的权值为正 二.算法思路 三.算法示例演示 如下图,请找出结点v1到其他各个结点的最短路径: 首先创建一个字典(散列表) ...
- python补充3
一单例模式 类:具体相同特征的一类事物,类似于模板 单例:常用的软件设计模式,用于设计一个类中只有一个实例且易于外界访问,可以对实例的个数控制并节约系统资源 运用场景:比如某个服务器程序的配置信息,它 ...
- [Unity插件]Lua行为树(十二):行为树管理
之前运行的行为树,都是一颗总树,那么实际上会有很多的总树,因此需要对行为树进行管理. BTBehaviorManager.lua BTBehaviorManager = {}; local this ...