Интервьюер: Замена! Он даже не понимает параметры TCP

интервью
Интервьюер: Замена! Он даже не понимает параметры TCP
Учите по одному предложению на английском языке каждый день и каждый день добивайтесь небольшого прогресса:

предисловие

Улучшение производительности TCP требует не только теоретических знаний о TCP, но и понимания и применения параметров ядра, предоставляемых операционной системой.

Протокол TCP реализуется операционной системой, поэтому операционная система предоставляет множество параметров для настройки TCP.

Linux TCP 参数
TCP-параметры Linux

Как правильно и эффективно использовать эти параметры для повышения производительности TCP, не так просто. Нам нужно назначать правильное лекарство для проблем каждой стадии TCP, а не обращаться за медицинской помощью в спешке.

Далее стратегия улучшения TCP будет объяснена с трех точек зрения, а именно:

  • Повышение производительности трехстороннего рукопожатия TCP;
  • Улучшение производительности четырехсторонней волны TCP;
  • Повышение производительности передачи данных TCP;
本节提纲
Краткое содержание этого раздела

текст

01 Повышение производительности трехстороннего рукопожатия TCP

TCP — это ориентированный на установление соединения, надежный протокол связи на транспортном уровне с двусторонней передачей, поэтому для установления соединения перед передачей данных требуется три рукопожатия.

三次握手与数据传输
Трехстороннее рукопожатие и передача данных

Затем на процесс трехэтапного рукопожатия приходится более 10% среднего времени HTTP-запроса.В таких сценариях, как плохое состояние сети, высокая степень параллелизма или столкновение с атаками SYN, корректно и эффективно, это будет иметь большое влияние на производительность.

Чтобы правильно и эффективно использовать эти параметры для повышения производительности трехэтапного рукопожатия TCP, необходимо понимать «переход состояний трехэтапного рукопожатия», чтобы при возникновении проблемы использоватьnetstatПрикажите увидеть, на каком этапе рукопожатия возникла проблема, а затем прописать правильное лекарство вместо того, чтобы в спешке идти к врачу.

TCP 三次握手的状态变迁
Переход состояния трехстороннего рукопожатия TCP

И клиент, и сервер могут оптимизировать производительность трехэтапного рукопожатия. Оптимизация клиента, который инициирует соединение, относительно проста, в то время как сервер должен прослушивать порт, который принадлежит пассивной стороне соединения, и поддерживает множество промежуточных состояний Метод оптимизации относительно сложен.

Следовательно, методы оптимизации клиента (активной стороны подключения) и сервера (пассивной стороны подключения) различаются, и тогда оптимизация выполняется для клиента и сервера соответственно.

Оптимизация на стороне клиента

Основная цель трехэтапного рукопожатия для установления соединения — «синхронизация порядкового номера».

Только когда серийный номер синхронизирован, передача может быть надежной.Многие функции TCP зависят от реализации серийного номера, например, управление потоком, повторная передача потерянных пакетов и т. д. Вот почему сообщение в трехэтапном рукопожатии называется SYN, а полное имя SYN называется SYN.Synchronize Sequence Numbers(серийный номер синхронизации).

TCP 头部
TCP-заголовок

Оптимизация состояния SYN_SENT

Как активный инициатор соединения, клиент сначала отправит пакет SYN, поэтому соединение клиента будет вSYN_SENTгосударство.

Клиент ожидает сообщения ACK от сервера.В нормальных условиях сервер вернет SYN+ACK в течение нескольких миллисекунд, но если клиент не получит сообщение SYN+ACK в течение длительного времени, он повторно отправит сообщение ACK. СИН-пакет.Количество повторных передач контролируется параметром tcp_syn_retries., по умолчанию 5 раз:

Обычно первая повторная передача по тайм-ауту осуществляется через 1 секунду, вторая повторная передача по тайм-ауту — через 2 секунды, третья повторная передача по тайм-ауту — через 4 секунды, а четвертая повторная передача по тайм-ауту — через 8 секунд. тайм-аут 16 секунд повторной передачи. Верно,Каждый тайм-аут в два раза длиннее предыдущего.

После пятой повторной передачи по тайм-ауту будет продолжаться ожидание в течение секунд 32. Если сервер по-прежнему не отвечает ACK, клиент завершает трехэтапное рукопожатие.

Итак, общее время 1+2+4+8+16+32=63 секунды, около 1 минуты.

SYN 超时重传
SYN тайм-аут повторной передачи

Вы можете изменить количество повторных передач SYN и отрегулировать верхний предел времени трехэтапного рукопожатия клиента в соответствии со стабильностью сети и загруженностью целевого сервера. Например, при обмене данными в интрасети количество повторных попыток может быть соответствующим образом уменьшено, чтобы как можно быстрее выявлять ошибки для приложения.

Оптимизация на стороне сервера

Когда сервер получает пакет SYN, сервер немедленно отвечает пакетом SYN+ACK, указывающим, что он получил серийный номер клиента, а также отправляет другой стороне свой собственный серийный номер.

В этот момент на сервере появляется новое соединение со статусомSYN_RCV. В этом состоянии ядро ​​Linux создаст "очередь полусоединений" для хранения "незавершенной" информации о рукопожатии. Когда очередь полусоединений переполняется, сервер не может устанавливать новые соединения.

半连接队列与全连接队列
Полусвязные очереди и полносвязные очереди

Атака SYN, атака этой полусвязной очереди.

Как узнать, когда соединение разрывается из-за того, что очередь полусоединения SYN заполнена?

мы можем пройтиnetstat -sВ статистике, выдаваемой командой, можно получить количество сбоев, вызванных полной очередью полусоединений:

Выходное значение вышеСовокупное значение, указывающее, сколько TCP-соединений было разорвано из-за переполнения очереди полусоединений.Выполнять несколько раз каждые несколько секунд.Если наблюдается восходящий тренд, значит, в данный момент имеет место явление переполнения очереди полуподключений..

Как настроить размер очереди полусоединения SYN?

Чтобы увеличить очередь полусоединений,Нельзя просто увеличить значение tcp_max_syn_backlog, но и увеличить somaxconn и backlog вместе, то есть увеличить очередь приема. В противном случае простое увеличение tcp_max_syn_backlog неэффективно.

Чтобы увеличить tcp_max_syn_backlog и somaxconn, нужно изменить параметры ядра Linux:

Способ увеличения отставания для каждого веб-сервиса разный, например способ увеличения отставания Nginx следующий:

Наконец, после изменения вышеуказанных параметров перезапустите службу Nginx, потому что очередь полусоединения SYN и очередь принятия находятся в состоянии ожидания.listen()Инициализация.

Можно ли сбрасывать только соединения, если очередь полусоединения SYN заполнена?

Не так,Включите syncookies для успешного установления соединения без использования очереди полусоединения SYN..

Принцип работы syncookies: Сервер вычисляет значение в соответствии с текущим состоянием и отправляет его в сообщении SYN+ACK, отправленном им самим.Когда клиент возвращает сообщение ACK, значение берется для проверки.Если оно легально , соединение считается успешно установленным, как показано ниже.

开启 syncookies 功能
Включить функцию синкокок

Параметр syncookies в основном имеет следующие три значения:

  • Значение 0 означает, что функция отключена;
  • Значение 1 указывает на то, что он активен только в том случае, если очередь полусоединения SYN не может быть размещена;
  • Значение 2, указывающее, что функция включена безоговорочно;

