Анализ сетевых характеристик с использованием JavaScript и DOM, часть 1

В этой статье мы рассмотрим некоторые методы манипулирования JavaScript для определения различных сетевых характеристик в браузере — характеристик, которые ранее были доступны только для приложений, которые непосредственно взаимодействуют с операционной системой. Многое из этого было обнаружено при создании проекта Boomerang для измерения реальной производительности пользователей.

Что в сети в любом случае?

Сеть имеет много слоев, но веб-разработчики среди нас больше всего заботятся о HTTP, который работает над TCP и IP (иначе известный совместно как пакет интернет-протоколов). Несколько слоев ниже, но по большей части, будь то работает на меди, волокна или самонаведения голубей не влияет на слои или характеристики, которые мы заботимся о.

Задержка сети

Задержка сети— это, как правило, время, необходимое для отправки сигнала по сети и получения ответа. Это также часто называют время туда и обратно или пинг время, потому что это время сообщили ping команды. Хотя это интересно сетевым инженерам, которые диагнозируют проблемы сети, веб-разработчики больше заботятся о времени, которое требуется, чтобы сделать запрос HTTP и получить ответ. Таким образом, мы определим задержку HTTP как время, необходимое для того, чтобы сделать возможный запрос HTTP, и получим ответ с незначительным временем обработки сервера (т.е. единственное, что делает сервер, это отправка ответа).

Прохладный совет: Свет и электричество пролетят через волокно и медь со скоростью 66% скорости света в вакууме, или 20 — 108 километров в секунду. Хорошее приближение задержки сети между точками A и B в четыре раза превышает время, которое требуется для легкого или электрического времени для перемещения по расстоянию. Кабельная карта Грега является хорошим ресурсом, чтобы узнать длину и пропускную способность подводных сетевых кабелей. Я оставлю это вам, чтобы положить эти куски вместе.

Пропускная часть сети

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

Dns

DNS немного отличается от всего остального, о чем мы заботимся. Он работает над UDP и обычно происходит на уровне, который является прозрачным для JavaScript. Мы увидим, как лучше определить время, необходимое для поиска DNS.

Существует, конечно, гораздо больше в сети, но определение этих характеристик через JavaScript в браузере становится все труднее.

Измерение задержки сети с помощью JavaScript

HTTP Get Request

Мой первый инстинкт был, что измерение задержки просто повлекло за собой отправку одного пакета в каждую сторону и сроки его. Это довольно легко сделать в JavaScript:


var ts, rtt, img = new Image;
img.onload=function() { rtt=(+new Date - ts) };
ts = +new Date;
img.src="/1x1.gif";

Мы запускаем таймер, а затем загружаем GIF 1 и 1 пиксель и измеряем, когда его onload событие сравнивается. Сам GIF составляет 35 байтов по размеру и поэтому помещается в один пакет TCP даже с добавленными заголовками HTTP.

Это своего рода сорта работает, но имеет противоречивые результаты. В частности, при первой загрузке изображения, это займет немного больше времени, чем последующие нагрузки — даже если мы убедитесь, что изображение не кэшируется. Глядя на пакеты TCP, которые идут по сети объясняет, что происходит, как мы увидим в следующем разделе.

TCP рукопожатие и HTTP Keep-Alive

TCP handshake: SYN-ACK/SYN-ACK

При загрузке веб-страницы или изображения или любого другого веб-ресурса браузер открывает подключение TCP к указанному веб-серверу, а затем делает запрос HTTP GET по этому подключению. Детали подключения TCP и запроса HTTP скрыты от пользователей и веб-разработчиков. Однако они важны, если нам нужно проанализировать характеристики сети.

В первый раз, когда соединение TCP открывается между двумя хостами (браузер и сервер, в нашем случае), они должны «рукопожатие». Это происходит путем отправки трех пакетов между двумя узлами. Хост, который инициирует соединение (браузер в нашем случае) сначала отправляет пакет SYN, что означает: «Давайте SYNc вверх. Я хотела бы поговорить с вами. Готовы ли вы поговорить со мной? Если другой хост (сервер в нашем случае) готов, он отвечает ACK, что означает: «Я ACKnowledge ваш SYN». И он также посылает SYN своих собственных, что означает: «Я хотел бы SYNc вверх, тоже. Готовы ли вы? Затем веб-браузер завершает рукопожатие с помощью собственного ACK, и соединение устанавливается. Соединение может выйти из строя, но процесс сбоя соединения выходит за рамки данной статьи.

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

Когда мы бросаем HTTP на TCP, теперь у нас есть клиент HTTP (обычно браузер), который инициирует подключение TCP и отправляет первый пакет данных GET (запрос, например). Если мы используем HTTP/1.1 (что почти все делают сегодня), то по умолчанию будет использовать HTTP keep-alive ( Connection: keep-alive ). Это означает, что несколько запросов HTTP могут иметь место по тому же подключению TCP. Это хорошо, потому что это означает, что мы уменьшаем накладные расходы рукопожатия (три дополнительных пакета).

Теперь, если у нас нет http pipelining включен (и большинство браузеров и серверов выключить его), эти запросы будут происходить последовательно.

