Оценка загруженности сетевого интерфейса при нагрузке множеством мелких пакетов
Описание проблемы
Я программирую массовый сканер портов. При попытке нарастить скорость за счёт количества потоков я ожидаемо столкнулся с тем что в какой-то момент задержка (ping) достигает каких то заоблачных значений по 300-800 мс. Конечно наиболее вероятно что это может не быть связано с моим компьютером напрямую, а будет перегружаться мой роутер, но хочется понять точно. И в этом проблема. Я просто не знаю как оценить такого рода перегрузку. Ранее я задавал подобный вопрос, но метод оценки посредством сравнения объёма трафика в секунду и пропускной способности интерфейса не показывает перегрузки (отметка сетевой нагрузки держится на отметке примерно 5%). Думаю дело в том что массовое создание/закрытие TCP соединений не занимает большого объёма трафика т.к я ничего не отправляю и лишь проверяю успешность соединения. Была идея для оценки использовать пакеты в секунду, но я столкнулся с тем что я просто не могу сообразить как узнать сколько пакетов за секунду может пропустить интерфейс до того как начнёт перегружаться тем самым повышая задержку.
Описание работы моего приложения
Для упрощения работы над ответом стоит немного сказать про самое приложение. Написано оно на Golang, целью приложение является как уже было сказано массовое сканирование портов и занесения результатов в базу данных (пока не сделал). Оно создаёт множество горутин (эмпирическим методом было выяснено, что 500 сканирующих потоков лишь слегка повышают задержку на 20-30 мс, когда как 600 потоков повышают задержку до 300 мс) которые пытаются создать TCP соединение, если успешно то порт считается открытым. Снизу вы видите код, где есть две функции ScannerThread
и scanHost
где первая является агрегатором (получает IP адрес, запускает сканирующую функцию, получает результат), а вторая последовательно перебирает порты для их проверки.
// ScannerThread является сканирующей горутиной, сюда попадают адреса после пингования
func ScannerThread(IPChannel chan string) {
defer WorkWG.Done()
for {
ip, ok := <-IPChannel
if ok {
ports := scanHost(ip)
if len(ports) != 0 {
for _, port := range ports {
println(ip, port)
}
}
} else {
break
}
}
}
// Функция сканирует порты конкретного адреса
func scanHost(ip string) []int {
openPorts := make([]int, 0)
for port := 1; port <= 1024; port++ {
d := net.Dialer{Timeout: time.Millisecond * 100}
conn, err := d.Dial("tcp", ip+":"+strconv.Itoa(port))
if err == nil {
conn.Close()
openPorts = append(openPorts, port)
}
}
return openPorts
}
Что бы я хотел получить
Мне нужен метод для оценки перегруженности сетевого интерфейса для подобного трафика. Даже если в итоге окажется что перегружен не сетевой интерфейс моего устройства, а узлы по пути, то я хочу всё равно убедится в том что это не проблема моего устройства. Впрочем, я всё равно с радостью приму другие идеи и объяснения тому почему при данной задаче так сильно растёт задержка.
Прошу, если вы хотите предложить какую-то утилиту которая измерит какие-то там параметры, постарайтесь приложить ещё и обьяснение какие именно параметры измеряет утилита, ведь мне нужно реализовать это в моей программе, а использовать парсинг консольного вывода это моветон.
Дополнительная информация
- Я использую сетевую карту Realtek RTL8118AS встроенную в материнскую плату с заявленной пропускной способностью 1 Гбит/с.
- Во всей локальной сети я использую UTP cat 5e.
- Я использую Linux, а точнее Arch Linux.
- Я проводил тесты нагруженности процессора разными инструментами, нагрузка в среднем повышается на 10-15% т.е процессор не перегружен.
Ответы (1 шт):
Смотри /proc/interrupts
- железные и /proc/softirqs
софтовые прерывания (счётчики IRQ). они не отображаются в нагрузке проца, то очень сильно тормозят систему в целом.
Разные модели сетевых карточек выдерживают разное количество прерываний в момент времени. Тут сложно дать оценку в %, но можно оценить стало их больше или меньше.
Как это всё устроенно и как тюнить написанно в статье https://habr.com/ru/companies/vk/articles/314168/#5