Тогда при работе с SYN-атаками вам нужно всего лишь установить его в 1:

Оптимизация состояния SYN_RCV

Когда клиент получает сообщение SYN+ACK от сервера, он ответит серверу ACK, и состояние подключения клиента будет преобразовано из SYN_SENT в ESTABLISHED, указывая на то, что соединение установлено успешно.

Время для успешного установления соединения на стороне сервера будет позже.После того, как сторона сервера получит ACK от клиента, состояние соединения на стороне сервера станет УСТАНОВЛЕНО.

Если сервер не получит ACK, он повторно отправит сообщение SYN+ACK и останется в состоянии SYN_RCV.

Когда сеть загружена и нестабильна, потери пакетов станут серьезными, в этом случае следует увеличить количество повторных передач. В противном случае количество повторных передач может быть уменьшено.Способ изменить количество повторных передач — настроить параметр tcp_synack_retries.:

Количество попыток по умолчанию для tcp_synack_retries равно 5. Подобно повторной передаче клиентом SYN, его повторная передача будет проходить через 1, 2, 4, 8 и 16 секунд. После последней повторной передачи будет продолжаться ожидание в течение 32 секунд. Соединение будет закрыто только в том случае, если ACK не получен, поэтому ожидание занимает 63 секунды.

После того, как сервер получит ACK, соединение будет успешно установлено, в это время ядро ​​удалит соединение из очереди полусоединений, затем создаст новое полное соединение, добавит его в очередь принятия и дождется завершения процесса. вызовите функцию accept, чтобы отключить соединение.

Если процесс не может вовремя вызвать функцию принятия, это приведет к переполнению очереди приема (также известной как очередь полного соединения), что в конечном итоге приведет к разрыву установленного TCP-соединения.

accept 队列溢出
принять переполнение очереди

Очередь приема заполнена, могу я просто разорвать соединение?

Отказ от соединения — это просто поведение по умолчанию в Linux.Мы также можем отправить клиенту сообщение сброса RST, чтобы сообщить клиенту, что соединение не удалось. Для включения этой функции необходимо установить для параметра tcp_abort_on_overflow значение 1.

tcp_abort_on_overflow имеет два значения, 0 и 1, которые представляют:

  • 0: если очередь приема заполнена, то сервер отбрасывает подтверждение, отправленное клиентом;
  • 1: если очередь приема заполнена, сервер отправляетRSTУпаковывается клиенту, указывая, что процесс рукопожатия и соединение отменены;

Если вы хотите знать, не может ли клиент подключиться к серверу, связано ли это с тем, что очередь полного соединения TCP сервера заполнена, вы можете установить tcp_abort_on_overflow в 1, тогда, если вы видите много исключений в клиентеconnection reset by peerошибка, то можно доказать, что она связана с переполнением очереди полного соединения TCP на стороне сервера.

В общем случае tcp_abort_on_overflow следует установить равным 0, так как это лучше для неравномерного трафика.

Например, когда очередь приема заполнена и сервер теряет ACK, в то же время состояние подключения клиента УСТАНОВЛЕНО, и клиентский процесс отправляет запросы по установленному соединению. Пока сервер не ответит ACK на запрос, запрос клиента будет «повторно передан» несколько раз.Если процесс на сервере занят только временно, а очередь приема заполнена, то, когда очередь приема пуста, полученное повторно сообщение запроса по-прежнему будет запускать сервер для успешного установления соединения, поскольку оно содержит ACK.

tcp_abort_on_overflow 为 0 可以应对突发流量
tcp_abort_on_overflow равен 0, чтобы иметь дело с пакетным трафиком

Таким образом, установка для tcp_abort_on_overflow значения 0 может повысить вероятность успешного установления соединения.Только если вы абсолютно уверены, что очередь полного соединения TCP будет переполнена в течение длительного времени, вы можете установить значение 1, чтобы уведомить клиента как можно скорее.

Как настроить длину очереди на прием?

Длина очереди приема зависит от минимального значения между somaxconn и невыполненной работой, которое равно min(somaxconn, невыполненной работы), где:

  • somaxconn — параметр ядра Linux, значение по умолчанию — 128, которое можно передать черезnet.core.somaxconnустановить его значение;
  • отставаниеlisten(int sockfd, int backlog)размер бэклога в функции;

Значение невыполненной работы по умолчанию для распространенных веб-сервисов, таких как Tomcat, Nginx и Apache, равно 511.

Как проверить длину очереди приема серверного процесса?

в состоянии пройтиss -ltnКоманда для просмотра:

  • Recv-Q: размер текущей очереди приема, то есть трехстороннее рукопожатие в настоящее время завершено и ожидает сервер.accept()TCP соединение;
  • Send-Q: максимальная длина очереди приема, приведенный выше вывод указывает, что служба TCP прослушивает порт 8088, максимальная длина очереди приема составляет 128;

Как я могу увидеть соединения, которые были разорваны из-за того, что очередь принятых соединений заполнена?

Когда очередь принятых соединений будет превышена, сервер будет сбрасывать последующие входящие TCP-соединения, и будет подсчитано количество сброшенных TCP-соединений.Мы можем использовать команду netstat -s для просмотра:

41 150 раз, показанные выше, представляют собой количество переполнений очереди приема.Обратите внимание, что это кумулятивное значение. Он может выполняться каждые несколько секунд.Если это число продолжает увеличиваться, это означает, что очередь приема соединений иногда переполняется.

Если соединения продолжают сбрасываться из-за переполнения очереди приема, следует увеличить параметры невыполненной работы и somaxconn.

Как обойти трехстороннее рукопожатие?

Выше мы просто оптимизируем процесс трехэтапного рукопожатия Далее давайте посмотрим, как обойти трехэтапное рукопожатие для отправки данных.

Следствием трехэтапного рукопожатия для установления соединения является то, что HTTP-запрос должен быть отправлен после RTT (один раз в оба конца от клиента к серверу).

常规 HTTP 请求
обычный HTTP-запрос

После версии ядра Linux 3.7 предоставляется функция TCP Fast Open, которая может уменьшить задержку установления TCP-соединения.

Далее поговорим о том, как работает функция TCP Fast Open.

开启 TCP Fast Open 功能
Включить функцию быстрого открытия TCP

Процесс, когда клиент впервые устанавливает соединение:

  1. Клиент отправляет сообщение SYN, содержащее параметр Fast Open, а файл cookie этой опции пуст, что указывает на то, что клиент запрашивает файл cookie Fast Open;
  2. Серверы, поддерживающие TCP Fast Open, генерируют файл cookie и помещают его в параметр Fast Open в пакете SYN-ACK для отправки обратно клиенту;
  3. После того, как клиент получает SYN-ACK, файл cookie в параметре Fast Open кэшируется локально.

Таким образом, когда HTTP-запрос GET инициируется в первый раз, по-прежнему требуется обычный трехэтапный процесс рукопожатия.

