Как эффективно разделить пинг

в 9:05, , рубрики: Блог компании RUVDS.com

Как эффективно разделить пинг - 1

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

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

$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=120 time=3.29 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=120 time=2.78 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=120 time=3.09 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=120 time=3.11 ms
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 2.789/3.073/3.298/0.186 ms
$ 

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

Как эффективно разделить пинг - 2

Принцип работы

Базовый режим работы ping подразумевает отправку к цели сообщения ICMP Type 8, в ответ на которое хост ожидает возвращения пакета ICMP Type 0. При этом измеряется время, прошедшее с момента отправки до момента получения пакета:

Как эффективно разделить пинг - 3

Есть общая тенденция считать, что при делении значения задержки на два мы получаем время доставки данных в одном направлении (такое предположение часто используется в отношении “netcode”). И хотя в идеале так оно и должно быть, на деле интернет полон асимметричной маршрутизации, и путь пинга может выглядеть, к примеру, так:

Как эффективно разделить пинг - 4

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

Но как же тогда правильно разделить такой пинг на этапы отправки и получения?
Понимание пришло ко мне после просмотра выступления apenwarr (pdf), где он рассказывал о Google Fibre WiFi. В этом выступлении apenwarr упоминает инструмент под названием isoping.

Isoping – это программа, которая определяет разницу в скорости передачи и получения пакетов.

# ./isoping test.benjojo.co.uk
connecting to ::ffff:185.230.223.69...
                48.8 ms rx  (min=48.8)  loss: 0/2 tx  0/1 rx
time paradox: backsliding start by -396 usec
  48.8 ms tx    48.6 ms rx  (min=48.6)  loss: 0/3 tx  0/2 rx
  48.7 ms tx    49.0 ms rx  (min=48.6)  loss: 0/4 tx  0/3 rx
  48.6 ms tx    48.9 ms rx  (min=48.5)  loss: 0/5 tx  0/4 rx
  48.5 ms tx    49.0 ms rx  (min=48.5)  loss: 0/6 tx  0/5 rx
  48.5 ms tx    48.9 ms rx  (min=48.5)  loss: 0/7 tx  0/6 rx
^C

# ping test.benjojo.co.uk
PING test.benjojo.co.uk (185.230.223.69) 56(84) bytes of data.
64 bytes from 185.145.203.147: icmp_seq=1 ttl=54 time=96.6 ms
^C

# # 48 + 48 = 96

Тем не менее после некоторых тестов и беседы с apenwarr я выяснил, что эта программа не может обнаруживать устойчивую асимметрию.

Она производит вычисление на основе минимального наблюдаемого RTT (времени приема-передачи), а не фактического. Минимальное RTT – это наименьшая доступная точность. Однако для обнаружения причин резких скачков пинга wifi до 500мс или увеличения задержки при загрузке файла этот инструмент очень эффективен.

Так что увы, Isoping отлично подходит для мониторинга джиттера (проблемы, которую Google Fiber решают с помощью WiFi-приставок) или обнаружения направленной потери пакетов, но не для нашей задачи определения систематической асимметрии в маршрутизации.

Так как же разделить пинг?

Как эффективно разделить пинг - 5

Как я уже говорил, ping ICMP измеряет время между отправкой и получением ответа. При отсутствии дополнительных метаданных невозможно выявить какую-либо асимметрию во времени передачи между RX и TX.

Как эффективно разделить пинг - 6

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

К нашему удобству, в ICMP уже есть такая возможность в виде Timestamp Requests (Запросы с временными метками).

Как эффективно разделить пинг - 7

В этом разложении Wireshark присутствуют Originate timestamp, указывающий время отправки пакета хостом, а также временные метки получения и передачи (обычно идентичные), указывающие время передачи встречной стороной.

Мне не известно ни одной программы, которая могла бы вычислять половинчатую задержку RTT для временных меток ICMP, поэтому я сам такую написал:

$ sudo ./icmp-timestap-pinger 
TS reddit.com (151.101.65.140): Forward: -1ms Back: 3ms RTT(2ms)
TS klir.benjojo.co.uk (5.231.83.4): Forward: 7ms Back: 5ms RTT(12ms)
TS airmail.benjojo.co.uk (23.132.96.179): Forward: 66ms Back: 65ms RTT(131ms)
TS syd-au-ping.vultr.com (108.61.212.117): Forward: 147ms Back: 153ms RTT(300ms)

Однако здесь есть проблема, поскольку нет гарантии, что на хосте, куда мы отправляем ICMP Timestamp Requests, установлено точное время, откалиброванное в соответствии с временем на машине отправки.

Для решения этой проблемы требуется нечто аналогичное, но гарантирующее собственный контроль точности времени.

Можно обеспечить, чтобы на всех участвующих в мониторинге хостах были установлены NTPd/Chrony. Опять же, здесь возникнет другой вопрос, а именно «Как обеспечить, чтобы наш IP-путь к этим NTP-серверам не подвергался той же асимметрии, которую мы хотим измерить». NTP и Chrony не могут сами предотвратить отклонение показателей из-за асимметрии задержки. В Chrony есть опция “Estimation of asymmetric jitter”, но она не сможет обнаружить систематическую асимметрию.

