sock
에 정의된 구조에는 sock.h
매우 유사해 보이는 두 가지 속성이 있습니다.
sk_wmem_alloc
, "커밋된 전송 대기열 바이트"로 정의됨sk_wmem_queued
, "지속적 대기열 크기"로 정의됨
나에게 이것은 sk_wmem_alloc
현재 전송 대기열에 할당된 메모리 양입니다. 그런데 은 무엇입니까 sk_wmem_queued
?
인용하다
- ~에 따르면이 StackOverflow 답변:
wmem_queued: 전송 큐에 대기 중이고 아직 전송되거나 승인되지 않은 소켓 전송 버퍼가 사용하는 메모리 양입니다.
- 그
ss
사람도 정의를 내렸지만 나에게는 그다지 이해가 되지 않았습니다. (IP 계층이 이것과 무슨 관련이 있는지 이해가 되지 않습니다.)wmem_allocation: 패킷 전송에 사용되는 메모리(레이어 3으로 전송) wmem_queued:패킷 전송을 위해 할당된 메모리(아직 레이어 3으로 전송되지 않음)
- 이미 누군가가 있어요LKML에서도 비슷한 질문이 나왔습니다., 하지만 답변이 없습니다.
- 매뉴얼
sock_diag(7)
페이지에는 다음 속성에 대한 자체 정의도 있습니다.SK_MEMINFO_WMEM_ALLOC: 전송 대기열에 있는 데이터의 양입니다. SK_MEMINFO_WMEM_QUEUED: TCP에 의해 대기 중이지만 아직 전송되지 않은 데이터의 양입니다.
이러한 정의는 모두 다르며 변형이 _alloc
어떻게 다른지 명확하게 설명하는 정의는 없습니다._queued
답변1
Linux 네트워킹 스택의 기고자인 Eric Dumazet에게 이메일을 보냈는데, 답변은 다음과 같습니다.
sk_wmem_alloc
skb가 대기열에 넣은 바이트 수를 추적합니다.뒤쪽에전송 스택: qdisc 계층 및 NIC TX 링 버퍼.아직 전송되지 않은 TCP 쓰기 큐에 1MB의 데이터가 있는 경우(cwnd 제한)
sk_wmem_queue
이는 약 1MB이지만sk_wmem_alloc
약 0입니다.
이 세 가지 유형의 큐(소켓 버퍼, qdisc 큐, 장치 큐)를 이해하는 데 아주 좋은 문서는 다음과 같습니다.이 글(꽤 깁니다). 즉, 소켓은 먼저 패킷을 qdisc 대기열에 직접 푸시한 다음 장치 대기열로 전달합니다. qdisc 대기열이 가득 차면 소켓은 자체 쓰기 대기열에서 데이터 버퍼링을 시작합니다.
네트워크 스택은 패킷을 큐잉 규칙에 직접 배치하거나 큐가 가득 찬 경우 패킷을 상위 계층(예: 소켓 버퍼)으로 다시 푸시합니다.
따라서 기본적으로는 소켓 버퍼( )에서 사용하는 메모리이지만 sk_wmem_queues
qdisc 및 장치 대기열의 패킷에서 사용하는 메모리입니다.sock.sk_write_queue
sk_wmem_alloc
답변2
요약: 매뉴얼 페이지를 믿으세요 :-). 그들은 데이터가 두 개의 서로 다른 위치에 대기할 수 있다고 말합니다. 따라서 총 메모리 사용량을 알고 싶다면 두 값을 더해야 합니다.
면책조항: 내 주장은 정보가 풍부한 출처에서 나온 것이지만, 그렇지 않습니다.테스트를 거쳤습니다.이것. 게다가 너무 길어서 읽고 싶지 않을 수도 있습니다.
Google 검색 sk_wmem_alloc
결과는 TSQ(TCP Small Queue) 도입에 맞춰 작동합니다.
- TCP 작은 큐, LWN.net 2012.
- tcp: TCP 작은 큐, 커널 커밋(코드 변경 + 설명).
하위 대기열 자체는 두 개의 서로 다른 대기열로 구성됩니다. 먼저 qdisc(큐잉 규칙) [*]가 나오고 그 다음에는 장치 내부의 큐가 옵니다.
TSQ 코드에서 "sk->sk_wmem_alloc은 [허용되지 않음] 주어진 제한을 초과하여 증가하며, qdisc/dev 계층의 각 tcp 소켓은 [기본적으로] 주어진 시간에 ~128KB를 넘지 않도록 허용됩니다."
=> sk_wmem_alloc
반드시 포함해야 함적어도qdisc 및 dev 레이어.
TSQ 코드는 많은 도움이 됩니다. "더 이상 단일 [대량 발신자]에 의한 qdisc에 4MB 백로그가 없습니다." 또한 "양측 소켓 자동 크기 조정은 더 이상 4MB를 사용하지 않습니다."
4MB는 어디에서 왔는가? 이것은 여기에 사용된 qdisc의 제한이 아닙니다. 훨씬 더 큽니다. 이 테스트에서는 기본값이 1000개 패킷인 "표준" FIFO qdisc를 사용합니다. 4MB/1000은 4K이지만 표준 패킷 크기는 아닙니다. 이 테스트에서는 표준 최대 TSO 패킷 크기인 64K를 사용합니다. 답변:
Linux 2.6.17에는 이제 발신자 및 수신자 자동 크기 조정 기능과 4MB의 기본 최대 창 크기 기능이 있습니다.
Linux의 현재 구현은 기본적으로 Semke '98에 설명된 내용이지만 최대-최소 공정한 공유는 없습니다.
--https://wiki.geant.org/display/public/EK/TCP+Buffer+Auto+Tuning
자동 확장은 대략 "2 * 대역폭 * 대기 시간"의 법칙을 따릅니다. 이는 "cwnd [혼잡 창]: 계속 전송할 적절한 데이터 양을 결정하기 위해 사용 가능한 대역폭 지연 곱(BDP)을 추정하는 기존 TCP 변수(단일 연결용)"를 사용하여 구현됩니다.
마지막으로 "전송 중인" 데이터의 총량은 TCP 버퍼 크기에 의해 제한됩니다. 이는 TCP가 신뢰할 수 있는 프로토콜이기 때문입니다. 물리적으로 패킷을 전송한 후에도 버퍼에 데이터 복사본을 보관해야 합니다. 전송 중에 패킷이 손실된 경우를 대비하여 다시 보낼 수 있어야 합니다. 우리는 수신자가 데이터가 안전하게 도착했다고 말할 때까지 데이터를 계속 저장해야 합니다.
이것은 TSQ의 다양한 결과를 설명합니다.
먼저, 발신자는 qdisc+device에 작은 대기열을 만듭니다. TCP는 경로의 여유 용량을 감지하기 위해 창을 점차적으로 늘립니다. 더 많이 보내므로 더 큰 대기열이 구축됩니다. TCP는 패킷이 삭제되었음을 감지하면 백오프합니다. 그러나 qdisc에는 여전히 더 많은 패킷을 저장할 공간이 있으므로 패킷을 삭제할 이유가 없습니다. 이 사이클은 한계에 도달할 때까지 계속됩니다...
TSQ를 사용하면 단일 TCP 발신자는 qdisc+ 장치 대기열을 128K 이상으로 늘리지 않습니다. 그러나 TSQ가 없으면 4MB 제한에 도달할 수 있습니다.
=> 여기 매뉴얼 페이지의 내용을 확인하세요.
TSQ가 없으면 sk_wmem_queued
최대값은 4MB입니다. sk_wmem_alloc
나머지 BDP를 빼면 4MB가 됩니다.
명시된 결과는 물리적 전송 지연이 매우 짧은 로컬 테스트에서 나온 것입니다.
대기 시간(또는 대역폭)을 늘리면 BDP가 증가합니다. TSQ는 128K로 제한되어 있지만 sk_wmem_queued
여전히 4MB에 도달할 수 있습니다.sk_wmem_alloc
[*] 다양한 패킷 우선순위 지정과 같은 라우터의 고급 qdisc 기능을 사용하세요. 그러나 모든 Linux 시스템은 qdisc 계층에서 일부 패킷을 대기열에 넣습니다. 처음에는 고정된 수의 패킷 대기열("fifo")입니다. 많은 최신 시스템에서 기본값은 이제 "fq_codel"입니다. "codel"은 전송 시간에 따라 대기열을 적응적으로 제한합니다. 장치 속도가 느릴수록 허용되는 대기열의 크기는 작아집니다. "fq_codel"은 또한 보다 공정한 공유를 제공하고 대량 발신자가 아닌 사람이 대량 발신자를 건너뛸 수 있도록 하여 응답성을 향상시키려고 시도합니다.
초기 노트
이 두 변수 중 하나가 UDP와 가장 관련이 있는 것 같습니다. 다른 하나는 TCP와 가장 관련이 있는 것 같습니다. 용도를 확인했어요양말_쓰기 가능()( sk_wmem_alloc
) 그리고sk_stream_is_writeable()( sk_wmem_queued
).
물론 UDP와 TCP 외에도 더 많은 소켓 프로토콜이 있습니다. 코드를 보면 차이점이 구현 "신뢰성"과 관련되어 있음을 알 수 있습니다.
이는 DCCP(데이터그램Congestion Control Protocol)에서는 :-P라는 기능을 사용하고 있습니다. DCCP는 "신뢰할 수 있는" 프로토콜입니다. 바라보다sk_stream_is_writeable()
dccp_poll().
삭제된 패킷을 처리하는 것과 관련이 있다면 sk_stream_is_writeable()
스트림 소켓 구현에서 해당 호출을 찾을 수 없는 이유도 설명됩니다. 데이터그램은 전송 중에 손실되지 않습니다.AF_LOCAL
AF_LOCAL
TCP와 UDP의 차이점은 다음 영역에서 특히 분명합니다 net/sunrpc/xprtsock.c
.
/**
* xs_udp_write_space - callback invoked when socket buffer space
* becomes available
* @sk: socket whose state has changed
*
* Called when more output buffer space is available for this socket.
* We try not to wake our writers until they can make "significant"
* progress, otherwise we'll waste resources thrashing kernel_sendmsg
* with a bunch of small requests.
*/
static void xs_udp_write_space(struct sock *sk)
{
read_lock_bh(&sk->sk_callback_lock);
/* from net/core/sock.c:sock_def_write_space */
if (sock_writeable(sk))
xs_write_space(sk);
read_unlock_bh(&sk->sk_callback_lock);
}
/**
* xs_tcp_write_space - callback invoked when socket buffer space
* becomes available
* @sk: socket whose state has changed
*
* Called when more output buffer space is available for this socket.
* We try not to wake our writers until they can make "significant"
* progress, otherwise we'll waste resources thrashing kernel_sendmsg
* with a bunch of small requests.
*/
static void xs_tcp_write_space(struct sock *sk)
{
read_lock_bh(&sk->sk_callback_lock);
/* from net/core/stream.c:sk_stream_write_space */
if (sk_stream_is_writeable(sk))
xs_write_space(sk);
read_unlock_bh(&sk->sk_callback_lock);
}
최종 메모
sock_writeable()
"소켓 버퍼"에 대한 정의와 sk_wmem_alloc
제안은 거짓말입니다.
위의 첫 번째 부분에서는 qdisc+장치 대기열과 구별되는 TCP 소켓 버퍼를 명확하게 식별했습니다. 이것은 모두 사실입니다. 그러나 TCP는 특별한 경우이며 신뢰할 수 있는("스트리밍") 프로토콜입니다.
구경하실 수도 있어요 man sendmsg
-
ENOBUFS
네트워크 인터페이스의 출력 대기열이 가득 찼습니다. 이는 일반적으로 인터페이스가 전송을 중지했음을 나타내지만 일시적인 정체로 인해 발생할 수도 있습니다. (일반적으로 Linux에서는 이런 일이 발생하지 않습니다. 장치 대기열이 오버플로되면 패킷이 자동으로 삭제됩니다.)
여기의 정확한 표현에는 UDP 소켓 버퍼가 언급되어 있지 않습니다. UDP 소켓에는 전용 전송 버퍼가 없습니다.. 우리는 패킷을 qdisc에 직접 채웁니다. sk_wmem_alloc
"전송 버퍼 크기"가 초과 되면 sendmsg()
호출이 차단(대기)됩니다 . 그러나 qdisc에 공간이 없으면 패킷은 자동으로 삭제됩니다.