После этого процесс, когда клиент снова устанавливает соединение с сервером:

  1. Клиент отправляет сообщение SYN, содержащее «данные» (для обычного процесса рукопожатия TCP, отличного от TFO, сообщение SYN не содержит «данных») и ранее записанный файл cookie;
  2. Сервер, поддерживающий TCP Fast Open, проверит полученный файл cookie: если файл cookie действителен, сервер подтвердит SYN и «данные» в сообщении SYN-ACK, после чего сервер передаст «данные» соответствующему приложению. ; Если файл cookie недействителен, сервер отбрасывает «данные», содержащиеся в сообщении SYN, а его последующее сообщение SYN-ACK только подтверждает соответствующий порядковый номер SYN;
  3. Если сервер принимает «данные» в сообщении SYN, сервер может отправить «данные» до завершения рукопожатия,Это уменьшает время, затрачиваемое на 1 RTT, вызванное рукопожатием.;
  4. Клиент отправит ACK для подтверждения SYN и «данных», отправленных обратно сервером, но если «данные», отправленные клиентом в исходном сообщении SYN, не подтверждены, клиент повторно отправит «данные»;
  5. Процесс передачи данных последующего TCP-соединения соответствует нормальной ситуации не-TFO.

Поэтому, когда HTTP-запрос GET инициируется позже, трехэтапное рукопожатие можно обойти, что сокращает время, затрачиваемое на 1 RTT, вызванное рукопожатием.

Когда функция TFO включена, значение файла cookie сохраняется в поле параметра TCP:

TCP option 字段 - TFO
Поле опций TCP — TFO

Примечание. После того, как клиент запрашивает и сохраняет файл cookie быстрого открытия, он может повторять TCP Fast Open до тех пор, пока сервер не сочтет файл cookie недействительным (обычно с истекшим сроком действия).

Как включить функцию TCP Fast Open под Linux?

В системах Linux вы можете использоватьУстановите параметр ядра tcp_fastopn, чтобы включить Fast Open.:

Значение каждого значения tcp_fastopn:

  • 0 выкл.
  • 1 Используйте функцию Fast Open в качестве клиента
  • 2 Используйте функцию Fast Open в качестве сервера
  • 3 Fast Open может использоваться как в качестве клиента, так и сервера

Для эффективной работы функция TCP Fast Open должна поддерживаться как клиентом, так и сервером.

резюме

В этом обзоре в основном представлены несколько параметров TCP для оптимизации трехэтапного рукопожатия TCP.

三次握手优化策略
Стратегия оптимизации трехстороннего рукопожатия

оптимизация на стороне клиента

Когда клиент инициирует пакет SYN, он может передатьtcp_syn_retriesУправляет количеством повторных передач.

оптимизация на стороне сервера

Когда очередь полусоединений SYN сервера переполняется, последующие соединения будут отбрасываться.netstat -sНаблюдайте за переполнением очереди полусоединений.Если переполнение очереди полусоединений SYN серьезно, вы можете передатьtcp_max_syn_backlog、somaxconn、backlogПараметр для настройки размера очереди полусоединения SYN.

Количество повторных передач, на которые сервер отвечает на SYN+ACK, определяетсяtcp_synack_retriesконтроль параметров. В случае SYN-атакиtcp_syncookiesПараметр имеет значение 1, что означает, что функция syncookie включается только после заполнения очереди SYN, что может гарантировать успешное установление нормального соединения.

Когда сервер получает ACK, возвращенный клиентом, он перемещает соединение в очередь разрешений, ожидая вызова функции accpet() для разрыва соединения.

в состоянии пройтиss -lntПроверьте длину очереди приема серверного процесса.Если очередь приема переполняется, система по умолчанию отбрасывает ACK.tcp_abort_on_overflowЕсли установлено значение 1 , это означает, что клиент уведомляется с помощью RST о сбое установления соединения.

Если очередь приема серьезно переполняется, вы можете передать функцию прослушиванияbacklogпараметры иsomaxconnСистемный параметр увеличивает размер очереди, а длина очереди приема зависит от min(backlog, somaxconn).

Обход трехэтапного рукопожатия

Функция TCP Fast Open может обходить трехэтапное рукопожатие, сокращая время HTTP-запроса на 1 RTT.tcp_fastopenЧтобы включить эту функцию, вы должны убедиться, что и сервер, и клиент поддерживают ее.


02 Повышение производительности четырехкратной волны TCP

Далее давайте посмотрим, как оптимизировать производительность, когда TCP передается четыре раза для закрытия соединения.

Прежде чем мы начнем, мы должны понять процесс четырех волновых переходов состояний.

И клиент, и сервер могут активно отключаться,Обычно сторона, которая закрывает соединение первой, называется активной стороной, а сторона, закрывающая соединение позже, называется пассивной стороной.

客户端主动关闭
Клиент активно закрывается

можно увидеть,Процесс четырех ручных взмахов включает только два типа сообщений, а именно FIN и ACK.:

  • FIN означает разорвать соединение.Тот, кто отправляет сообщение FIN, означает, что он больше не будет отправлять данные и закроет канал передачи в этом направлении;
  • ACK означает подтверждение, которое используется для уведомления другой стороны о том, что ваш канал отправки закрыт;

Процесс взмахивания четыре раза:

  • Когда активная сторона закроет соединение, будет отправлено сообщение FIN, а TCP-соединение отправителя изменится с ESTABLISHED на FIN_WAIT1.
  • Когда пассивная сторона получает сообщение FIN, ядро ​​автоматически ответит сообщением ACK, а статус соединения изменится с ESTABLISHED на CLOSE_WAIT, указывая на то, что пассивная сторона ожидает, пока процесс вызовет функцию закрытия, чтобы закрыть соединение.
  • Когда активная сторона получает этот ACK, статус соединения меняется с FIN_WAIT1 на FIN_WAIT2, что означает, чтоКанал отправки активной стороны закрыт..
  • Когда пассивная сторона входит в CLOSE_WAIT, пассивная сторона продолжит обработку данных.После того, как функция чтения процесса вернется к 0, приложение вызовет функцию закрытия, которая заставит ядро ​​отправить сообщение FIN.В это время, статус подключения пассивной стороны становится LAST_ACK.
  • Когда активная сторона получает сообщение FIN, ядро ​​ответит пассивной стороне сообщением ACK, и статус соединения активной стороны изменится с FIN_WAIT2 на TIME_WAIT,Соединение в состоянии TIME_WAIT будет полностью закрыто после ожидания около 1 минуты в системе Linux..
  • Когда пассивная сторона получает последнее сообщение ACK,Пассивное соединение будет закрыто.

Как видите, каждое направление требуетFIN и ACK, так его часто называютпомахал четыре раза.

Здесь следует отметить следующее:Состояние TIME_WAIT доступно, только если соединение активно закрыто.

Идеи оптимизации активной и пассивной заключительной стороны также различаются, и далее мы поговорим о том, как их оптимизировать.

Оптимизация активной стороны

Обычно есть два способа закрыть соединение, а именно: закрыть сообщение RST и закрыть сообщение FIN.

Если процесс завершится аварийно, ядро ​​отправит сообщение RST, чтобы закрыть его.Ему не нужно махать четыре раза, что является способом насильственного закрытия соединения.

Способ безопасного закрытия соединения должен быть через четыре волны, это называется процессомcloseиshutdownФункция инициирует сообщение FIN (параметр отключения должен быть передан в SHUT_WR или SHUT_RDWR для отправки FIN).

В чем разница между вызовом функции закрытия и функцией выключения?

Вызов функции закрытия означает полное отключение,Полное отключение означает, что данные не только не могут быть переданы, но и данные не могут быть отправлены. В это время соединение стороны, вызвавшей функцию закрытия, называется «бесхозным соединением».Если вы используете команду netstat -p, вы обнаружите, что имя процесса, соответствующее соединению, пусто.

