задний план
Недавно при тестировании проекта обнаружилось странное явление: в тестовой среде среднее время вызова внутреннего HTTP-сервиса через Apache HttpClient было близко к 39,2 мс. Может быть, вы не считаете это нормальным на первый взгляд, что тут странного? На самом деле это не так. Позвольте мне рассказать вам некоторые основные сведения. Серверная HTTP-служба не имеет бизнес-логики. Она просто преобразует строку в верхний регистр и возвращает ее. Длина строки составляет всего 100 символов, а сеть задержка пинга составляет всего 1,9 мс. Поэтому по идее время звонка должно быть в районе 2-3мс, но почему в среднем 39,2мс?
По рабочим причинам проблема долгих вызовов меня не удивляет, я часто помогаю бизнесу решать проблемы, связанные с таймаутом внутренних вызовов RPC framework, но HTTP-вызовы занимают много времени впервые. Тем не менее, процедура устранения неполадок такая же. Основная методология есть не что иное, как методы исследования «снаружи внутрь», «сверху вниз» и другие. Давайте сначала взглянем на некоторые периферийные индикаторы, чтобы посмотреть, сможем ли мы найти какие-либо подсказки.
Периферийные индикаторы
Системные показатели
В основном смотрите на некоторые индикаторы периферийной системы (примечание: должны быть видны и вызывающая, и вызываемая машины). Например, нагрузка, ЦП. Все, что нужно, это одна команда сверху, чтобы получить обзор.
Следовательно, подтверждается, что ЦП и нагрузка простаивают. Поскольку на тот момент скриншотов не было, я не буду размещать здесь картинку.
индикатор прогресса
Индикаторы процесса программы Java в основном смотрят на состояние GC и стека потоков (примечание: необходимо смотреть как на вызывающую, так и на вызываемую машину).
Молодых GC очень мало, и они занимают менее 10 мс, поэтому нет длинных STW.
Поскольку среднее время вызова составляет 39,2 мс, что является относительно большим, если затраты времени вызваны кодом, стек потоков должен быть в состоянии что-то найти. Прочитав его, я ничего не нашел.Связанный стек потоков сервиса в основном показывает, что потоки пула потоков ждут задач, а это означает, что потоки не заняты.
Вы чувствуете, что у вас заканчиваются навыки, что делать дальше?
местное воспроизведение
Если локальная (локальная система MAC) может воспроизводиться, это также отлично подходит для устранения неполадок.
Поэтому я написал простую тестовую программу локально с помощью Apache HttpClient и напрямую вызвал внутренний HTTP-сервис.Обнаружилось, что среднее время составило около 55 мс. Эй, почему это немного отличается от результата 39,2 мс в тестовой среде. Основная причина заключается в том, что компьютеры HTTP-сервера в локальной и тестовой средах являются межрегиональными, а задержка проверки связи составляет около 26 мс, поэтому задержка увеличивается. Однако локально проблемы действительно есть, потому что задержка пинга составляет 26 мс, а логика серверного HTTP-сервиса проста и почти не требует времени, поэтому среднее время, затрачиваемое на локальные вызовы, должно быть около 26 мс. ?
Разве не запутался, запутался, я не знаю, как начать?
В течение этого периода я задавался вопросом, используется ли Apache HttpClient неправильно, поэтому я написал простую программу, используя HttpURLConnection, который поставляется с JDK, и протестировал ее, и результат был таким же.
диагноз
должность
Фактически, с точки зрения показателей периферической системы, показателей процесса и местного рецидива можно сделать грубый вывод, что это не процедурная причина. А как насчет уровня протокола TCP?
Учащиеся, имеющие опыт сетевого программирования, должны знать, какие параметры TCP вызывают это явление. Да, вы правильно догадались, TCP_NODELAY.
Какая программа вызывающего абонента и Callee не устанавливается?
Вызывающий использует Apache HttpClient, а для tcpNoDelay по умолчанию установлено значение true. Давайте взглянем на callee, который является нашей серверной HTTP-службой.Эта HTTP-служба использует HttpServer, поставляемый с JDK.
HttpServer server = HttpServer.create(new InetSocketAddress(config.getPort()), BACKLOGS);
Прямой настройки интерфейса tcpNoDelay я не видел, поэтому полистал исходники. О, оказывается, здесь есть этот статический блок в классе ServerConfig для получения параметров запуска, по умолчанию ServerConfig.noDelay имеет значение false.
static {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServerConfig.idleInterval = Long.getLong("sun.net.httpserver.idleInterval", 30L) * 1000L;
ServerConfig.clockTick = Integer.getInteger("sun.net.httpserver.clockTick", 10000);
ServerConfig.maxIdleConnections = Integer.getInteger("sun.net.httpserver.maxIdleConnections", 200);
ServerConfig.drainAmount = Long.getLong("sun.net.httpserver.drainAmount", 65536L);
ServerConfig.maxReqHeaders = Integer.getInteger("sun.net.httpserver.maxReqHeaders", 200);
ServerConfig.maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime", -1L);
ServerConfig.maxRspTime = Long.getLong("sun.net.httpserver.maxRspTime", -1L);
ServerConfig.timerMillis = Long.getLong("sun.net.httpserver.timerMillis", 1000L);
ServerConfig.debug = Boolean.getBoolean("sun.net.httpserver.debug");
ServerConfig.noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay");
return null;
}
});
}
проверять
В серверной службе HTTP добавьте параметр «-Dsun.net.httpserver.nodelay=true» и повторите попытку. Эффект очевиден, среднее время сокращается с 39,2 мс до 2,8 мс.
Проблема решаема, но если останавливаться на достигнутом, то это слишком дешево в данном случае, пустая трата денег. Потому что вас еще ждет много сомнений?
-
Почему добавление TCP_NODELAY уменьшает задержку с 39,2 мс до 2,8 мс?
-
Почему средняя задержка локальных тестов составляет 55 мс вместо 26 мс для пинга?
-
Как протокол TCP отправляет пакеты?
Давай, куй железо жаром.
решить путаницу
TCP_NODELAY Кто это?
В программировании сокетов параметр TCP_NODELAY используется для управления включением алгоритма Нагла. В Java значение true отключает алгоритм Нейгла, а значение false включает алгоритм Нейгла. Вы должны спросить, что такое алгоритм Нэгла?
Что, черт возьми, алгоритм Нагле?
Алгоритм Нэгла — это метод повышения эффективности сети TCP/IP за счет уменьшения количества пакетов, отправляемых по сети. Он назван в честь его изобретателя Джона Нэгла, который впервые применил алгоритм в 1984 году, чтобы попытаться решить проблему перегрузки сети в Ford Motor Company.
Представьте себе, что если приложение генерирует 1 байт данных за раз, а затем этот 1 байт данных отправляется на удаленный сервер в виде сетевых пакетов, то легко вызвать перегрузку сети слишком большим количеством пакетов. В этом типичном случае отправка пакета только с 1 байтом достоверных данных требует дополнительных накладных расходов в виде заголовка длиной 40 байт (т. е. 20 байтов для заголовка IP + 20 байтов для заголовка TCP) Использование этой полезной нагрузки чрезвычайно мало.
Содержание алгоритма Нэгла относительно простое, следующий псевдокод:
if there is new data to send
if the window size >= MSS and available data is >= MSS
send complete MSS segment now
else
if there is unconfirmed data still in the pipe
enqueue data in the buffer until an acknowledge is received
else
send data immediately
end if
end if
end if
Конкретный подход:
-
Если отправляемый контент больше или равен 1 MSS, отправьте его немедленно;
-
Если нет предыдущего пакета не ACK, передается немедленно;
-
Если есть пакет, который ранее не был подтвержден, кэш отправляет содержимое;
-
Если получен ACK, кэшированное содержимое отправляется немедленно. (MSS — это самый большой сегмент данных, который TCP-пакет может передать за раз)
Что такое отложенный ACK?
Всем известно, что для обеспечения надежности передачи в протоколе TCP предусмотрено, что подтверждение должно быть отправлено другой стороне при получении пакета данных. Просто отправка подтверждения обходится дорого (заголовок IP 20 байт + заголовок TCP 20 байт).TCP Delayed ACK (отложенное подтверждение) — это попытка улучшить производительность сети для решения этой проблемы.Он объединяет несколько ответов ACK в один ответ или отправляет ответ ACK вместе с данными ответа другой стороне, тем самым уменьшая накладные расходы протокола..
Конкретный подход:
-
Когда есть данные ответа для отправки, ACK будет отправлено другой стороне немедленно с данными ответа;
-
Если нет данных ответа, ACK будет задержан, чтобы увидеть, могут ли какие-либо данные ответа быть отправлены вместе. В системах Linux время задержки по умолчанию составляет 40 мс;
-
Если второй пакет данных другой стороны поступает во время ожидания отправки ACK, ACK следует отправить немедленно. Но если три других пакета данных прибывают последовательно, следует ли отправлять ACK сразу после прибытия третьего сегмента данных, зависит от двух вышеуказанных.
Какова химия Nagle с Delayed ACK?
И Nagle, и Delayed ACK могут повысить эффективность передачи по сети, но вместе они будут делать плохие вещи с добрыми намерениями. Например, следующий сценарий:
A и B для передачи данных: A запускает алгоритм Nagle, B запускает алгоритм Delayed ACK.
Если A отправляет пакет B, B не ответит немедленно из-за задержки ACK. И A использует алгоритм Nagle, A всегда будет ждать ACK от B, ACK не придет и не отправит второй пакет данных.Если два пакета данных отвечают на один и тот же запрос, запрос будет задержан на 40 мс. .
Бери сумку и играй
Давайте захватим пакет для проверки. Выполните следующий скрипт на серверной службе HTTP, чтобы легко завершить процесс захвата пакета.
sudo tcpdump -i eth0 tcp and host 10.48.159.165 -s 0 -w traffic.pcap
Как показано на рисунке ниже, это отображение содержимого пакета анализа с использованием Wireshark. Красное поле — это полный процесс обработки POST-запроса. Посмотрите на разницу между серийным номером 130 и серийным номером 149 на 40 мс (0,1859 - 0,1448 = 0,0411 с = 41 мс), это Nagle и химия Delayed ACK, отправленные вместе, где 10.48.159.165 работает с Delayed ACK, а 10.22.29.180 работает с алгоритмом Nagle. 10.22.29.180 ожидает ACK, а 10.48.159.165 запускает Delayed ACK, что составляет глупые 40 мс.
Это также объясняет, почему тестовая среда занимает 39,2 мс, потому что большинство из них задерживаются на 40 мс Delayed ACK..
Но при воспроизведении локально, почему средняя задержка местных испытаний 55 мс вместо 26 мс для пинга? Давайте тоже схватим сумку.
Как показано на рисунке ниже, красное поле представляет собой завершенный процесс обработки POST-запроса.Разница между серийным номером 8 и серийным номером 9 составляет около 25 мс, а сетевая задержка составляет примерно половину задержки ping, которая составляет около 13 мс. , поэтому Delayed Ack составляет около 12 мс (из-за задержки).Локальная система - это MAC-система, а Linux имеет некоторые отличия).
- Linux использует системную конфигурацию /proc/sys/net/ipv4/tcp_delack_min для управления временем отложенного ACK.Linux по умолчанию 40 мс;
- MAC управляет отложенным подтверждением через системную конфигурацию net.inet.tcp.delayed_ack.
delayed_ack=0 responds after every packet (OFF)
delayed_ack=1 always employs delayed ack, 6 packets can get 1 ack
delayed_ack=2 immediate ack after 2nd packet, 2 packets per ack (Compatibility Mode)
delayed_ack=3 should auto detect when to employ delayed ack, 4packets per ack. (DEFAULT)
Установите 0, чтобы отключить отложенный ACK, установите 1, чтобы всегда задерживать ACK, установите 2, чтобы отвечать ACK каждые два пакета данных, и установите 3, чтобы автоматически определять время ответа ACK.
Почему TCP_NODELAY решает проблему?
TCPNODELAY отключает алгоритм Nagle, даже если ACK предыдущего пакета не приходит, он отправит следующий пакет, тем самым сломав влияние Delayed ACK. Как правило, в сетевом программировании настоятельно рекомендуется открывать TCPNODELAY для повышения скорости отклика.
Конечно, проблему можно решить и настройкой системы, связанной с Delayed ACK, но изменять конфигурацию машины очень неудобно, поэтому этот метод не рекомендуется.
Суммировать
Эта статья представляет собой процесс устранения неполадок, вызванных простым HTTP-вызовом с относительно большой задержкой. При этом соответствующие проблемы сначала анализируются снаружи внутрь, а затем обнаруживается проблема и проверяется решение. Наконец, я дал исчерпывающее объяснение Nagle и Delayed ACK при передаче TCP и более тщательно проанализировал проблемный случай.
Прочитав три вещи ❤️
Если вы считаете, что этот контент очень полезен для вас, я хотел бы пригласить вас сделать мне три небольших одолжения:
-
Лайки, репосты и ваши "лайки и комментарии" - движущая сила моего творчества.
-
Обратите внимание на общедоступный номер 『яванская гнилая свиная кожа’, время от времени делясь оригинальными знаниями.
-
В то же время вы можете рассчитывать на последующие статьи🚀
Добавить Автора
Источник:club.perf.com/article/200…