TCP socket SYN 대기 열과 Accept 대기 열의 차이 원리 분석

6333 단어 TCPsocketSYNAccept

우선"LISTENING"상태 에 있 는 TCP socket 에는 두 개의 독립 된 대기 열 이 있다 는 것 을 알 아야 합 니 다.
  • SYN 대기 열(SYN Queue)
  • Accept 대기 열(Accept Queue)
  • 이 두 용 어 는 때때로"reqsk"라 고도 불 린 다.quue","ACK backlog","listen backlog",심지어"TCP backlog".그러나 이 글 에서 우 리 는 헷 갈 리 지 않도록 위의 두 가지 용 어 를 사용한다.
    SYN 대기 열
    SYN 대기 열 은 SYN 패 키 지 를 받 은 연결(커 널 코드 에 대응 하 는 구조 체:struct inet_request_sock을 저장 합 니 다.SYN+ACK 가방 에 답장 하고 ACK 가방 을 받 지 못 했 을 때 시간 이 초 과 될 때 까지 다시 전달 하 는 것 이 직책 이다.Linux 에서 재 전송 횟수 는 다음 과 같 습 니 다.
    $ sysctl net.ipv4.tcp_synack_retries
    net.ipv4.tcp_synack_retries = 5
    문서 에서tcp_synack_retries에 대한 설명 은 다음 과 같다.
     tcp_synack_retries-int 정형
     수 동적 TCP 연결 에 대해 SYNACKs 를 재 전송 하 는 횟수 입 니 다.이 값 은 255 를 초과 할 수 없다.
     기본 값 은 5 입 니 다.초기 RTO 가 1 초 라면 마지막 리 셋 은 31 초 입 니 다.
     대응 하 는 마지막 시간 초 과 는 63 초 후 였 다.
    SYN+ACK 를 보 낸 후 SYN 대기 열 은 클 라 이언 트 에서 보 내 는 ACK 가방(즉 세 번 악수 하 는 마지막 가방)을 기다 리 고 있 습 니 다.ACK 패 키 지 를 받 았 을 때 먼저 해당 하 는 SYN 대기 열 을 찾 은 다음 해당 하 는 SYN 대기 열 에서 관련 데이터 가 일치 하 는 지 확인 합 니 다.일치 하면 커 널 은 이 연결 과 관련 된 데 이 터 를 SYN 대기 열 에서 제거 하고 완전한 연결(커 널 코드 에 대응 하 는 구조 체:struct inet_sock을 만 들 고 이 연결 을 Accept 대기 열 에 추가 합 니 다.
    수락 대기 열
    Accept 대기 열 에 저 장 된 것 은 연결 이 되 어 있 습 니 다.즉,상위 프로그램 에서 가 져 갈 연결 을 기다 리 는 것 입 니 다.프로 세 스 가 accept()를 호출 하면 이 socket 은 대기 열 에서 꺼 내 상위 프로그램 에 전 달 됩 니 다.
    이것 이 바로 Linux 가 SYN 가방 을 처리 하 는 간단 한 설명 이다.참고 로 socket 이 TCP 를 열 었 을 때DEFER_ACCEPT 와 TCPFASTOPEN 시 작업 방식 이 조금씩 다 를 것 이 므 로 본 고 는 소개 하지 않 겠 습 니 다.
    대기 열 크기 제한
    응용 프로그램 은 시스템 호출 listen(2)을 통 해 backlog 인 자 를 입력 하여 SYN 대기 열과 Accept 대기 열의 최대 크기 를 설정 합 니 다.예 를 들 어 SYN 대기 열과 Accept 대기 열의 최대 크기 를 1024 로 설정 합 니 다.
    listen(sfd, 1024)
    4.3 버 전의 커 널 에 서 는 SYN 대기 열의 크기 를 다른 방식 으로 계산 합 니 다.
    SYN 대기 열의 최대 크기 는 이전에 net.ipv4.tcp 를 사 용 했 습 니 다.max_syn_backlog 로 설정 하지만 이 제 는 사용 하지 않 습 니 다.현재 net.core.somaxconn 으로 SYN 대기 열과 Accept 대기 열의 최대 크기 를 동시에 표시 합 니 다.서버 에서 16k 로 설정 합 니 다.
    $ sysctl net.core.somaxconn
    net.core.somaxconn = 16384
    위의 이 정 보 를 알 게 되면 대기 열 설정 이 얼마나 적합 한 지 물 어 볼 수 있 습 니 다.대기 열 설정 이 얼마나 적합 합 니까?
    정 답 은 상황 을 보 는 것 이다.대부분의 TCP 서비스 에 있어 서 이것 은 그다지 중요 하지 않다.예 를 들 어 Go 언어 1.11 버 전 전에는 대기 열 크기 를 설정 하 는 방법 을 제공 하지 않 았 다.
    그럼 에 도 불구 하고 합 리 적 인 이유 가 있 습 니 다.대열 의 크기 를 늘 려 야 합 니 다.
  • 연결 을 만 드 는 요청 속도 가 확실히 클 때 고성능 서비스 에 도 SYN 대기 열 을 크게 설정 해 야 할 수 있 습 니 다.
  • SYN 대기 열의 크기 는 다시 말 하면 ACK 패키지 의 연결 수 를 기다 리 는 것 이다.즉,클 라 이언 트 와 의 평균 왕복 시간 이 클 수록 SYN 대기 열 에 쌓 인 연결 이 많아 지 는 것 이다.대부분의 클 라 이언 트 가 서버 에서 멀리 떨 어 진 장면,예 를 들 어 왕복 시간 이 몇 백 밀리초 이상 이면 대기 열 크기 를 크게 설정 할 수 있 습 니 다.
  • TCP_DEFER_ACCEPT 옵션 이 열 리 면 socket 이 SYN-RECV 상태 에서 더 오래 유 지 됩 니 다.즉,SYN 대기 열 에 있 는 시간 을 늘 립 니 다.
  • 그러나 backlog 를 너무 크게 설정 하 는 것 도 좋 지 않 은 영향 을 미 칠 수 있 습 니 다.SYN 대기 열 에 있 는 모든 슬롯 은 메모 리 를 사용 해 야 합 니 다.SYN Flood 공격 을 당 했 을 때 우 리 는 이러한 공격 을 하 는 가방 에 자원 을 낭비 할 필요 가 없다.SYN 대기 열의 inetrequest_sock 구조 체 는 4.14 커 널 에서 각각 256 바이트 의 메모 리 를 차지 합 니 다.
    Liux 에서 SYN 대기 열의 현재 상 태 를 보 려 면 ss 명령 을 사용 하여 SYN-RECV 상태의 socket 을 조회 할 수 있 습 니 다.예 를 들 어 다음 과 같은 실행 결 과 는 80 포트 를 나타 내 는 SYN 대기 열 에 현재 119 개의 요소 가 있 고 443 포트 는 78 이다.
     $ ss -n state syn-recv sport = :80 | wc -l
     119
     $ ss -n state syn-recv sport = :443 | wc -l
     78
    프로그램 호출 accept()가 빠 르 지 않 으 면?또한 우리 의 SystemTap 스 크 립 트 를 통 해 이 데 이 터 를 관찰 할 수 있 습 니 다.resq.stp

    프로그램 호출 accept()가 부족 하면 무슨 일이 일어 날 까요?
  • 후속 수령 한 SYN 가방 은 SYN 대기 열 에 처리 되 지 않 습 니 다
  • 후속 으로 받 은(연결 을 위 한)ACK 패 키 지 는 SYN 대기 열 에 처리 되 지 않 습 니 다
  • TcpExtListenOverflows / LINUX_MIB_LISTENOVERFLOWS 계수 증가
  • TcpExtListenDrops / LINUX_MIB_LISTENDROPS 계수 증가
  • 이러한 상황 이 발생 했 을 때,우 리 는 프로그램의 처리 성능 이 잠시 후에 정상 으로 회복 되 고 클 라 이언 트 가 서버 에 버 려 진 가방 을 다시 보 낼 수 있 기 를 희망 할 수 밖 에 없습니다.
    커 널 의 이런 표현 은 대부분의 서비스 에 있어 서 받 아들 일 수 있다.참고 로 net.ipv4.tcp 조정 을 통 해abort_on_overflow 라 는 전역 매개 변 수 는 이러한 표현 을 수정 하지만 이 매개 변 수 를 바 꾸 지 않 는 것 이 좋 습 니 다.
    nstat 의 수 를 보고 Accept 대기 열 이 넘 치 는 상 태 를 관찰 할 수 있 습 니 다:
     $ nstat -az TcpExtListenDrops
     TcpExtListenDrops 49199 0.0
    하지만 이 는 전반적인 계산 이다.관찰 해 보면 직관 적 이지 못 하 다.예 를 들 어 가끔 우 리 는 그것 이 증가 하고 있 는 것 을 관찰 하지만 모든 서비스 프로그램 이 정상 적 으로 보인다.이 때 우 리 는 ss 명령 을 사용 하여 단일 감청 포트 의 Accept 대기 열 크기 를 관찰 할 수 있 습 니 다.
     $ ss -plnt sport = :6443|cat
     State Recv-Q Send-Q Local Address:Port Peer Address:Port
     LISTEN 0 1024 *:6443 *:*
    Recv-Q 열 은 Accept 대기 열 에 있 는 socket 수 를 표시 합 니 다.Send-Q 는 대기 열의 최대 크기 를 표시 합 니 다.위의 예 에서 우 리 는 프로그램 accept()의 socket 이 없 는 것 을 발 견 했 지만,Listen Drops 계수 가 증가 하고 있 는 것 을 발견 했다.
    이것 은 우리 의 프로그램 이 영구적 으로 처리 하지 않 는 것 이 아니 라 주기 적 으로 잠시 멈 춰 서 새로운 연결 을 처리 하지 않 기 때 문 입 니 다.시간 이 지나 면 프로그램 이 다시 정상 으로 돌 아 왔 습 니 다.이러한 상황 에서 ss 명령 으로 는 이러한 현상 을 관찰 하기 어렵 기 때문에 우 리 는 하나의SystemTap 스 크 립 트를 썼 다.이것 은 커 널 에 훅 을 넣 고 버 려 진 SYN 가방 을 인쇄 할 것 이다.
    
    $ sudo stap -v acceptq.stp
    time (us)    acceptq qmax local addr  remote_addr
    1495634198449075 1025  1024 0.0.0.0:6443 10.0.1.92:28585
    1495634198449253 1025  1024 0.0.0.0:6443 10.0.1.92:50500
    1495634198450062 1025  1024 0.0.0.0:6443 10.0.1.92:65434
    ...
    위의 조작 을 통 해 어떤 SYN 가방 이 Listen Drops 에 영향 을 받 았 는 지 관찰 할 수 있 습 니 다.그래서 우 리 는 어떤 프로그램 이 연결 을 잃 어 버 리 고 있 는 지 알 수 있다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기