Использование функции закрытия для закрытия соединения не элегантно. В результате происходит изящное закрытие соединенияshutdownфункция,Он может контролировать закрытие соединений только в одном направлении:

Второй параметр определяет способ отключения, в основном тремя способами:

  • SHUT_RD(0):Закрыть направление "чтение" соединения, если в приемном буфере есть принятые данные, они будут отброшены, а когда впоследствии будут получены новые данные, данные будут подтверждены ACK, а затем тихо отброшены. То есть одноранговый узел все равно получит ACK, и в этом случае он даже не узнает, что данные были отброшены.
  • SHUT_WR(1):Закройте направление «записи» соединения, которое часто называют «полузакрытым» соединением. Если в буфере отправки все еще есть неотправленные данные, они будут отправлены немедленно, а партнеру будет отправлено сообщение FIN.
  • SHUT_RDWR(2): Эквивалентно операциям SHUT_RD и SHUT_WR по одному разу,Закрыть сокет как для чтения, так и для записи.

И функция close, и функция shutdown могут закрыть соединение, но соединения, закрытые этими двумя методами, не только функционально различны, но и параметры Linux, управляющие ими, также различны.

Оптимизация состояния FIN_WAIT1

После того, как активная сторона отправит сообщение FIN, соединение находится в состоянии FIN_WAIT1.В нормальных условиях, если ACK пассивной стороны может быть получен вовремя, оно вскоре перейдет в состояние FIN_WAIT2.

Однако, когда ACK, возвращенный другой стороной, не получен в течение длительного времени, соединение всегда будет находиться в состоянии FIN_WAIT1. В настоящее время,Ядро будет регулярно повторно передавать сообщение FIN, а количество повторных передач контролируется параметром tcp_orphan_retries.(Обратите внимание, что хотя orphan означает «сирота», этот параметр действителен не только для потерянных соединений, фактически он действителен для всех соединений в состоянии FIN_WAIT1), значение по умолчанию равно 0.

Вам может быть интересно, сколько раз представляет этот 0?На самом деле, когда это 0, это означает 8 раз, из следующего исходного кода ядра:

Если в состоянии FIN_WAIT1 много соединений, нам нужно рассмотреть возможность уменьшения значения tcp_orphan_retries.Когда количество повторных передач превысит tcp_orphan_retries, соединение будет закрыто напрямую.

Для обычных ситуаций достаточно понизить tcp_orphan_retries. При обнаружении вредоносной атаки сообщение FIN вообще не может быть отправлено, что вызвано двумя характеристиками TCP:

  • Прежде всего, TCP должен гарантировать, что сообщения отправляются упорядоченным образом, и сообщение FIN не является исключением.Когда в буфере отправки все еще есть данные, которые не были отправлены, сообщение FIN не может быть отправлено заранее.
  • Во-вторых, TCP имеет функцию управления потоком: когда окно приема получателя равно 0, отправитель больше не может отправлять данные. Поэтому, когда злоумышленник скачивает большой файл, через окно приема он может быть установлен в 0, что предотвратит отправку сообщения FIN, а соединение всегда будет находиться в состоянии FIN_WAIT1.

Путь решения этой проблемы заключается вНастройте параметр tcp_max_orphans, который определяет максимальное количество «бесхозных соединений».:

когда процесс вызываетcloseФункция закрывает соединение, и в этот момент соединение становится «бесхозным соединением», поскольку оно не может отправлять или получать данные. Чтобы предотвратить слишком много бесхозных соединений и привести к тому, что системные ресурсы будут заняты в течение длительного времени, система Linux предоставляетtcp_max_orphansпараметр. Если количество потерянных подключений больше, чем это, вновь добавленное потерянное соединение больше не будет волноваться четыре раза, а будет напрямую отправлять сообщение сброса RST, чтобы принудительно закрыть его.

Оптимизация состояния FIN_WAIT2

Когда активная сторона получает сообщение ACK, она будет находиться в состоянии FIN_WAIT2, что означает, что канал отправки активной стороны был закрыт, и затем она будет ждать, пока другая сторона отправит сообщение FIN, и закроет канал отправки другой стороны. .

В настоящее время,Если соединение было закрыто с помощью функции завершения работы, соединение может оставаться в состоянии FIN_WAIT2, поскольку оно все еще может отправлять или получать данные. Но для потерянного соединения, закрытого функцией закрытия, поскольку оно не может отправлять и получать данные, это состояние не может длиться слишком долго, и tcp_fin_timeout контролирует продолжительность соединения в этом состоянии., значение по умолчанию — 60 секунд:

Это означает, что для потерянных соединений (соединений, закрытых вызовом close), если сообщение FIN не будет получено через 60 секунд, соединение будет закрыто напрямую.

Эти 60 секунд не определены произвольно, это то же самое, что продолжительность состояния TIME_WAIT, и мы поговорим о том, почему именно 60 секунд позже.

Оптимизация состояния TIME_WAIT

TIME_WAIT — это последнее состояние, в котором активная сторона помахала четыре раза, а также наиболее часто встречающееся состояние.

После получения сообщения FIN от пассивной стороны активная сторона немедленно ответит ACK, указав, что канал отправки другой стороны закрыт, после чего он перейдет в состояние TIME_WAIT. В системах Linux состояние TIME_WAIT будет длиться 60 секунд, прежде чем перейти в состояние выключения.

Соединение в состоянии TIME_WAIT действительно близко к активной стороне. Затем пассивная сторона все еще находится в состоянии LAST_ACK до получения сообщения ACK. Если сообщение ACK не достигает пассивной стороны, пассивная сторона повторно отправит сообщение FIN. Количество повторных передач по-прежнему контролируется параметром tcp_orphan_retries, описанным ранее.

Статус TIME-WAIT особенно важен по двум причинам:

  • предотвратить прием «старых» пакетов с той же «четверкой»;
  • Гарантировать, что сторона с «пассивно закрытым соединением» может быть правильно закрыта, то есть гарантировать, что последний ACK может быть получен пассивно закрытой стороной, тем самым помогая ей нормально закрыться;

Причина первая: предотвращение пакетов от старых соединений

Одним из эффектов TIME-WAIT являетсяЧтобы предотвратить получение исторических данных, что приводит к проблеме путаницы данных.

Предполагая, что TIME-WAIT не имеет времени ожидания или слишком короткое, что происходит, когда приходит задержанный пакет?

接收到历史数据的异常
Получено исключение исторических данных
  • Как показано на рисунке выше, желтое поле отправляется сервером перед закрытием соединения.SEQ = 301Сообщение задерживается сетью.
  • В это время, после мультиплексирования TCP-соединения с тем же портом, задержанноеSEQ = 301После достижения клиента клиент может нормально получить сообщение с истекшим сроком действия, что вызовет серьезные проблемы, такие как путаница данных.

Поэтому TCP разработал такой механизм, после2MSLв этот раз,Достаточно отбросить пакеты данных в обоих направлениях, чтобы пакеты данных исходного соединения естественным образом исчезли в сети, а вновь появившиеся пакеты данных должны быть сгенерированы вновь установленным соединением.

Причина 2. Убедитесь, что соединение правильно закрыто

Другая роль TIME-WAITОжидание, достаточное для того, чтобы убедиться, что последний ACK получен стороной, выполняющей пассивное отключение, помогает корректно завершить работу.