С целью уменьшения джиттера можно выбрать сервера NTP с наименьшей задержкой. Идея в том, что так асимметрии будет сложнее оказать влияние на оценку времени.

Какие NTP-сервера лучше?

Чтобы ответить на этот вопрос, я решил выполнить тест на популярных и общедоступных серверах:

  • Google
  • Facebook
  • Cloudflare
  • Apple

Для тестирования я использовал GPS-модуль uBlox 6M, который выступил в качестве генератора импульсов (PPS). Его я подключил к GPIO Raspberri Pi 4 для генерации прерываний, реализовав обработку импульсов с помощью LinuxPPS.

Можно предположить, что PPS, генерируемый uBlox, практически идеален, поскольку предоставляется GNSS (спутниковой системой навигации), то есть является наиболее точным из легко доступных. Производители uBox заявляют, что точность его импульса составляет примерно ± 100нс.

Это позволяет нам регистрировать момент возникновения импульса и сравнивать его близость с системным временем нашего NTP-сервера:

root@tempest:~# ppstest /dev/pps0 
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1604603306.999999790, sequence: 1403151
source 0 - assert 1604603307.999999554, sequence: 1403152
source 0 - assert 1604603309.000000373, sequence: 1403153
source 0 - assert 1604603310.000000803, sequence: 1403154
source 0 - assert 1604603310.999999807, sequence: 1403155
source 0 - assert 1604603311.999999830, sequence: 1403156

Чем дальше оказываются временные метки от точной секунды, тем менее точен NTP-источник (скорее всего из-за асимметрии или других сетевых факторов).

Как эффективно разделить пинг - 8

По VDSL-линии, предоставляемой оператором IDNet в Великобритании, видно, что служба времени Cloudflare дает наименьшую ошибку в сравнении с временем, откалиброванным по GNSS. Но здесь нужно учесть еще один нюанс, а именно то, что в Cloudflare маршрутизация NTP-траффика внутренней сети реализуется с помощью anycast, а в Apple для направления системы к ближайшему кластеру используется DNS.

Хорошо в этом то, что все кластеры Apple достижимы независимо (Сингапур, Сан-Паулу, Гон-Конг, Сан-Хосе, Лос-Анжелес, Нью-Йорк, Майами, Атланта, Сидней, Франкфурт, Лондон, Амстердам, Токио, Стокгольм, Сеул, Тайбэй).

И поскольку это позволяет гарантировать фиксированную привязку к NTP-кластеру, я решил использовать в качестве эталона серверы Apple несмотря на то, что их отклонение по времени было больше (в моем тесте для одной локации).

Кластеры Facebook и Google оказались несовместимы друг с другом из-за различий в реализации «размазывания» дополнительных секунд.

Таблицы времени

Синхронизировав часы, можно, наконец, переходить к основной цели — «разделению пинга»! Сначала мы просто создаем на обеих сторонах таблицы для регистрации временных меток и ID пакетов.

Как эффективно разделить пинг - 9

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

Помимо этого, также можно увидеть, какие пакеты были утеряны и при движении в каком направлении.

Вот ряд примеров:

Как эффективно разделить пинг - 10

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

В дополнении к этому следующая строчка демонстрирует достаточно высокую асимметрию задержки:

 [xxx.xxx.xxx.xxx] RX: 15.076895ms TX: 5.450551ms [Loss RX: 0/32 | Loss TX 0/32]

Здесь отправка пакетов происходит на 10мс дольше, чем их получение. Вероятно, это проявление определенной формы чередования DSL.

В еще одном эксперименте я настроил sping между моей квартирой и VM в Китае. Здесь видны печально известные ежедневные пиковые потери пакетов:

Как эффективно разделить пинг - 11

Интересно отметить, что основная потеря происходит при передаче из Великобритании в Китай и лишь небольшой период потерь приходится на обратное направление.

Поскольку этот инструмент очень полезен для отладки сетевых задержек и для определения возможности использования NTP с целью точного хронометража, я оформил его в программу, которую назвал sping: https://github.com/benjojo/sping

Usage of sping:
  -clock-is-perfect
    	Enable userspace calibration against Apple's GPS NTP servers (default true)
  -debug.showslots
    	Show incoming packet latency slots
  -debug.showstats
    	Show per ping info, and timestamps
  -listenAddr string
    	Listening address (default "[::]:6924")
  -peers string
    	List of IPs that are peers
  -pps.debug
    	Enable debug output for PPS inputs
  -pps.path string
    	what PPS device to use (default "/dev/pps0")
  -udp.pps int
    	max inbound PPS that can be processed at once (default 100)
  -use.pps
    	If to use a PPS device instead of system clock
  -web.listen-address string
    	Address on which to expose metrics and web interface (default "[::]:9523")
  -web.telemetry-path string
    	Path under which to expose metrics. (default "/metrics")

Базово эта программа может полагаться на системное время. Если же в среде настройка времени невозможна (например, в контейнерах, OpenVZ и т.д.), то она может выполнять собственную калибровку в отношении NTP-серверов Apple, которые, как я выяснил, размещены глобально наиболее согласованным образом.

С целью повышения точности sping также можно использовать с устройством генерации PPS.
Для обмена данными пинга между пирами программа использует UDP, а для обмена рукопожатиями – TCP. В IANA для этого был назначен порт 6924.

Автор: Дмитрий Брайт

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js