ESTABLISHED 상태 인 socket 에는 프로 세 스 정보 가 없습니다.

6026 단어
'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 에서 보 낸 요청 을 볼 수 있 습 니 다. 커 널 프로 토 콜 스 택 은 이미 받 아 들 였 지만 해당 하 는 링크 에 작은 세부 사항 이 있 습 니 다. 그것 은 바로 establishe 상태의 링크 입 니 다. 프로 세 스 번 호 를 찾 을 수 없습니다.
나 는 이전에 netstat 의 소스 코드 를 본 적 이 없다. 다만 strace 를 통 해 netstat 가 / proc / net / tcp (또는 / proc / net / tcp 6) 를 읽 고 링크 정 보 를 얻 는 것 을 대충 알 고 있 을 뿐이다.
 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_위의 socket 을 분리 하 는 fd 는 31915. 읽 은 후에 해당 하 는 프로 세 스 와 프로 세 스 이름 을 포맷 한 다음 socket 의 inode 와 map 에 존재 합 니 다.
모든 / proc 의 프로 세 스 를 옮 겨 다 니 며 이 과정 이 너무 무 겁 습 니 다. map 가 존재 한 후 읽 기 를 통 해 /proc / net / tcp 에서 요구 에 부 합 된 socket 은 fd 의 숫자 를 맵 에 색인 하여 프로 세 스 번 호 를 찾 은 다음 인쇄 합 니 다.
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", ' ' , "
", 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=) 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", ' ' , "
", 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", ' ' , "
" (gdb) p inode $47 = 31915  

이 관련 원 리 를 알 게 된 후에 기본적으로 확인 할 수 있 습 니 다. 우리 응용 프로 세 스 는 제때에 accept 하지 않 았 습 니 다.
알 고 있 습 니 다. accept 의 호출 원 리 는 accept () - > sys 입 니 다.accept4() -> inet_accept() -> inet_csk_accept()
이 를 통 해 알 수 있 듯 이 accept 역할 은 이미 연 결 된 socket (즉 세 번 의 악 수 를 거 쳤 다) 으로 돌아 가 는 것 입 니 다. 이 과정 은 협의 스 택 과 비동기 적 입 니 다. accept () 는 직접 세 번 의 악수 과정 을 처리 하지 않 고 icsk 만 감청 합 니 다.accept_quue 대기 열, socket 이 세 번 악 수 를 하면 icsk 에 추 가 됩 니 다.accept_quue 에서 accept 가 해 야 할 일 은 대기 열 에 socket 을 삽입 한 다음 에 깨 워 서 이 socket 으로 돌아 가 는 것 입 니 다.세 번 악 수 를 하 는 과정 은 완전히 협의 창고 자체 가 완성 한 것 이다.
그래서 우 리 는 위의, 이미 established 된 링크 를 보 았 습 니 다. 업무 프로 세 스 가 제때에 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 호출 전에 established 상태 에 있 는 socket 의 inode 도 프로 세 스 와 관련 이 없습니다.
 
다음으로 전송:https://www.cnblogs.com/10087622blog/p/9362474.html

좋은 웹페이지 즐겨찾기