Предполагая, что TIME-WAIT не имеет времени ожидания или слишком короткое, какие проблемы могут быть вызваны отключением?

没有确保正常断开的异常
Никаких исключений для обеспечения нормального отключения
  • Как показано на рисунке выше, клиент в красной рамке — последний из четырех махающих руками.ACKЕсли сообщение потеряно в сети, если клиентTIME-WAITЕсли он слишком короткий или нет, он войдет напрямуюCLOSEсостоянии, то сервер всегда будет вLASE-ACKгосударство.
  • Когда клиент инициирует установление соединенияSYNПосле сообщения запроса сервер отправитRSTсообщение клиенту, процесс установления соединения будет прекращен.

Давайте вернемся и посмотрим, почему состояние TIME_WAIT сохраняется в течение 60 секунд? Это тот же принцип, по которому состояние FIN_WAIT2 потерянного соединения сохраняется в течение 60 секунд по умолчанию.Потому что оба состояния нужно сохранить для 2MSL. Полное название MSL — Максимальное время жизни сегмента, определяющее максимальное время жизни пакета в сети.(Каждый раз, когда пакет пересылается маршрутизатором, поле TTL IP-заголовка будет уменьшаться на 1, а при уменьшении до 0 пакет будет отбрасываться, что ограничивает максимальное время выживания пакета).

Почему продолжительность 2 MSL? Это на самом деле эквивалентноРазрешить хотя бы одну потерю пакетов. Например, если ACK потерян в одном MSL, FIN, повторно переданный пассивной стороной, прибудет во второй MSL, и соединение в состоянии TIME_WAIT может справиться.

Почему не 4 или 8 длин MSL? Вы можете представить себе плохую сеть с коэффициентом потери пакетов 1%.Вероятность двух последовательных потерь пакетов составляет всего 1 из 10 000. Эта вероятность слишком мала.Экономичнее игнорировать ее, чем решать ее.

Таким образом, максимальная продолжительность состояний TIME_WAIT и FIN_WAIT2 составляет 2 MSL, а поскольку значение MSL фиксировано на уровне 30 секунд в системах Linux, они оба равны 60 секундам.

Несмотря на то, что состояние TIME_WAIT необходимо, в конце концов оно потребляет системные ресурсы.Если состояние TIME_WAIT стороны, инициирующей соединение, слишком велико и все ресурсы порта заняты, новое соединение создать невозможно.

  • Клиент ограничен ресурсами порта: Если у клиента слишком много TIME_WAIT, это приведет к тому, что ресурсы порта будут заняты, потому что портов всего 65536, и будет невозможно создать новое соединение, когда оно будет заполнено;
  • Сервер ограничен системными ресурсами: Поскольку четверка представляет собой TCP-соединение, теоретически сервер может установить много соединений.Сервер слушает только один порт, но он перебросит соединение в поток обработки, поэтому теоретически слушающий порт может продолжать слушать. Но пул потоков не может обрабатывать такое количество постоянных подключений. Поэтому, когда на стороне сервера происходит большое количество TIME_WAIT, когда системные ресурсы заполнены, это приведет к невозможности обработки нового соединения;

Кроме того,Linux предоставляет параметр tcp_max_tw_buckets.Когда количество соединений в TIME_WAIT превышает этот параметр, вновь закрытое соединение не будет проходить через TIME_WAIT и будет закрыто напрямую:

При увеличении количества одновременных подключений к серверу соответственно будет увеличиваться и количество подключений в состоянии TIME_WAIT, поэтому его следует увеличитьtcp_max_tw_bucketsпараметры для уменьшения вероятности путаницы данных между различными соединениями.

tcp_max_tw_buckets не настолько велик, насколько это возможно, ведь память и порты ограничены.

Одним из способов повторного использования соединения в состоянии TIME_WAIT при установлении нового соединения является открытие параметра tcp_tw_reuse. Однако следует отметить, что этот параметр используется только для клиента (инициатора соединения), потому что он работает при вызове connect() и бесполезен для сервера (пассивное соединение).

tcp_tw_reuse безопасен и управляем с точки зрения протокола и может повторно использовать порты в течение TIME_WAIT для новых подключений.

Что такое безопасность и управляемость с точки зрения протокола? Есть два основных момента:

  • Применимо только к инициатору соединения, то есть к клиенту в модели C/S;
  • Время создания соединения для соответствующего состояния TIME_WAIT превышает 1 секунду, прежде чем его можно будет использовать повторно.

При использовании этой опции также предполагается, что необходимо включить поддержку временных меток TCP (другая сторона также должна включить):

За счет введения временных меток это дает некоторые преимущества:

  • Упомянутая ранее проблема 2MSL исчезла, поскольку повторяющиеся пакеты естественным образом отбрасываются из-за просроченных меток времени;
  • В то же время это также предотвращает перенос порядкового номера, в том числе потому, что повторяющиеся пакеты естественным образом отбрасываются из-за просроченных временных меток;

Отметка времени определяется в поле выбора TCP.Когда функция отметки времени включена, отметка времени отправленного сообщения будет переноситься при передаче сообщения TCP.

TCP option 字段 - 时间戳
Поле параметра TCP — метка времени

Давайте посмотрим на включенную функцию tcp_tw_reuse, что произойдет, если последний ACK из четырех волн потеряется в сети?

四次挥手中的最后一次 ACK 在网络中丢失
Последний ACK из четырех волн теряется в сети

Процесс, показанный выше:

  • Последний ACK из четырех волн теряется в сети, и сервер всегда находится в состоянии LAST_ACK;
  • Поскольку клиент включил функцию tcp_tw_reuse, когда клиент снова инициирует новое соединение, он будет повторно использовать соединение в состоянии time_wait более чем через 1 секунду.Однако новый пакет SYN, отправленный клиентом, будет проигнорирован (из-за метки времени), поскольку сервер сравнивает метку времени последнего пакета клиента с пакетом SYN, и пакет с истекшим сроком действия будет отброшен сервером.;
  • Сообщение FIN сервера не получило последний ACK из четырех взмахов рук, поэтому со временем он повторно отправляет сообщение FIN клиенту;
  • Клиент в состоянии SYN_SENT вернет серверу RST после получения сообщения FIN, поэтому сервер выйдет из состояния LAST_ACK;
  • Время ожидания исходного клиентского SYN-сообщения истекло, и оно было передано повторно (через 1 секунду)., и в это время сервер может правильно пожать руку три раза.

Так что все скажут, что tcp_tw_reuse включен, и соединение может быть успешно установлено через 1 секунду мультиплексирования состояния time_wait, эта 1 секунда в основном тратится на повторную передачу SYN-пакетов.

Кроме того, в старой версии Linux также предусмотрен параметр tcp_tw_recycle, но при его включении возникают две ямы:

  • Linux ускорит время состояния клиента и сервера TIME_WAIT, то есть сделает состояние TIME_WAIT менее 60 секунд, что легко может привести к путанице данных;
  • Кроме того,Linux будет отбрасывать все пакеты с удаленного устройства с отметкой времени меньше, чем последняя записанная отметка времени (отправленная тем же удаленным устройством).. То есть, чтобы использовать эту опцию, временная метка пакета должна быть гарантированно монотонно возрастающей. Тогда проблема в том, что отметка времени здесь не абсолютное время в нашем обычном смысле, а относительное время. Во многих случаях мы не можем гарантировать, что метка времени монотонно увеличивается, например, когда используются NAT, LVS и т. д.;

