Почему повторная передача TCP останавливает обмен с промышленной камерой и как это диагностировать
· Обновлено: · Го Комура · TCP, Сети, Расследование сбоев, Разработка Windows, Промышленная камера
История изменений (2 обновлений, последнее 30 Aug 2026)
Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.
- Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
- Исправлена ошибка отображения: строки с вертикальной чертой выводились как таблица, из-за чего справочные ссылки нельзя было нажать. Текст статьи не изменился.
- Первая публикация
Цитирование статьи(DOI: 10.5281/zenodo.21619649)
Статья заархивирована на Zenodo. Ниже приведены DOI, который всегда ведёт к последней версии, и DOI, закреплённый за версией, которую вы читаете.
Го Комура (2026). Почему повторная передача TCP останавливает обмен с промышленной камерой и как это диагностировать. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21619649 https://comcomponent.com/ru/blog/2026/03/11/001-tcp-retransmission-rfc1323-industrial-camera/
- DOI (последняя версия)
- 10.5281/zenodo.21619649
- DOI (эта версия)
- 10.5281/zenodo.21619650
В обмене с промышленными камерами и в управлении оборудованием самое неприятное — когда в среднем всё быстро, но изредка на несколько секунд всё останавливается. Воспроизводимость низкая, обычно ничего не происходит, и по очереди начинают казаться подозрительными UI, потоки, GC, SDK камеры, сетевая карта, коммутатор — буквально всё.
Речь о случае, когда TCP-обмен между приложением управления промышленной камерой и хостом изредка останавливался на несколько секунд. Разбираясь, мы увидели, что приложение не зависало: это было ожидание повторной передачи TCP после потери пакета. В этой системе включение меток времени семейства RFC1323 (в действующей редакции — RFC 7323) позволило свести это ожидание к минимуму.
Имена устройств, конфигурация и цифры обобщены, но сам подход применим на практике как есть.
Содержание
- Сначала вывод (в двух словах)
- Как выглядел симптом
- 2.1. Приложение живо, а ответ на несколько секунд пропадает
- 2.2. Из-за низкой частоты по одним логам это плохо видно
- Что происходило (схема)
- 3.1. От потери пакета к ожиданию повторной передачи
- 3.2. Остановки на секунды совпадали по форме с RTO
- На что смотрели при расследовании
- 4.1. Сначала исключаем причины остановки внутри приложения
- 4.2. Подтверждаем повторную передачу по захвату пакетов
- 4.3. Смотрим, какие опции TCP были согласованы
- Почему здесь помогают метки времени RFC1323
- 5.1. Метки времени нужны для RTTM и PAWS
- 5.2. Можно снять неоднозначность измерения RTT при повторной передаче
- 5.3. Почему в этом случае удалось сократить ожидание
- Что сделали на практике
- 6.1. Включаем метки времени
- 6.2. Проверяем TSopt в SYN / SYN-ACK
- 6.3. Куда смотреть, если всё равно не помогает
- На что смотреть в Wireshark
- Как выбирать (кратко)
- Итог
- Справочные материалы
Карта знаний этой статьи
Статья разбирает, почему в приложении управления промышленной камерой связь изредка останавливается всего на несколько секунд. Причиной была не остановка приложения, а ожидание повторной передачи: из-за потери пакетов ACK не возвращался, и TCP ждал истечения таймера повторной передачи (RTO). RTO удваивается при каждом отказе, отталкиваясь от начального значения в 1 секунду, и в плохих условиях это выглядит как остановка на несколько секунд. Включение опции TCP timestamps (RFC 1323 / RFC 7323) снимает ограничение алгоритма Karn — не измерять RTT по сегменту, который уже был повторно передан, — и сокращает время, пока RTO остаётся чрезмерно консервативным, но само по себе не устраняет потерю пакетов. Основа разбора — проверка повторных передач и времени ожидания в Wireshark и подтверждение согласования TSopt в SYN/SYN-ACK.
flowchart LR
accTitle: Карта знаний: повторная передача TCP и временные метки RFC 1323
accDescr: Схема, которая показывает, как потеря пакетов вызывает повторную передачу TCP и ожидание RTO, выглядящее как остановка связи на несколько секунд; как опция TCP timestamps снимает ограничение алгоритма Karn и уменьшает неоднозначность измерения RTT при повторной передаче; и связь с процедурой проверки в Wireshark
tcp_retransmission["повторная передача TCP (Retransmission)"]
tcp_rto["RTO (таймер повторной передачи)"]
tcp_timestamps_option["опция TCP Timestamps"]
packet_loss["потеря пакетов"]
tcp_rtt["RTT (время кругового обхода)"]
intermittent_communication_stall["прерывистые остановки связи на несколько секунд"]
wireshark["Wireshark"]
rttm["RTTM (измерение RTT)"]
paws["PAWS (защита от обёртывания sequence number)"]
karn_algorithm["алгоритм Карна (Karn)"]
retransmission_rtt_ambiguity["неоднозначность RTT при повторной передаче"]
fast_retransmit["fast retransmit"]
duplicate_ack["Duplicate ACK"]
tcp_handshake["трёхстороннее рукопожатие TCP"]
windows_tcp_timestamp_setting["настройка TCP timestamps в Windows"]
packet_loss -->|"может вызвать"| tcp_retransmission
tcp_retransmission -.->|"требует"| tcp_rto
tcp_rto -->|"использует"| tcp_rtt
tcp_retransmission -->|"может вызвать"| intermittent_communication_stall
intermittent_communication_stall -->|"проверяется"| wireshark
tcp_retransmission -->|"проверяется"| wireshark
packet_loss -->|"проверяется"| wireshark
tcp_timestamps_option -->|"использует"| rttm
tcp_timestamps_option -->|"использует"| paws
karn_algorithm -->|"снижает"| retransmission_rtt_ambiguity
tcp_timestamps_option -->|"снижает"| retransmission_rtt_ambiguity
tcp_timestamps_option -.->|"снижает"| intermittent_communication_stall
fast_retransmit -.->|"предотвращает"| tcp_rto
fast_retransmit -->|"требует"| duplicate_ack
packet_loss -->|"может вызвать"| duplicate_ack
tcp_timestamps_option -->|"требует"| tcp_handshake
tcp_timestamps_option -.->|"настраивается"| windows_tcp_timestamp_setting
windows_tcp_timestamp_setting -->|"проверяется"| wireshark
tcp_rto -->|"использует"| karn_algorithm
На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 19, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle
1. Сначала вывод (в двух словах)
- TCP-обмен, который изредка останавливается на несколько секунд, иногда объясняется не зависанием приложения, а ожиданием повторной передачи после потери пакета
- Если в захвате пакетов видна
Retransmissionи большой разрыв по времени, а длительность остановки совпадает с тем, как ведёт себя ожидание RTO, версия становится весьма правдоподобной - Опция TCP timestamps — механизм для измерения RTT и для PAWS; она же снимает неоднозначность измерения RTT при повторной передаче
- В этом случае включение меток времени семейства RFC1323 сократило время, пока оценка RTO оставалась устаревшей и излишне консервативной, и остановки на секунды удалось свести к минимуму
- Но это не волшебство, которое устраняет саму потерю. Физический уровень, сетевую карту, коммутатор, промежуточное оборудование, драйверы и проектирование буферов всё равно нужно разбирать отдельно
Иначе говоря, если за «изредка останавливается на несколько секунд» стоит ожидание внутри TCP, одни лишь доработки повторов на стороне приложения бьют мимо. Быстрее сначала посмотреть на wire и установить, идёт ли речь об ожидании повторной передачи.
flowchart TB
accTitle: Ход вывода этой статьи
accDescr: Редкий многосекундный простой TCP-обмена сначала подтверждают по wire как ожидание повторной передачи; если это оно, timestamps иногда сокращают ожидание, но источник потерь пакетов всё равно исследуют отдельно.
sym["TCP-обмен изредка останавливается на секунды"] --> wire["сначала смотрим на wire"]
wire --> conf["устанавливаем, это ли ожидание повторной передачи"]
conf -.-> ts["timestamps иногда сокращают ожидание"]
conf -.-> loss["источник потерь исследуют отдельно"]
Рис. 1: Прежде чем наращивать повторы в приложении, по wire находят, где именно идёт ожидание.
Дальше в тексте подряд пойдут сокращения TCP. Для разработчиков Windows, у которых сеть не основная специальность, сводка ниже. Если зафиксировать её, дальше текст не должен спотыкаться.
| Термин | Полное имя | Смысл |
|---|---|---|
| ACK | Acknowledgment | Подтверждение. Сообщает собеседнику: «до сюда дошло» |
| RTT | Round-Trip Time | Время кругового пути. От отправки до возврата ACK |
| RTO | Retransmission Timeout | Таймер повторной передачи. Если за это время ACK не вернулся, данные отправляют снова. Считается по оценке RTT |
| RTTM | Round-Trip Time Measurement | Измерение RTT. Одна из целей меток времени |
| PAWS | Protect Against Wrapped Sequences | Защита от оборота номера последовательности. Вторая цель меток времени |
| TSopt | TCP Timestamps Option | Одна из опций заголовка TCP. Тип 8, длина 10 байт, несёт два значения ниже |
| TSval | Timestamp Value | Значение часов отправителя, которое он сам кладёт в сегмент |
| TSecr | Timestamp Echo Reply | Поле, в котором полученный TSval возвращают как есть. По нему видно, на какую отправку пришёл ACK |
| SACK | Selective Acknowledgment | Механизм, которым получатель по отдельности сообщает, какие диапазоны он уже принял |
| Dup ACK | Duplicate ACK | Повторный ACK на тот же номер последовательности. Признак, что по пути есть пробел |
| fast retransmit | — | Повторная отправка, не дожидаясь истечения RTO, когда накопилось достаточно Dup ACK. В Windows по умолчанию: «приняты 3 ACK на один и тот же номер последовательности (первый и ещё два дубля)» |
| Алгоритм Карна | — | Правило: с повторно отправленного сегмента RTT-выборку брать нельзя. Неясно, на какую из отправок пришёл ACK |
2. Как выглядел симптом
2.1. Приложение живо, а ответ на несколько секунд пропадает
Первое, что путает картину, — приложение в целом не выглядит зависшим.
- UI не мёртв полностью
- процесс не упал
- CPU не прибит к потолку
- но ответ на команды управления камерой изредка пропадает на несколько секунд
Такой симптом трудно отличить от deadlock или бесконечного цикла внутри приложения. В управлении оборудованием одна остановка на несколько секунд сразу ощущается как остановка линии. Даже если средние цифры выглядят чисто, на площадке это воспринимается заметно хуже.
2.2. Из-за низкой частоты по одним логам это плохо видно
Неприятность таких дефектов — в низкой частоте. Раз в час, раз в полдня, только когда совпали условия — примерно так это себя ведёт.
Если идти только по логам, обычно получается так.
- в логе приложения всё обрывается на «отправили» / «ответ не пришёл»
- в логе принимающей стороны выглядит как «ничего не приходило»
- в тот же интервал случайно происходит другое событие, и список подозреваемых расползается
Пытаться восстановить причинную связь только по логам приложения в такой ситуации легко заводит в тупик. Быстрее спуститься на уровень обмена.
flowchart TB
accTitle: Почему по одним логам виновник не определяется
accDescr: Лог приложения обрывается на «отправили, ответа нет», лог приёмника выглядит как «ничего не приходило», а другие события того же интервала размывают список подозреваемых. Поэтому причинную связь не восстанавливают по одним логам приложения, а спускаются на уровень обмена.
l1["лог приложения: отправили, ответа нет"] --> lost["подозреваемые расходятся, ход теряется"]
l2["лог приёмника: ничего не приходило"] --> lost
l3["другие события того же интервала"] -.-> lost
lost --> down["спускаемся на уровень обмена"]
Рис. 2: Редкую остановку по одним логам легко потерять. По пакетам это видно быстрее.
3. Что происходило (схема)
3.1. От потери пакета к ожиданию повторной передачи
Цепочка в этом случае простая. Где-то по пути терялся пакет, отправитель ждал ACK, тот не приходил, поэтому отправитель ждал истечения RTO и лишь затем повторял отправку.
sequenceDiagram
participant Host as приложение на хосте
participant Net as сеть
participant Cam as сторона камеры
Host->>Net: команда управления (Seq=N)
Note over Net: здесь потеря
Note over Host: ACK не приходит, поэтому ждём
Note over Host: восстановление этого запроса требует ожидания RTO
Host->>Net: повторная отправка команды управления
Net->>Cam: повторный пакет доходит
Cam-->>Net: ACK
Net-->>Host: ACK
Note over Host: здесь обмен возобновляется
Рис. 3: Если пакет теряется, ACK не возвращается, и повторная отправка идёт только после истечения RTO. Приложению этот интервал виден как «остановка на несколько секунд».
Со стороны приложения это выглядит как «остановка на несколько секунд», но с точки зрения TCP это просто «ACK ещё не пришёл, поэтому мы ждали истечения таймера повторной передачи». Неэффектно, но такая форма остановки встречается часто.
Управляющий обмен в этом случае состоял в основном из небольших request/response, и за один обмен в полёте не оказывалось большого объёма неподтверждённых данных. Поэтому в такой конфигурации ожидание RTO чаще выходило на первый план раньше, чем набиралось достаточно duplicate ACK для fast retransmit.
flowchart TB
accTitle: Почему в управляющем обмене на первый план выходит ожидание RTO
accDescr: В управляющем обмене из небольших request/response мало неподтверждённых данных, duplicate ACK не успевают накопиться, fast retransmit срабатывает редко, и в результате на первый план выходит ожидание RTO.
small["в основном небольшие request/response"] --> few["мало неподтверждённых данных"]
few --> nodup["Dup ACK не успевают накопиться"]
nodup --> nofr["fast retransmit срабатывает редко"]
nofr --> rto["на первый план выходит ожидание RTO"]
Рис. 4: В отличие от потока с большим объёмом данных, потеря в управляющем обмене чаще заканчивается ожиданием истечения RTO.
3.2. Остановки на секунды совпадали по форме с RTO
Ожидание повторной передачи TCP, хотя и зависит от реализации, ведёт себя консервативно. По RFC 6298 начальный RTO принимают за 1 секунду: если расчёт дал меньше, значение поднимают до 1 секунды, а при каждом тайм-ауте удваивают.
flowchart LR
A[потеря пакета] --> B[ACK не приходит]
B --> C[ожидание RTO]
C --> D[повторная отправка]
D --> E{ACK вернулся?}
E -- да --> F[обмен возобновляется]
E -- нет --> G[RTO удваивается]
G --> C
Рис. 5: RTO удваивается каждый раз, когда ACK не возвращается. Ожидание 1 с, 2 с, 4 с следует из этой формы.
Поэтому даже там, где хотелось бы уложиться в сотни миллисекунд, при неблагоприятных условиях ожидание может выглядеть как 1, 2, 4 секунды. «Изредка останавливается на несколько секунд» в этом случае довольно прямо совпало именно с такой формой.
4. На что смотрели при расследовании
4.1. Сначала исключаем причины остановки внутри приложения
Не бросаясь сразу обвинять TCP, сначала исключили типичные причины на стороне приложения.
| Что проверяли | Зачем смотрели | Вывод в этом случае |
|---|---|---|
| UI-поток / рабочие потоки | Проверка зависания и взаимного ожидания | Не была основной причиной |
| Загрузка CPU | Проверка задержки обработки из-за высокой нагрузки | Даже во время остановок CPU не был прибит к потолку |
| GC / давление по памяти | Проверка пауз | Форма длительности остановок не совпадала |
| Вызовы SDK камеры | Проверка ожиданий внутри SDK | Не совпадало с задержкой на wire |
| Захват пакетов | Проверка повторной передачи на уровне обмена | Здесь и обозначилась причина |
Важно не назначать виновного только по времени в логе приложения. В приложении управления оборудованием ожидание на верхнем уровне иногда просто отражает ожидание ниже.
flowchart TB
accTitle: Порядок диагностики: сначала исключаем причины внутри приложения
accDescr: TCP не назначают виновным сразу. Сначала исключают типичные причины остановки внутри приложения — потоки, CPU, GC, SDK камеры — и только потом по захвату пакетов подтверждают повторную передачу на уровне обмена.
app["сначала исключаем потоки, CPU, GC, SDK"] --> cap["смотрим уровень обмена по захвату пакетов"]
cap --> found["проступает цепочка повторной передачи"]
app -.-> warn["не назначаем виновного только по времени в логе"]
Рис. 6: Без заранее выбранного виновного. Сначала снимают типичные причины внутри приложения, затем спускаются на wire.
4.2. Подтверждаем повторную передачу по захвату пакетов
В захвате пакетов в интервале остановки было видно TCP Retransmission, а непосредственно перед этим — что ACK не возвращался.
Смотреть стоит примерно на следующее.
- появляется ли повторная отправка с тем же
Seq - совпадает ли разрыв по времени до повторной отправки с длительностью остановки
- похоже ли это на ожидание истечения RTO, а не на
Dup ACKилиFast Retransmission - проявляется ли проблемное соединение каждый раз в одном и том же
tcp.stream
Если это сходится, версия «TCP ждёт повторной передачи», а не «приложение зависло», становится заметно весомее.
flowchart TB
accTitle: Что подтверждает ожидание повторной передачи
accDescr: Если сходятся три точки — повторная отправка с тем же Seq, разрыв по времени совпадает с длительностью остановки, картина похожа на ожидание истечения RTO, а не на fast retransmission — версия «это не зависание приложения, а ожидание повторной передачи TCP» становится заметно весомее.
c1["есть ли повторная отправка с тем же Seq"] --> conc["TCP ждёт повторной передачи"]
c2["совпадает ли разрыв с длительностью остановки"] --> conc
c3["похоже ли на ожидание истечения RTO"] --> conc
conc -.-> not["это не зависание приложения"]
Рис. 7: Если эти три точки сходятся, версия «не зависание приложения, а ожидание повторной передачи TCP» становится весьма правдоподобной.
4.3. Смотрим, какие опции TCP были согласованы
Следующее, на что посмотрели, — SYN / SYN-ACK при установлении соединения. Метки времени согласовываются в трёхстороннем рукопожатии TCP, поэтому если TSopt там не появляется, на этом соединении они не используются.
sequenceDiagram
participant Host as хост
participant Cam as сторона камеры
Host->>Cam: SYN + TSopt ?
Cam-->>Host: SYN/ACK + TSopt ?
Host->>Cam: ACK
Note over Host,Cam: только после согласования здесь TSopt можно использовать в последующих сегментах
Рис. 8: Метки времени согласовываются в трёхстороннем рукопожатии. Если в SYN / SYN-ACK нет TSopt, на этом соединении они не используются.
Если трогать настройки ОС, не посмотрев на это, легко получить ещё одну тихую ошибку: «вроде бы включил, а не работает». Факт на wire весомее значения в настройках.
5. Почему здесь помогают метки времени RFC1323
На практике название «метки времени RFC1323» всё ещё в ходу, хотя действующая редакция — RFC 7323. В этой статье мы, следуя обычаю, пишем RFC1323 и имеем в виду опцию TCP timestamps.
5.1. Метки времени нужны для RTTM и PAWS
Опция timestamps в TCP используется в основном для двух целей.
- RTTM (Round-Trip Time Measurement)
- PAWS (Protect Against Wrapped Sequences)
В этом случае сработала сторона RTTM. Отправив сегмент со значением TSval, отправитель получает его обратно в поле TSecr ACK, и за счёт этого может измерять RTT чаще и точнее.
flowchart TB
accTitle: Две цели опции timestamps
accDescr: Опция TCP timestamps служит двум целям — RTTM, то есть измерению времени кругового пути, и PAWS, то есть защите от оборота номера последовательности. В этом случае сработала сторона RTTM.
tso["timestamps option"] --> rttm["RTTM (измерение времени кругового пути)"]
tso --> paws["PAWS (защита от оборота номера последовательности)"]
rttm --> hit["в этом случае сработала эта сторона"]
rttm -.-> how["измеряют, возвращая TSval в TSecr ACK"]
Рис. 9: У меток времени две цели: RTTM и PAWS. В этом случае сработала сторона измерения RTT.
5.2. Можно снять неоднозначность измерения RTT при повторной передаче
Когда идёт повторная отправка, без меток времени возникает неоднозначность: «этот ACK относится к первой отправке или к повторной?» Именно об этом беспокоится так называемый алгоритм Карна.
RFC 6298 говорит, что с повторно отправленного сегмента RTT-выборку брать нельзя: непонятно, на какую именно отправку пришёл ACK. Но если есть опция timestamps, эту неоднозначность можно снять. По TSecr в ACK видно, какой сегмент с каким TSval дошёл.
sequenceDiagram
participant Host as отправитель
participant Cam as получатель
Host->>Cam: Seq=N, TSval=1000
Note over Host,Cam: этот сегмент теряется
Note over Host: ACK не приходит, поэтому ждём
Host->>Cam: повторно отправляем Seq=N, TSval=2000
Cam-->>Host: ACK, TSecr=2000
Note over Host: можно определить, на какую отправку это ответ
Рис. 10: По TSecr видно, отвечает этот ACK на первую отправку или на повторную.
Именно в этом суть улучшения в этом случае.
5.3. Почему в этом случае удалось сократить ожидание
В этом случае потери пакетов возникали время от времени, и каждый раз это склоняло оценку RTT / RTO к консервативной стороне. Если включить метки времени, оценку RTT проще обновлять и в сценариях с повторной передачей, и можно сократить время, пока оценка RTO продолжает расти, оставаясь устаревшей.
Здесь легко сделать скачок в рассуждении, поэтому разберём аккуратнее.
Сначала: нижняя граница RTO от наличия меток времени не меняется. RFC 6298 говорит: если рассчитанный RTO меньше 1 секунды, его следует поднять до 1 секунды. У реализации может быть и своя нижняя граница; в Windows это MinRtoMs в выводе Get-NetTCPSetting (диапазон 20–300 мс с шагом 10 мс). То есть «включили метки времени — и нижняя граница стала меньше» — нет.
Работает предыдущий шаг. RFC 6298 фиксирует три вещи.
- При каждом истечении таймера повторной передачи RTO удваивают (экспоненциальный backoff)
- Удвоенный RTO возвращается к исходному, когда получено новое измерение RTT
- Это «новое измерение RTT» можно взять только когда отправили данные без повторной передачи и на них пришёл ACK
Плюс алгоритм Карна: с повторно отправленного сегмента RTT-выборку брать нельзя. Но это ограничение снимается, если используется опция timestamps. Как в 5.2, по TSecr можно определить, на какую отправку пришёл ACK.
Если выстроить это в ряд, цепочка становится видна. В системе с разрозненными потерями без меток времени условия 2 и 3 долго не сходятся, и время, пока удвоенный RTO не вернётся по фактическому измерению, остаётся длинным. Если в этом состоянии приходит следующая потеря, ожидание начинается не с 1 секунды, а с 2 или 4. С метками времени можно измерить заново и на участке с повторной передачей, поэтому это «время, когда вернуться нельзя» становится короче — вот путь, который сработал в этом случае.
flowchart TB
accTitle: Когда удвоенный RTO возвращается и как здесь работают метки времени
accDescr: При каждом тайм-ауте RTO удваивается и возвращается, когда получено новое измерение RTT, но это измерение берут только с ACK на данные без повторной передачи. Если timestamps снимают это ограничение, время, пока удвоенный RTO не может вернуться, становится короче.
backoff["при каждом тайм-ауте RTO удваивается"] --> ret["новое измерение RTT возвращает его обратно"]
ret -.-> limit["измерение только с ACK на данные без повторной передачи"]
ts2["timestamps позволяют мерить и на участке повторной передачи"] --> often["появляется больше поводов измерить заново"]
often --> short["время, пока удвоенный RTO не может вернуться, сокращается"]
Рис. 11: Суть не в том, что нижняя граница стала меньше, а в том, что удвоенный RTO быстрее возвращается по фактическому измерению.
Честно: в этой статье мы не снимали фактические значения RTO после улучшения. Известно только, что остановки на секунды сократились до уровня, который на площадке перестал быть проблемой. Если эффект нужно показать цифрами, самый прямой путь — фильтрами отображения из главы 7 и столбцом Time delta from previous displayed packet свести распределение разрыва до повторной передачи до и после.
Иначе говоря, сделанное здесь — не волшебство, которое ускоряет TCP, а сокращение времени, пока TCP выжидает дольше, чем нужно.
Разумеется, RFC 7323 тоже не утверждает, что «больше выборок RTT аккуратно решает всё». Степень пользы для оптимизации RTO в некоторых отношениях ограничена. Тем не менее тот факт, что удаётся снять неоднозначность при повторной передаче, в системе вроде этой может сработать прямо.
Есть и оговорки.
- часть этого зависит от реализации TCP-стека
- одни метки времени потерю пакетов не устраняют
- если виноват физический уровень или промежуточное оборудование, первопричина в другом месте
- SACK, драйвер сетевой карты, настройки offload и проблемы на стороне коммутатора лучше смотреть отдельно
Но в системе, подобной этой, где «потери не равны нулю», а «по-настоящему болят именно секундные ожидания», эффект бывает заметным.
6. Что сделали на практике
6.1. Включаем метки времени
В качестве меры мы добились того, чтобы опция timestamps могла согласовываться на обоих концах соединения. В системах Windows её иногда трактуют как опцию RFC 1323, и на это влияют настройки ОС и сети.
Конкретные шаги ниже. Сначала смотрим, как сейчас.
netsh interface tcp show global
В выводе есть пункт про метки времени RFC 1323 — по нему видно, включены они или нет. Чтобы включить, в командной строке с правами администратора:
netsh interface tcp set global timestamps=enabled
Для timestamps допустимы три значения: disabled / enabled / default. default возвращает системное значение по умолчанию.
Из PowerShell смотреть и задавать так.
Get-NetTCPSetting | Select-Object SettingName, Timestamps, MinRtoMs, InitialRtoMs
Set-NetTCPSetting -SettingName InternetCustom -Timestamps Enabled
Для Timestamps допустимы Enabled / Disabled. Какие SettingName можно менять, зависит от версии Windows, поэтому не стоит сразу бить Set-: сначала Get-NetTCPSetting и проверка, что имя существует. Несуществующее имя на этом месте останавливает команду.
Если смотреть реестр напрямую в старой среде, это Tcp1323Opts (REG_DWORD) в ключе:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
Смысл значения: 0 — опции RFC 1323 выключены, 1 — только window scaling, 2 — только timestamps, 3 — оба включены. Запомнить просто: бит 0 — window scaling, бит 1 — timestamps.
При настройке есть три оговорки.
- Действует только на новые соединения. Метки времени согласовываются в трёхстороннем рукопожатии, поэтому уже установленные соединения не затрагиваются. Соединение со стороны устройства нужно установить заново
- Без поддержки на обоих концах согласование не проходит. Если включить только на хосте, а камера в SYN/ACK не вернёт TSopt, на этом соединении опция не используется
- Настройка меняет и характер соединения. Метки времени увеличивают заголовок TCP, поэтому данных в одном сегменте становится чуть меньше
На практике важнее не «включено в окне настроек», а «TSopt действительно есть в реальных пакетах SYN / SYN-ACK». Здесь это действительно так.
flowchart TB
accTitle: Три оговорки при включении меток времени
accDescr: Настройка меток времени согласовывается в трёхстороннем рукопожатии, поэтому действует только на новые соединения; без поддержки на обоих концах не проходит; заголовок становится больше, и данных в одном сегменте чуть меньше.
care["три оговорки при настройке"] --> n1["действует только на новые соединения"]
care --> n2["нужна поддержка на обоих концах"]
care --> n3["заголовок растёт, данных в сегменте чуть меньше"]
n1 -.-> re["соединение со стороны устройства устанавливают заново"]
Рис. 12: Настройкой дело не кончается. Нужны переустановка соединения и проверка поддержки на другой стороне.
6.2. Проверяем TSopt в SYN / SYN-ACK
После включения проверили три момента.
- есть ли TSopt в SYN проблемного соединения
- возвращает ли TSopt и сторона SYN/ACK
- продолжают ли последующие сегменты данных и ACK нести TSopt
Только убедившись в этом, можно сказать, что «на этом соединении метки времени действительно используются».
6.3. Куда смотреть, если всё равно не помогает
Даже после включения меток времени улучшение бывает слабым в таких случаях.
- сам процент потерь высок
- промежуточное оборудование портит, отбрасывает или искажает опции TCP
- есть отдельная проблема вокруг сетевой карты / драйвера / offload
- приложение подвешивает всё на один синхронный вызов, из-за чего одно ожидание выглядит как полная остановка
- реальная причина вовсе не TCP, а остановка обработки на стороне камеры или затор во внутренней очереди устройства
Поэтому двигаться удобнее в таком порядке.
- сначала по wire подтвердить ожидание повторной передачи
- посмотреть, согласован ли TSopt
- включить timestamps и оценить разницу
- если проблема остаётся, отдельно разбирать источник потерь и устройство приложения
flowchart TB
accTitle: Порядок, в котором двигают меры
accDescr: Сначала по wire подтверждают ожидание повторной передачи, смотрят, согласован ли TSopt, включают timestamps и оценивают разницу, и если проблема остаётся — отдельно разбирают источник потерь и устройство приложения.
s1["по wire подтверждаем ожидание повторной передачи"] --> s2["смотрим, согласован ли TSopt"]
s2 --> s3["включаем timestamps и смотрим разницу"]
s3 --> s4["если остаётся — источник потерь и устройство приложения разбираем отдельно"]
Рис. 13: Подтверждение → согласование → включение → оставшееся расследование. В таком порядке легче отделить, почему мера не сработала.
7. На что смотреть в Wireshark
Фильтры отображения, которые удобны при диагностике.
tcp.stream eq <нужный поток>
tcp.analysis.retransmission
tcp.analysis.fast_retransmission
tcp.analysis.lost_segment
tcp.options.timestamp.tsval
tcp.options.timestamp.tsecr
Есть несколько приёмов, как на это смотреть.
- сузить выборку до нужного соединения через
tcp.stream - вывести
Time delta from previous displayed packet, чтобы напрямую увидеть длительность остановки в секундах - проверить, появляется ли
Retransmissionв нужный момент - проверить, согласован ли TSopt в SYN / SYN-ACK при установлении соединения
- посмотреть, возвращается ли
TSecrв ACK
Как это выглядит на экране, тоже опишем словами. Этот случай, когда привыкнешь, узнаётся сразу.
| Куда смотреть | Что видно |
|---|---|
| Столбец Info в списке пакетов | У пакетов повторной передачи стоит [TCP Retransmission] |
| Цвет строки | Правило раскраски Wireshark по умолчанию «Bad TCP»: эта строка — чёрный фон, красный текст. При просмотре потока её легко заметить |
| Панель подробностей | Выберите строку, раскройте Transmission Control Protocol, внутри откройте SEQ/ACK analysis — там будет указано, что пакет признан повторной передачей |
| Разрыв по времени | Если вывести столбец Time delta from previous displayed packet, видно, сколько секунд прошло от предыдущего отображённого пакета. Здесь выстраиваются 1 с, 2 с |
| Options в SYN | Выберите строку SYN, раскройте Options: есть ли пункт Timestamps — по нему видно, есть ли TSopt |
Типичный порядок такой. Сначала та же строка Seq появляется через 1 секунду, затем ещё раз через 2 секунды после неё, сразу после последней строки возвращается ACK, и с этого места обычный обмен возобновляется. Если эти «пустые несколько секунд» совпадают со временем, когда в логе приложения пропадал ответ, виновник почти установлен.
Когда сопоставляете логи и пакеты, смотрите и на сдвиг эталона времени между приложением и захватом. Если он есть, легко назначить виновным другое событие.
flowchart TB
accTitle: Как в Wireshark устанавливают виновника
accDescr: Сужают выборку до нужного соединения через tcp.stream, по столбцу разрыва напрямую смотрят пустые секунды, и если эти пустые секунды совпадают со временем, когда в логе приложения пропадал ответ, виновник почти установлен.
filt["tcp.stream: только нужное соединение"] --> delta["по столбцу разрыва смотрим пустые секунды"]
delta --> re["проверяем, что подряд идут повторные отправки с тем же Seq"]
re --> match{"совпадает со временем остановки в приложении?"}
match -->|"да"| fix["виновник почти установлен"]
match -->|"нет"| other["подозрение на сдвиг эталона времени или другую причину"]
Рис. 14: Сузить, посмотреть разрыв, сопоставить. Этими тремя шагами устанавливают, что стоит за «пустыми несколькими секундами».
8. Как выбирать (кратко)
| Симптом | Что подозревать сначала | Что сделать сначала |
|---|---|---|
| Изредка останавливается на несколько секунд | Ожидание RTO в TCP | Подтвердить повторную передачу и разрыв по времени по пакетам |
| Останавливается почти в одно и то же время каждый раз | Ожидание внутри приложения, обработка на стороне устройства, фиксированные тайм-ауты | Посмотреть потоки, вызовы SDK, логи устройства |
| Ухудшается только при высокой нагрузке | CPU, GC, затор в очереди | Посмотреть CPU, прерывания, память, длину очереди |
| Плохо сразу на широком диапазоне соединений | Физический уровень, коммутатор, промежуточное оборудование | Посмотреть сетевую карту, кабели, статистику портов, логи промежуточного оборудования |
| Настройки изменили, а ничего не поменялось | Опция TCP не согласована | Ещё раз проверить SYN / SYN-ACK |
Последняя строка встречается действительно часто. Удовлетворение от того, что настройку поменяли, и факт, что она реально используется на wire, — разные вещи.
9. Итог
Основные моменты в этом случае:
- «изредка останавливается на несколько секунд» может быть не зависанием приложения, а ожиданием повторной передачи TCP
- если длительность остановки совпадает с тем, как ведёт себя ожидание RTO, и видна
Retransmission, версия весьма правдоподобна - опция TCP timestamps — механизм RTTM и PAWS, и она же снимает неоднозначность измерения RTT при повторной передаче
- в этом случае включение меток времени семейства RFC1323 сократило время, пока RTO оставался излишне консервативным
Чего лучше избегать:
- назначать виновника остановки обмена только по логам приложения
- смотреть только настройки ОС, не глядя на реальные пакеты
- думать, что включение меток времени устранит и причину потерь
Что работает на практике:
- сначала смотреть на wire
- подтверждать форму повторной передачи и времени ожидания
- проверять согласование TSopt
- даже после улучшения источник потерь и устройство приложения разбирать отдельно
То есть в дефектах такого рода важнее не «ускорить», а «попасть в то место, где идёт ожидание». Если это не упускать, расследование заметно короче.
10. Справочные материалы
- RFC 1323 - TCP Extensions for High Performance
- RFC 7323 - TCP Extensions for High Performance
- RFC 5681 - TCP Congestion Control
- RFC 6298 - Computing TCP’s Retransmission Timer
- Description of Windows TCP features - Windows Server | Microsoft Learn
- Netsh commands for Interface Transmission Control Protocol - Microsoft Learn
- Set-NetTCPSetting - Microsoft Learn
- Get-NetTCPSetting - Microsoft Learn
- Wireshark User’s Guide - Time Display Formats And Time References
- Wireshark User’s Guide - Packet Colorization
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Application Verifier: инфраструктура тестов нештатных путей Windows
Разбираем, что такое Application Verifier, и как с Handles, Heaps, Low Resource Simulation и !htrace строить инфраструктуру тестов нештат...
Утечка хендлов: почему приложение промышленной камеры падает после месяца работы
На примере приложения управления промышленной камерой разбираем, как смотреть на Windows-приложение, которое внезапно падает после длител...
Как читать «использование памяти» в Windows: Working Set, Private Bytes, Commit и файл подкачки
Столбец «Память» в диспетчере задач, Working Set, Private Bytes и Commit — это разные величины. Разбираем связь виртуальной и физической ...
Инцидент не закрывается восстановлением — постмортем для небольшой команды
Если закрыть инцидент после исправления и извинений, тот же сбой повторится. Адаптируем blameless-постмортем для небольшой команды: шабло...
Спящий режим, гибернация и Modern Standby: как не дать долгоживущему приложению остановиться ночью
Разбираем, почему долгоживущее Windows-приложение к утру оказывается остановленным: чем отличаются спящий режим S3, гибернация и Modern S...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Расследование ошибок и долгие сбои
Периодические сбои, диагностика связи, сбои после длительной работы и проверка путей отказа.
Связанные примеры проектов
В этих примерах используется сходный подход к анализу, расстановке приоритетов или переработке.
Как мы локализовали многосекундные остановки связи
Кейс о редкой остановке связи, которую удалось разделить на ожидание повторной передачи и условия на стороне операционной системы.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Расследование ошибок и причин
Речь о том, как по пакетам и фактическим свидетельствам локализовать плохо воспроизводимую остановку обмена — это напрямую относится к расследованию сбоев и анализу причины.
Разработка приложений для Windows
Для Windows-приложения, связанного с оборудованием, это также выходит на консультацию: как со стороны реализации пересмотреть проектирование обмена и наблюдение.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Что такое TCP Retransmission (повторная передача TCP)?
- Механизм, при котором TCP снова отправляет те же данные, если на отправленный пакет не вернулся ACK (подтверждение). Если пакет теряется где-то по пути, отправитель ждёт ACK и, не дождавшись, ждёт истечения таймера повторной передачи (RTO), и только затем повторяет отправку. Со стороны приложения это выглядит как «остановка на несколько секунд», но с точки зрения TCP это просто «ACK ещё не пришёл, поэтому ждём истечения таймера» — такая форма остановки встречается часто. В захвате пакетов это видно как TCP Retransmission.
- Почему возникает TCP Retransmission?
- Непосредственный триггер — потеря пакета: из-за неё не возвращается ACK, и происходит повторная отправка. Источник потери нужно смотреть отдельно: физический уровень (кабель, порт), сетевая карта, её драйвер и настройки offload, коммутатор или промежуточное оборудование. Включение TCP timestamps может сократить ожидание после повторной передачи, но это не волшебство, которое устраняет саму потерю, — источник потерь исследуют отдельно. Бывает и так, что промежуточное оборудование портит или отбрасывает опции TCP, а также так, что главная причина вовсе не TCP, а остановка обработки на стороне устройства.
- Почему из-за повторной передачи TCP обмен останавливается на несколько секунд?
- Потому что таймер повторной передачи TCP (RTO) ждёт консервативно. По RFC 6298 начальный RTO принимают за 1 секунду: даже если расчёт дал меньше, значение поднимают до 1 секунды, а при каждом тайм-ауте удваивают. В неблагоприятных условиях ожидание выглядит как 1, 2, 4 секунды. В управляющем обмене из небольших request/response ожидание RTO чаще выходит на первый план раньше, чем наберётся достаточно duplicate ACK для fast retransmit, и это проявляется как редкая остановка на несколько секунд. Если включить опцию TCP timestamps, иногда удаётся снять неоднозначность измерения RTT при повторной передаче и сократить время, пока оценка RTO остаётся излишне консервативной.
- Как смотреть TCP Retransmission в Wireshark?
- Как фильтры отображения удобны tcp.analysis.retransmission, tcp.analysis.fast_retransmission, tcp.analysis.lost_segment. Сузьте выборку до нужного соединения через tcp.stream, выведите Time delta from previous displayed packet, чтобы напрямую увидеть длительность остановки в секундах, и проверьте, появляется ли Retransmission в нужный момент и совпадает ли разрыв до повторной передачи с длительностью остановки. Используются ли TCP timestamps, смотрят по тому, согласован ли TSopt в SYN / SYN-ACK при установлении соединения. Важнее не «включено в настройках», а факт, что TSopt есть в реальных пакетах.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.