Скрипт Нагрузочного Тестирования Для Проверки Соответствия Текущих Параметров Каналов Связи Заявленным



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

Появляются потери, влияющие на качество сетевых услуг.

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

от согласованных с операторами связи.

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

Хочу поделиться своим опытом автоматизации этого процесса.



Идея

Идея состоит в том, чтобы разработать и периодически использовать скрипт, который запускается, в моем случае, на Linux-сервере в центральной точке корпоративной сети.

Предполагается, что скрипт взаимодействует с роутерами, на которых:

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

На вход скрипта в качестве параметра поступает файл с IP-адресами каналообразующих интерфейсов маршрутизаторов, каналы связи которых нам необходимо проверить.

Количество строк в файле не ограничено каким-либо конкретным значением.

После последовательного чтения соответствующего IP-адреса из входного файла скрипт:

  1. Он запускает фоновый процесс генерации трафика по считываемому IP-адресу, используя менее 100% пропускной способности тестируемого канала, чтобы не загружать канал полностью.

    Я ограничил процесс генерации трафика двумя минутами, при этом генерируемая пропускная способность трафика составляла 85% от максимальной пропускной способности канала.

  2. Через несколько секунд после начала генерации трафика он запрашивает по протоколу SNMP текущее значение полученных байт для интерфейса маршрутизатора, имеющего указанный IP-адрес.

    Запоминает текущее время t0.

  3. Запускает серию из 60 ICMP-пакетов.

    Записывает количество потерь.

  4. Многократно запрашивает по протоколу SNMP значение полученных байтов одного и того же интерфейса.

    Запоминает текущее время t1. Вычисляет продолжительность измерения: t1-t0.

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

    Хочу отметить, что не весь трафик, генерируемый скриптом, может быть доставлен на роутер.

    Это возможно, если пропускная способность канала не соответствует заявленной.

    Сценарий должен выявить такие факты.

  6. В результате выводит следующие значения:
    • отношение пропускной способности доставленного трафика к пропускной способности генерируемого трафика,
    • количество потерь на канале и
    • результат соответствия параметров канала заявленным, который формируется на основе двух предыдущих значений.



Особенности реализации



Генератор трафика

В качестве генератора трафика используется программа TCPBLAST/UDPBLAST, исходные коды которой доступны по следующей ссылке: TCPBLAST/UDPBLAST Данная программа как нельзя лучше подошла на роль генератора трафика для данной задачи, т.к.

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



Обнаружение SNMP-индексов интерфейсов маршрутизатора для тестируемых каналов

Скрипт получает на вход только IP-адрес интерфейса роутера.

Этого вполне достаточно для определения индекса интерфейса SNMP. OID, используемый для этих целей: .

1.3.6.1.2.1.4.20.1.2

Обнаружение пропускной способности тестируемых каналов

Пропускная способность интерфейса и другие параметры определяются с использованием соответствующих OID с подставив в них индекс интерфейса SNMP.

Код сценария

   

#!/usr/bin/perl use strict; use warnings; use POSIX qw(strftime); use SNMP; die "Usage: $0 <inputFile>" if ($#ARGV < 0); my $community = 'community'; ### pingLoss function ### sub pingLoss { my ($param) = @_; my @result = `ping $param`; foreach my $str (@result) { if ($str =~ /(\d+)%/ && $1 < 100) { return $1; } } return 100; } ### stressTest function for one host ### sub stressTest { my $ifIp = shift; my $ifIndex; my $ifName = ""; my $ifAlias = ""; my $ifSpeed = ""; my $ifInOctets; my $ifInOctetsBegin; my $ifInOctetsEnd; my $sendBytes; my $sysName = ""; my $testPeriod; my $pingLossCount = ""; my $inOutPercent = ""; my $testStatus; my $nowDateTime = strftime "%Y.%m.%d %H:%M:%S", localtime; if (&pingLoss("$ifIp -c 3 -i 0.2 -W 2") > 90) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tping error\n"; return 0; } my $sess = new SNMP::Session(DestHost => "$ifIp:161", Community => $community, Version => "2c", NonIncreasing => 1, UseLongNames => 1,); $sysName = $sess->get('.

1.3.6.1.2.1.1.5.0'); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tsnmp sysName error\n"; return 0; } if ($sysName =~ m/^([\w_-]+)\.

/) { $sysName = $1; } $ifIndex = $sess->get('.

1.3.6.1.2.1.4.20.1.2.' .

$ifIp); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tsnmp ifIndex error\n"; return 0; } $ifName = $sess->get('.

1.3.6.1.2.1.31.1.1.1.1.' .

$ifIndex); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t$sysName\t\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tsnmp ifName error\n"; return 0; } $ifAlias = $sess->get('.

1.3.6.1.2.1.31.1.1.1.18.' .

$ifIndex); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t\t$ifSpeed\t$inOutPercent\t$pingLossCount\tsnmp ifAlias error\n"; return 0; } $ifSpeed = $sess->get('.

1.3.6.1.2.1.2.2.1.5.' .

$ifIndex); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t\t$inOutPercent\t$pingLossCount\tsnmp ifSpeed error\n"; return 0; } if ($ifSpeed > 30000000) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tHigh speed channel\n"; return 0; } my $sendBytesSec = $ifSpeed * 0.85 / 8; system("killall udpblast > /dev/null 2> /dev/null"); system("udpblast -c 1000000 --rate $sendBytesSec,100s $ifIp > /dev/null 2> /dev/null &"); sleep(5); my $testBegin = strftime "%s", localtime; $ifInOctetsBegin = $sess->get('.

1.3.6.1.2.1.2.2.1.10.' .

$ifIndex); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tsnmp ifInOctetsBegin error\n"; return 0; } $pingLossCount = &pingLoss("$ifIp -c 60 -W 1.5"); system("killall udpblast > /dev/null 2> /dev/null"); $ifInOctetsEnd = $sess->get('.

1.3.6.1.2.1.2.2.1.10.' .

$ifIndex); if ($sess->{ErrorNum}) { print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\tsnmp ifInOctetsEnd error\n"; return 0; } my $testEnd = strftime "%s", localtime; $testPeriod = $testEnd - $testBegin; $ifInOctets = $ifInOctetsEnd - $ifInOctetsBegin; $sendBytes = $sendBytesSec * $testPeriod * 1.04; $inOutPercent = sprintf("%d", $ifInOctets * 100 / $sendBytes); $testStatus = $inOutPercent > 89 && $pingLossCount < 6 ? "Good" : "Bad"; print "$nowDateTime\t$ifIp\t$sysName\t$ifName\t$ifAlias\t$ifSpeed\t$inOutPercent\t$pingLossCount\t$testStatus\n"; } ### Main ### open (inputFile, $ARGV[0]) or die "Failed to open $ARGV[0]: $!\n"; print "date time \tipAddress \tsysName \tifName \tifAlias \tifSpeed \tinOutPercent\tpingLossCount\ttestStatus\n"; foreach my $readString (<inputFile>) { my $ipAddress = ""; if ($readString =~ m/([0-9]{1,3})\.

([0-9]{1,3})\.

([0-9]{1,3})\.

([0-9]{1,3})/ && $1 < 256 && $2 < 256 && $3 < 256 && $4 < 256) { $ipAddress = "$1.$2.$3.$4"; } else {next}; &stressTest($ipAddress); }

Буду очень рад конструктивной критике с целью оптимизации алгоритма скрипта.

Теги: #cisco #cisco #Сетевые технологии #Системное администрирование #Huawei #нагрузочное тестирование #perl #juniper #juniper #SNMP #bandwidth #udpblast

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.