Поэтому не рекомендуется ставить его равным 1. После версии Linux 4.12 ядро ​​Linux напрямую отменяет этот параметр, и его рекомендуется отключить:

Кроме того, мы можем установить параметр сокета в программе, чтобы установить поведение вызова close для закрытия соединения.

еслиl_onoffотличен от нуля, иl_lingerзначение 0,Затем после вызова close он немедленно отправит флаг RST на противоположный конец, и TCP-соединение пропустит четыре волны, пропустит состояние TIME_WAIT и закроет его напрямую.

Но это дает возможность пересечь состояние TIME_WAIT, но это очень опасное поведение, и его не стоит продвигать.

Пассивная боковая оптимизация

Когда пассивная сторона получает сообщение FIN, ядро ​​​​автоматически отвечает ACK, и соединение находится в состоянии CLOSE_WAIT, что, как следует из названия, означает ожидание, пока процесс приложения вызовет функцию закрытия, чтобы закрыть соединение.

Ядро не имеет права заменить процесс на закрытие соединения, потому что если активная сторона закрыла соединение через shutdown, то оно хочет получить данные или отправить данные по полузакрытому соединению. Поэтому Linux не ограничивает продолжительность состояния CLOSE_WAIT.

Конечно, большинство приложений не используют функцию выключения для закрытия соединений. так,Когда вы используете команду netstat, чтобы найти много статусов CLOSE_WAIT. Вам необходимо устранить неполадки в приложении, поскольку функция закрытия не вызывается, когда функция чтения возвращает 0 из-за ошибки в приложении.

Когда в состоянии CLOSE_WAIT вызывается функция закрытия, ядро ​​​​отправляет сообщение FIN, чтобы закрыть канал отправки, и соединение переходит в состояние LAST_ACK, ожидая, пока активная сторона вернет ACK, чтобы подтвердить, что соединение закрыто.

Если ACK не будет получен в течение длительного времени, ядро ​​повторно отправит сообщение FIN, а количество повторных передач по-прежнему будет контролироваться параметром tcp_orphan_retries, что согласуется со стратегией оптимизации активной стороны для повторной отправки сообщения FIN.

Есть еще одна вещь, на которую мы должны обратить внимание,Если пассивная сторона вызывает функцию закрытия быстро, то ACK и FIN пассивной стороны могут быть отправлены в одном сообщении, поэтому кажется, что четыре волны станут тремя волнами, это всего лишь частный случай, не важно.

Что, если обе стороны соединения закроют соединение одновременно?

Поскольку TCP является двойным полнодуплексным протоколом, может возникнуть явление, когда две стороны закрывают соединение одновременно, то есть сообщение FIN отправляется одновременно.

На этом этапе все еще применяются стратегии оптимизации, описанные выше. Когда обе стороны отправляют пакеты FIN, они обе считают себя активной стороной, поэтому они обе входят в состояние FIN_WAIT1, а количество повторных передач пакетов FIN по-прежнему контролируется параметром tcp_orphan_retries.

同时关闭
закрыто в то же время

Следующий,В процессе ожидания сообщения ACK обе стороны ожидают сообщения FIN. Это новая ситуация, поэтому соединение переходит в новое состояние, называемое ЗАКРЫТИЕ, которое заменяет состояние FIN_WAIT2.. Затем, после того как два ядра ответят ACK, чтобы подтвердить закрытие канала отправки другой стороны, они переходят в состояние TIME_WAIT, и после ожидания 2MSL соединение автоматически закрывается.

резюме

Для оптимизации четырехсторонней волны TCP нам необходимо настроить параметры ядра TCP системы в соответствии с изменением состояния четырехсторонней волны активной и пассивной сторон.

四次挥手的优化策略
Стратегия четырехволновой оптимизации

Оптимизация активной стороны

Если сторона, которая активно инициирует сообщение FIN, отключает соединение, если она не получает ответ ACK от другой стороны, она повторно передает сообщение FIN, и количество повторных передач устанавливаетсяtcp_orphan_retriesрешение по параметрам.

Когда активная сторона получает сообщение ACK, соединение переходит в состояние FIN_WAIT2.В зависимости от метода закрытия метод оптимизации также различается:

  • Если это соединение, закрытое функцией закрытия, то это бесхозное соединение. еслиtcp_fin_timeoutЕсли сообщение FIN от другой стороны не получено в течение нескольких секунд, соединение сразу закрывается. В то же время, чтобы иметь дело с бесхозными соединениями, занимающими слишком много ресурсов,tcp_max_orphansОпределяет максимальное количество потерянных соединений, при превышении которых соединение будет разорвано напрямую.
  • Напротив, соединение, закрытое функцией выключения, не ограничивается этим параметром;

Когда активная сторона получает сообщение FIN и возвращает ACK, соединение активной стороны переходит в состояние TIME_WAIT. Это состояние будет длиться 1 минуту. Чтобы состояние TIME_WAIT не занимало слишком много ресурсов,tcp_max_tw_bucketsМаксимальное количество определено, и соединение будет разорвано сразу после его превышения.

Когда слишком много состояний TIME_WAIT, вы также можете установитьtcp_tw_reuseиtcp_timestampsЕсли он равен 1, порт в состоянии TIME_WAIT будет повторно использоваться для новых подключений в качестве клиентов.Обратите внимание, что этот параметр применяется только к клиентам.

Пассивная боковая оптимизация

Ответ пассивно закрытого соединения очень прост: он переходит в состояние CLOSE_WAIT после ответа ACK, ожидая, пока процесс вызовет функцию закрытия для закрытия соединения. Поэтому при большом количестве подключений в состоянии CLOSE_WAIT проблема должна быть в приложении.

Когда пассивная сторона отправляет сообщение FIN, соединение переходит в состояние LAST_ACK.tcp_orphan_retriesПовторно отправьте сообщение FIN под контролем параметров.


03 Повышение производительности передачи данных TCP

В начале вводится стратегия оптимизации трехстороннего рукопожатия и четырехсторонней волны, а затем в основном вводится стратегия оптимизации передачи данных TCP.

Соединения TCP поддерживаются ядром, которое создает буферы памяти для каждого соединения:

  • Если конфигурация памяти соединения слишком мала, пропускная способность сети не может быть использована полностью, и эффективность передачи TCP будет снижена;
  • Если конфигурация памяти соединения слишком велика, можно легко исчерпать ресурсы сервера, что приведет к сбою установки нового соединения;

Поэтому мы должны понимать назначение TCP-памяти под Linux, чтобы правильно настроить размер памяти.

Как скользящее окно влияет на скорость передачи?

TCP гарантирует, что каждое сообщение может быть доставлено другой стороне.Его механизм таков: после того, как сообщение отправлено, он должен получить подтверждающее сообщение ACK, возвращенное другой стороной.Если оно не получено, оно повторно отправит сообщение через какое-то время. ., пока не будет получен ACK другой стороны.

Поэтому после отправки TCP-пакета он не будет сразу удален из памяти, потому что его нужно использовать для повторной передачи.

Поскольку TCP поддерживается ядром, пакеты сохраняются в буфере ядра. Если соединений очень много, мы можем наблюдать с помощью команды freebuff/cacheпамять увеличится.