HTTP keep-alive

Теперь мы можем немного изменить наш код, чтобы учесть время рукопожатия TCP и соответствующим образом измерить задержку.


var t=[], n=2, tcp, rtt;
var ld = function() {
   t.push(+new Date);
   if(t.length > n)
     done();
   else {
     var img = new Image;
     img.onload = ld;
     img.src="/1x1.gif?" + Math.random()
                         + '=' + new Date;
   }
};
var done = function() {
  rtt=t[2]-t[1];
  tcp=t[1]-t[0]-rtt;
};
ld();

С помощью этого кода мы можем измерить как задержку, так и время рукопожатия TCP. Существует вероятность того, что подключение TCP уже было активным и что первый запрос прошел по этому подключению. В этом случае два раза будут очень близки друг к другу. Во всех остальных случаях, rtt что требует двух пакетов, должно быть примерно 66%, tcp что требует трех пакетов. Обратите внимание, что я говорю «приблизительно», потому что сеть испуг и различные маршруты на слое IP может сделать два пакета в том же подключении TCP принять различные
продолжительности времени, чтобы пройти.

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

Измерение пропускной связи сети с помощью JavaScript

Опять же, наш первый инстинкт с этим тестом было просто скачать большое изображение и измерить, сколько времени это занимает. Тогда size/time должны сказать нам пропускную стрелку.

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


// Assume global object
// image={ url: …, size: … }
var ts, rtt, bw, img = new Image;
img.onload=function() {
   rtt=(+new Date - ts);
   bw = image.size*1000/rtt;    // rtt is in ms
};
ts = +new Date;
img.src=image.url;

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

К сожалению, это не так просто, из-за чего-тоназывается TCP медленного запуска .

Медленный старт

Во избежание перегрузки сети оба конца соединения TCP начнут медленно отправлять данные и ждать подтверждения (пакет ACK). Помните, чем пакет ACK означает: «Я ACKnowledge, что вы только что послал мне». Каждый раз, когда он получает ACK без времени, он предполагает, что другой конец может работать быстрее и будет отправлять больше пакетов, прежде чем ждать следующего ACK. Если ACK не проходит в ожидаемые сроки, он предполагает, что другой конец не может работать достаточно быстро и так отступает.

TCP window sizes for slow-start

Это означает, что наш тест пропускной связи выше было бы хорошо до тех пор, как наше изображение достаточно мал, чтобы поместиться в текущем окне TCP, который в начале установлен на 2. Хотя это хорошо для медленных сетей, быстрая сеть действительно не будет облагаться налогом на столь малые изображения.

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

Для целей кода глобальный image объект теперь представляет собой массив со следующей структурой:


var image = [
    {url: …, size: … }
];

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


var i=0;
var ld = function() {
   if(i > 0)
      image[i-1].end = +new Date;
   if(i >= image.length)
      done();
   else {
      var img = new Image;
      img.onload = ld;
      image[i].start = +new Date;
      img.src=image[i].url;
   }
   i++;
};

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

Наш код теперь выглядит следующим образом:


var i=0;
var ld = function() {
   if(i > 0) {
      image[i-1].end = +new Date;
      clearTimeout(image[i-1].timer);
   }
   if(i >= image.length ||
         (i > 0 && image[i-1].expired))
      done();
   else {
      var img = new Image;
      img.onload = ld;
      image[i].start = +new Date;
      image[i].timer =
            setTimeout(function() {
                       image[i].expired=true
                    },
                    image[i].timeout);
      img.src=image[i].url;
   }
   i++;
};

Это выглядит гораздо лучше — и работает гораздо лучше, тоже. Но мы увидим много дисперсии между несколькими запусками. Единственный способ уменьшить погрешность в измерении — выполнить тест несколько раз и взять сводном значении, например медиану. Это компромисс между тем, насколько точным вы должны быть и как долго вы хотите, чтобы пользователь ждать, прежде чем тест завершается. Получение пропускной связи сети на порядок часто так близко, как вам нужно. Зная, является ли подключение пользователя составляет около 64 Кбит/ 2 Мбит/с полезно, но определить, является ли это точно 2048 или 2500 Кбит/ с гораздо менее полезным.

Резюме и ссылки

Вот и все для части 1 этой серии. Мы рассмотрели, как пакеты, которые составляют веб-запрос пройти между браузером и сервером, как это меняется с течением времени, и как мы можем использовать JavaScript и немного знаний статистики, чтобы сделать образованные догадки на характеристики сети, что мы работать с.

В следующей части мы рассмотрим DNS и разницу между IPv6 и IPv4 и API WebTiming. Мы хотели бы знать, что вы думаете об этой статье и что вы хотели бы видеть в части 2, так что дайте нам знать в комментарии.

До тех пор, вот список ссылок на ресурсы, которые были полезны в составлении этого документа.

Источник: smashingmagazine.com

Великолепный Журнал

Великолепный, сокрушительный, разящий (см. перевод smashing) независимый журнал о веб-разработке. Основан в 2006 году в Германии. Имеет няшный дизайн и кучу крутых авторов, которых читают 2 млн человек в месяц.

Добавить комментарий

%d такие блоггеры, как: