Недавно столкнулись с интересной задачкой, которая возникла из-за странного стечения обстоятельств.
Вкратце, проблема связана с задержками в работе пользователей и изначально представлялась потерями пакетов, что подтверждается даже штатной утилитой ping:
$ ping -i 0.2 mail.ru # mail
PING mail.ru (94.100.180.200) 56(84) bytes of data.
64 bytes from cp.mail.ru (94.100.180.200): icmp_req=3 ttl=58 time=11.2 ms
...
64 bytes from cp.mail.ru (94.100.180.200): icmp_req=109 ttl=58 time=21.9 ms
--- mail.ru ping statistics ---
109 packets transmitted, 66 received, 39% packet loss, time 307289ms
rtt min/avg/max/mdev = 11.130/11.369/21.975/1.323 ms
$ ping -i 0.2 ya.ru # yandex
PING ya.ru (213.180.193.3) 56(84) bytes of data.
64 bytes from www.yandex.ru (213.180.193.3): icmp_req=2 ttl=56 time=10.8 ms
...
64 bytes from www.yandex.ru (213.180.193.3): icmp_req=7 ttl=56 time=10.8 ms
--- ya.ru ping statistics ---
7 packets transmitted, 6 received, 14% packet loss, time 10861ms
rtt min/avg/max/mdev = 10.789/10.906/11.088/0.155 ms
$ ping -i 0.2 8.8.8.8 # google
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_req=1071 ttl=58 time=8.74 ms
...
64 bytes from 8.8.8.8: icmp_req=1073 ttl=58 time=8.69 ms
--- 8.8.8.8 ping statistics ---
1073 packets transmitted, 990 received, 7% packet loss, time 216005ms
rtt min/avg/max/mdev = 8.623/8.968/52.273/2.152 ms
$ ping -i 0.2 192.168.1.2 # default gateway
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_req=1 ttl=64 time=0.088 ms
...
64 bytes from 192.168.1.2: icmp_req=305 ttl=64 time=0.029 ms
--- 192.168.1.2 ping statistics ---
305 packets transmitted, 303 received, 0% packet loss, time 60808ms
rtt min/avg/max/mdev = 0.018/0.117/14.024/1.008 ms
Для того, чтобы эту информацию детализировать, я предлагаю воспользоваться утилитой MTR. Она совмещает в себе ping и traceroute, определяя задержки до каждого хопа. Отметим, что она использует меньшие интервалы между запросами, поэтому требует прав суперпользователя.
Устновим CLI версию утилиты. Для debian это можно сделать так:
# apt-get install mtr-tiny
Основные используемые ключи:
-r -- сформировать отчёт
-w -- сделать отчёт более детальным
-c COUNT -- количество отправляемых пингов
Для проверки был выбран хост 8.8.8.8:
# mtr -rwc 5 8.8.8.8
HOST: alpha Loss% Snt Last Avg Best Wrst StDev
1.|-- 192.168.1.2 40.0% 5 0.0 0.0 0.0 0.0 0.0
2.|-- gw-01-14.~~~~~~~~~~ 40.0% 5 0.2 0.2 0.2 0.2 0.0
3.|-- ptgcr1-rad2cr1.~~~~~~~~~ 40.0% 5 0.5 0.5 0.5 0.5 0.0
4.|-- ae0-3002.rt1.~~~~~~~~~~~~~~~~ 60.0% 5 20.1 10.4 0.7 20.1 13.8
5.|-- ae6-215-rt1.~~~~~~~~~~~~~~~~ 60.0% 5 8.5 8.2 7.9 8.5 0.4
6.|-- google-gw.~~~~~~~~~~~~~~~~ 60.0% 5 10.1 9.2 8.3 10.1 1.3
7.|-- 216.239.47.125 60.0% 5 9.0 9.0 9.0 9.0 0.0
8.|-- google-public-dns-a.google.com 60.0% 5 8.7 8.7 8.7 8.8 0.1
И то же самое, при использовании UDP:
# mtr -rwuc 5 8.8.8.8
HOST: alpha Loss% Snt Last Avg Best Wrst StDev
1.|-- 192.168.1.2 40.0% 5 0.0 0.0 0.0 0.0 0.0
2.|-- gw-01-14.~~~~~~~~~~ 40.0% 5 0.2 0.3 0.2 0.4 0.1
3.|-- ptgcr1-rad2cr1.~~~~~~~~~ 40.0% 5 0.5 0.5 0.5 0.6 0.0
4.|-- ae0-3002.rt1.~~~~~~~~~~~~~~~~ 20.0% 5 0.7 0.7 0.6 0.7 0.0
5.|-- ae6-215-rt1.~~~~~~~~~~~~~~~~ 80.0% 5 8.0 8.0 8.0 8.0 0.0
6.|-- ??? 100.0 5 0.0 0.0 0.0 0.0 0.0
В этом случае, очевидно, проблема на нашей системе.
Это подтверждается, если заглянуть в /var/log/messages:
Feb 20 11:17:42 ~~~ kernel: [1366055.534335] nf_conntrack: table full, dropping packet.
Feb 20 11:17:42 ~~~ kernel: [1366055.541823] nf_conntrack: table full, dropping packet.
Feb 20 11:17:42 ~~~ kernel: [1366055.725239] nf_conntrack: table full, dropping packet.
Посмотреть соединения можно используя подсистему conntrack:
# wc -l /proc/net/nf_conntrack
63331 /proc/net/nf_conntrack
# grep -c TIME_WAIT /proc/net/nf_conntrack
2760
В нашем случае проблема решилась просто:
# echo net.netfilter.nf_conntrack_max=1048576 >> /etc/sysctl.conf
# sysctl -p
net.ipv4.ip_forward = 1
net.netfilter.nf_conntrack_max = 1048576
Сообщения в messages попадать перестали, а mtr (в том числе, с маршрутизатора - 192.168.1.2) теперь показывает 0% потерь:
# mtr -rwc 5 8.8.8.8
HOST: 192.168.1.2 Loss% Snt Last Avg Best Wrst StDev
1.|-- gw-01-14.~~~~~~~~~~ 0.0% 5 0.2 0.2 0.2 0.2 0.0
2.|-- ptgcr1-rad2cr1.~~~~~~~~~ 0.0% 5 0.5 0.5 0.4 0.5 0.0
3.|-- ae0-3002.rt1.~~~~~~~~~~~~~~~~ 0.0% 5 0.8 0.6 0.6 0.8 0.1
4.|-- ae6-215-rt1.~~~~~~~~~~~~~~~~ 0.0% 5 7.9 16.5 7.9 46.6 16.9
5.|-- google-gw.~~~~~~~~~~~~~~~~ 0.0% 5 8.3 8.3 8.3 8.3 0.0
6.|-- 216.239.47.125 0.0% 5 9.1 9.0 8.9 9.1 0.1
7.|-- google-public-dns-a.google.com 0.0% 5 8.7 8.7 8.7 8.8 0.0
Итого, резюмируя понимание проблемы:
В ЦОД лёг один из провайдеров, весь трафик был целиком переведён на второго и начались задержки.
В это время, трафик через наш сервер начал порождать большое количество открытых соединений и переполнилась таблица соединений в ядре.
Совместными усилиями наших инженеров и специалистов ЦОД, проблема была устранена. Трафик ходит, задержек нет, заказчик доволен.
Но проблема имеет такое простое решение только если есть возможность выполнить подобные настройки. Зачастую, приходится обслуживать большие потоки данных. В нашем случае, используя tcpdump, было выявлено большое количество ACK на несуществующие соединения. Для того, чтобы не загружать систему, можно воспользоваться встроенной в ядро подсистемой защиты от ACK-флудов. Проще всего это сделать установив значение переменной new.ipv4.ip_conntrack_loose в 0. Это позволит отбрасывать INVALID-пакеты.