Если TCP отправляет данные, он должен отправить ответ с подтверждением. Когда предыдущий пакет получил подтверждение, отправить следующий. Этот режим немного похож на то, как я общаюсь с вами лицом к лицу, вы говорите со мной, но недостатком этого метода является то, что он менее эффективен.

按数据包进行确认应答
Подтверждение пакетом

Поэтому такой способ передачи имеет недостаток:Чем больше время прохождения туда и обратно, тем менее эффективна коммуникация..

Эту проблему несложно решить, отправляя сообщения пакетами параллельно, а затем сразу же подтверждая сообщения пакетами.

并行处理
параллельная обработка

Однако это приводит к другому вопросу, может ли отправитель отправить сообщение так, как ему заблагорассудится?Конечно, это нереально, и мы должны учитывать вычислительную мощность приемника.

Когда оборудование получателя не так хорошо, как у отправителя, или когда система занята, а ресурсы ограничены, невозможно обработать такое количество пакетов за одно мгновение. Следовательно, эти пакеты можно только отбросить, что делает эффективность сети очень низкой.

Чтобы решить эту проблему, TCP предоставляет механизм, который позволяет «отправителю» контролировать количество отправляемых данных в соответствии с фактическими возможностями приема «получателя», который является источником скользящего окна.

По своему буферу получатель может рассчитать, сколько байтов сообщения может быть получено в будущем, это число называется окном приема. Когда ядро ​​получает сообщения, оно должно хранить их в буфере, чтобы оставшееся место в буфере стало меньше, а окно приема стало меньше; когда процесс вызывает функцию чтения, данные считываются в пространство пользователя, и ядро буфер очищается, что означает, что хост может принимать больше пакетов, и окно приема станет больше.

Следовательно, окно приема не является постоянным, и получатель поместит текущий допустимый размер в заголовок TCP-сообщения.поле окна, чтобы он мог играть роль уведомления о размере окна.

Эквивалентно ли окно отправителя окну получателя? Если управление перегрузкой не учитывается, размер окна отправителя «приблизительно равен» размеру окна получателя, поскольку существует задержка при передаче сообщения уведомления об окне по сети, поэтому она приблизительно равна.

TCP 头部
TCP-заголовок

Как видно из рисунка выше, поле окна имеет размер всего 2 байта, поэтому оно может отображать окно размером до 65535 байт, что составляет 64 КБ.

Этот максимальный размер окна явно недостаточен для современных высокоскоростных сетей. Так что есть способ расширить окно позже:Коэффициент расширения окна определяется в поле TCP option (опция), которое используется для расширения окна объявления TCP = 2^30), поэтому максимальное значение окна может достигать 1 ГБ в это время.

TCP option 选项 - 窗口扩展
Опция TCP - расширение окна

Чтобы включить эту функцию в Linux, вам нужно установить конфигурацию tcp_window_scaling в 1 (по умолчанию открыто):

Чтобы использовать опцию увеличения окна, обе стороны должны отправить эту опцию в своих соответствующих SYN-сообщениях:

  • Сторона, которая активно устанавливает соединение, отправляет эту опцию в сообщении SYN;
  • Сторона, пассивно устанавливающая соединение, может отправить эту опцию только после получения сообщения SYN с опцией расширения окна.

Таким образом, пока процесс может вовремя вызвать функцию чтения для чтения данных, а буфер приема настроен достаточно большим, окно приема может увеличиваться до бесконечности, а отправитель может увеличивать скорость отправки до бесконечности.

Это невозможно, поскольку пропускная способность сети ограничена.Когда отправитель отправляет пакеты, которые превышают пропускную способность сети в соответствии с окном отправки, маршрутизатор будет напрямую отбрасывать эти пакеты. Поэтому буферная память не чем больше, тем лучше.

Если определяется максимальная скорость передачи?

Ранее мы знали, что скорость передачи TCP зависит от окна отправки и окна приема, а также пропускной способности сетевого устройства. Среди них размер окна определяется размером буфера ядра. Использование буфера максимально, если буфер соответствует пропускной способности сети.

Вопрос в том, как рассчитать пропускную способность сети?

Я думаю, все знают, что сеть ограничена «пропускной способностью», которая описывает пропускную способность сети, которая отличается от единицы измерения буфера ядра:

  • Пропускная способность — это трафик в единицу времени, выраженный как «скорость», например, обычная пропускная способность 100 МБ/с;
  • Единицей буфера являются байты, и количество байтов можно получить, умножив скорость сети на время;

Здесь следует упомянуть концепцию произведения пропускной способности на задержку, которая определяет размер передаваемых пакетов в сети, и метод ее расчета:

Например, если максимальная пропускная способность составляет 100 МБ/с, а сетевая задержка (RTT) — 10 мс, это означает, что сеть от клиента до сервера может хранить в общей сложности 100 МБ/с * 0,01 с = 1 МБ байтов.

Этот 1 МБ является произведением пропускной способности и задержки, поэтому он называется «Продукт задержки пропускной способности» (сокращенно BDP, Продукт задержки пропускной способности). В то же время этот 1 МБ также представляет собой размер TCP-пакета «на лету», который находится на сетевых устройствах, таких как сетевые линии и маршрутизаторы. Если размер передаваемых пакетов превышает 1 МБ, сеть будет перегружена, и пакеты могут быть легко потеряны.

Так как размер буфера отправки определяет верхнюю границу окна отправки, а окно отправки определяет верхнюю границу "отправленных неподтвержденных" полетных сообщений. Следовательно, буфер отправки не может превышать «продукт задержки пропускной способности».

Связь между буфером отправки и произведением пропускной способности на задержку:

  • Если передающий буфер «превышает» произведение полосы пропускания на задержку, избыточная часть не может быть эффективно передана по сети, и в то же время сеть перегружается и пакеты легко теряются;
  • Если буфер отправки «меньше, чем» произведение полосы пропускания на задержку, эффективность передачи сети не может быть использована полностью.

Следовательно, размер буфера отправки предпочтительно должен быть близок к произведению пропускной способности на задержку.

Как настроить размер буфера?

И буфер отправки, и буфер приема можно настроить с помощью параметров в Linux. После настройки Linux продолжит работу в соответствии с установленным вами буфером.Динамическая регулировка.

Отрегулируйте диапазон буфера отправки

Давайте сначала посмотрим на буфер отправки, его диапазон настраивается параметром tcp_wmem;

Вышеупомянутые три числовые единицы - все байты, и они представляют:

  • Первое значение — минимальное значение динамического диапазона, 4096 байт = 4К;
  • Второе значение — исходное значение по умолчанию, 87380 байт ≈ 86 КБ;
  • Третье значение — максимальное значение динамического диапазона, 4194304 байта = 4096К (4М);

Буфер отправки самонастраивается, когда данные, отправленные отправителем, подтверждены, а новых данных для отправки нет, память буфера отправки будет освобождена.

Отрегулируйте диапазон буфера приема

Настройка приемного буфера более сложная, сначала рассмотрим параметр tcp_rmem, задающий диапазон приемного буфера:

Вышеупомянутые три числовые единицы - все байты, и они представляют:

  • Первое значение — это минимальное значение динамического диапазона, указывающее минимальный размер приемного буфера, который может быть гарантирован даже при нехватке памяти, 4096 байт = 4 КБ;
  • Второе значение — исходное значение по умолчанию, 87380 байт ≈ 86 КБ;
  • Третье значение — максимальное значение динамического диапазона, 6291456 байт = 6144К (6М);

Буфер приема может настроить окно приема в соответствии с размером свободной памяти системы:

  • Если в системе много свободной памяти, буфер может быть автоматически увеличен, так что окно приема другой стороне также станет больше, тем самым увеличив объем передаваемых данных, отправляемых отправителем;
  • В любом случае, если память системы очень мала, буфер будет уменьшен, хотя это снизит эффективность передачи, но может обеспечить нормальную работу большего количества одновременных соединений;

Автоматически включается функция настройки буфера отправки,Буфер приема должен настроить tcp_moderate_rcvbuf на 1, чтобы включить функцию настройки.:

Настройка диапазона памяти TCP

При получении корректировки буфера, как узнать, достаточно ли текущей памяти? Это делается через конфигурацию tcp_mem:

Вышеупомянутые три числовые единицы - это не байты, а "размер страницы", 1 страница означает 4 КБ, они соответственно означают:

  • Когда память TCP меньше первого значения, автоматическая настройка не требуется;
  • Между 1-м и 2-м значениями ядро ​​начинает корректировать размер приемного буфера;
  • Когда значение больше третьего значения, ядро ​​больше не будет выделять новую память для TCP, и в это время невозможно установить новое соединение;

Обычно эти значения рассчитываются при запуске системы на основе объема системной памяти. Согласно текущему максимальному количеству страниц памяти tcp_mem равно 177120, при размере памяти (177120*4)/1024К ≈ 692М система не сможет выделить память для новых TCP-соединений, то есть TCP-соединение будет отклоненный.

Стратегии корректируются в соответствии с реальными сценариями

На сервере с высокой степенью параллелизма, чтобы учесть скорость сети и большое количество одновременных подключений,Мы должны следить за тем, чтобы максимальное значение динамической подстройки буфера достигало произведения пропускной способности-задержки, а минимальное значение оставалось по умолчанию 4К. Для служб с ограниченным объемом памяти снижение значения по умолчанию является эффективным способом улучшения параллелизма.

Между тем, если это сервер типа сетевого ввода-вывода, то,Увеличение верхнего предела tcp_mem может позволить TCP-соединениям использовать больше системной памяти, что полезно для улучшения параллелизма.. Следует отметить, что единицей измерения tcp_wmem и tcp_rmem являются байты, а единицей измерения tcp_mem является размер страницы. и,Никогда не устанавливайте SO_SNDBUF или SO_RCVBUF непосредственно в сокете, это отключит функцию динамической настройки буфера.

резюме

В этом разделе содержится некоторое введение в то, как TCP оптимизирует передачу данных.

数据传输的优化策略
Стратегия оптимизации передачи данных

Надежность TCP достигается за счет сообщений подтверждения ACK, и он основан на скользящих окнах для повышения скорости отправки и учета возможностей обработки получателя.

Однако максимальное значение скользящего окна по умолчанию составляет всего 64 КБ, что не соответствует требованиям современной высокоскоростной сети.Если вы хотите увеличить скорость отправки, необходимо увеличить верхний предел скользящего окна.tcp_window_scalingсделано для 1, после чего максимальное значение может достигать 1 ГБ.

Скользящее окно определяет максимальное количество байтов передаваемых пакетов в сети. Когда оно превышает произведение пропускной способности на задержку, сеть перегружается и происходит потеря пакетов. Когда она меньше, чем произведение пропускной способности на задержку, полоса пропускания сети не может быть использована полностью. Следовательно, настройка скользящего окна должна относиться к произведению пропускной способности-задержки.

Буфер ядра определяет верхнюю границу скользящего окна.Буфер можно разделить на: буфер отправки tcp_wmem и буфер приема tcp_rmem.

Linux будет динамически регулировать буфер, мы должны установить верхний предел буфера на произведение пропускной способности-задержки. Функция настройки буфера отправки включается автоматически, а буфер приема необходимо включить, установив tcp_moderate_rcvbuf в 1. Среди них настройка основана на диапазоне памяти TCP tcp_mem.

Но следует отметить, что если в сокете в программе установлены SO_SNDBUF и SO_RCVBUF, функция динамической настройки буфера будет отключена, поэтому не рекомендуется их устанавливать в программе, а лучше оставить в ядро ​​для автоматической настройки.

Когда эти параметры настроены эффективно, параллелизм может поддерживаться в наибольшей степени, а скорость передачи соединения может быть максимальной при изобилии ресурсов.


плечи гигантов

[1] Настройка производительности системы должна быть известна. Тао Хуэй. Время компьютерщика.

[2] Колонка практики сетевого программирования, Шэн Яньминь, Geek Time.

[3] http://www.blogjava.net/yongboy/archive/2013/04/11/397677.html

[4] http://blog.itpub.net/31559359/viewspace-2284113/

[5] https://blog.51cto.com/professor/1909022

[6] https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux


болтовня болтовня

Расскажи всем грустную вещь.

Я думаю, что большинство моих друзей открыли его.Недавно официальный аккаунт был пересмотрен.Поток информации в учетной записи подписки больше не в хронологическом порядке, а отображается в соответствии с рекомендуемым алгоритмом.

Это для Кобаяши"Чжоу Гэн"Автор, действительно сильно ударил, очень недружелюбно.

Поскольку я давно не публиковал пост, официальный аккаунт может уменьшить вес рекомендации, что приведет к тому, что многие читатели не будут получать мои "последние" твиты.Если так будет продолжаться, не будут ли статьи Кобаяши игнорировать? (Держать и плакать...)

Кроме того, причина, по которой Кобаяши пишет уже давно, не в том, что он ленив.

Это значит «писать четче и рисовать четче», поэтому это неизбежно будет занимать все больше и больше времени.

Если вы узнали и вам понравилась статья Сяолиня и вы не хотите пропустить первый толчок статьи, вы можете пошевелить ручонками и поставить официальному аккаунту Сяолиня ""звезда".

Если все в порядке, просто пусть «Кодирование Сяо Линь» тихо лежит на дне вашей учетной записи подписки, но вы должны знать, что она не делает ничего в этот период, а усердно работает над подготовкой лучшего контента, и когда он будет готов, это, естественно, «выскочит» перед вами.

Кобаяши — человек-инструмент, созданный для всех. До свидания, увидимся в следующий раз!


Вопросы и ответы читателей

Читатель спросил: «Сяо Линь, задайте вопрос, относятся ли и somaxconn, и backlog к очереди принятия? Тогда somaxconn — это параметр ядра, а backlog — это периодическое изменение somaxconn через системные вызовы, такие как функция listen() в линукс?"

Наименьшее значение из двух — это очередь принятия.

Читатель спросил: «Сяо Линь, есть еще один вопрос: «Если очередь приема заполнена, то сервер отбрасывает подтверждение, отправленное клиентом», то есть TCP-соединение все еще находится в полузакрытом состоянии. -очередь соединений, она не отбрасывается?"

  1. Когда очередь приема заполнена, последующие новые входящие пакеты синхронизации будут потеряны.
  2. Примером всплеска трафика в моей статье является то, что когда соединение пришло, очередь приема не была заполнена, но во время третьего рукопожатия очередь приема внезапно оказалась заполненной, из-за чего подтверждение было бы отброшено и осталось в полузакрытом состоянии. очередь подключения.