Анализ сетевых характеристик с использованием JavaScript и DOM (часть 2).

В первой части этой серии мы рассмотрели особенности работы основных веб-протоколов и возможности использования JavaScript для оценки их характеристик.
Во второй части этой серии мы рассмотрим DNS, IPv6 и новые спецификации W3C для NavigationTiming API.

Разъяснение особенностей DNS (доменная система именований).

Каждое устройство, подключенное к интернету, получает персональный числовой набор известный как IP-адрес. В открытом интернете существует две формы IP адресов: IPv4, который представляет собой 32-разрядное число, зачастую отображаемое в виде серии из четырех десятичных чисел, разделенных точками, например, 80.72.139.101, и IPv6, который представляет собой 128-битное число, отображаемое в виде серии нескольких шестнадцатеричных номеров, разделенных двоеточиями, например,2607:f298:1:103::c8c:a407.

Эти адреса хороши для компьютерной инициализации; они занимают фиксированное количество байт и могут быть легко обработаны, но с другой стороны людям довольно трудно их запомнить. Они не очень хорошо влияют на брендинг, и часто связаны с географическим положением или поставщик услуг связи (например, интернет-провайдер или хостинг-провайдер).

Чтобы обойти все эти ограничения и недостатки была изобретена «Доменная система именований». В своей простейшей форме доменная система именований создает сопоставление между человекочитаемым именем, таким как «www.smashingmagazine.com», и его машиночитаемым адресом-аналогом, например, (80.72.139.101). DNS может содержать гораздо больше информации, и все важные моменты будут рассмотрены в этой статье.

Сейчас мы акцентируем внимание на DNS времени ожидании, и на том, как мы можем измерить его с помощью JavaScript в браузере. DNS время ожидания важно, потому что браузеру необходимо проводить поиск для каждого уникального имени главной машины (в компьютерной сети) из которой ему затем необходимо будет загрузить информацию — даже если будет присутствовать несколько хостов с идентичными IP адресами.


Увеличенная версия.

Измерение времени DNS поиска.

Простой способ измерения времени DNS поиска в отличие от JavaScript заключается в следующем: сначала необходимо измерить задержку к хосту используя его IP-адрес, а затем повторить процедуру, используя имя хоста. Разница между этими двумя значениями должна дать нам искомое время поиска DNS. Для измерения времени задержки мы используем методы, описанные в первой части.

Проблема этого подхода заключается в том, что если браузер уже сделал запрос DNS на имя главной машины, то этот поиск будет храниться в КЭШе, и мы не сможем получить действительную разницу. Все, что нам нужно, это специальный символ DNS записи и веб-сервер для его прослушивания. Несколько лет назад Карлос Буэно написал по этому поводу отличную обзорную статью на блоге YDN, и создал код, в основе которого лежит принцип бумеранга.

Прежде чем мы посмотрим на этот код, с помощью следующей (упрощенной) схемы давайте поверхностно рассмотрим то, как работают DNS-запросы:

DNS Lookup path from Client to Authoritative Server

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

Каждый из этих слоев имеет свой собственный кэш, который обычно существует до тех пор, пока основной TTL сервера (известный как «Time To Live» — время жизни) не даст команду запрета; нужно отметить, что не все серверы следуют данной спецификации (для себя вы можете более подробно рассмотреть данный вопрос).

Теперь давайте посмотрим на программный код:

var dns_time;

function start() {
    var gen_url, img,
        t_start, t_dns, t_http,
        random = Math.floor(Math.random()*(2147483647)).toString(36);

    // 1. Create a random hostname within our domain
    gen_url = "http://*.foo.com".replace(/\*/, random);

    var A_loaded = function() {
        t_dns = new Date().getTime() - t_start;

        // 3. Load another image from the same host (see step 2 below)
        img = new Image();
        img.onload = B_loaded;

        t_start = new Date().getTime();
        img.src = gen_url + "image-l.gif?t=" + (new Date().getTime()) + Math.random();
    };

    var B_loaded = function() {
        t_http = new Date().getTime() - t_start;

        img = null;

        // 4. DNS time is the time to load the image with uncached DNS
        //    minus the time to load the image with cached DNS

        dns_time = t_dns - t_http;
    };

    // 2. Load an image from the random hostname
    img = new Image();
    img.onload = A_loaded;

    t_start = new Date().getTime();
    img.src = gen_url + "image-l.gif?t=" + (new Date().getTime()) + Math.random();

}

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

  1. Создание случайного имени с приставкой к нашему домену. Это даст гарантии того, что имя хоста еще не было кэшировано.
  2. Загрузка изображения с этого хоста и измерение времени, необходимого для полной загрузки.
  3. Загрузка другого изображения с этого же хоста и измерение времени, необходимого для загрузки.
  4. Вычисление разности между измеренными значениями времени.

Первый измеренный период времени включает время поиска DNS, TCP установления связи и время задержки в сети. Во второй раз, измеренное время включает в себя сетевые задержки.

У этого подхода существует два недостатка. Во-первых, он измеряет самый худший показатель DNS времени поиска, то есть время, которое уходит на DNS поиск, если имя хоста не кэшируются любым промежуточным DNS сервером. На практике, иногда, все получается по-другому. Простого способа обойти этот недостаток без помощи браузеров не существует, и мы еще вернемся к этому немного позже, в конце статьи.

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

Определение возможности поддержки IPv6 и времени задержки.

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

Тестирование IPv6 по принципу бумеранга помогает определить, имеют ли ваши пользователи возможность поддержки протокола IPv6, и как можно сравнить IPv6 время задержки с задержкой IPv4. Вы не сможете проверить нарушена ли поддержка IPv6 или нет (если вам нужна информация подобного рода, то посмотрите тестовую страницу IPv6 от Google).

IPv6 тестирование состоит из двух частей:

  1. Во-первых, мы проверяем возможность подключения к хосту, используя свои IPv6 адреса, и если такая возможность существует, то мы фиксируем требуемое время соединения.
  2. Следующим шагом будет попытка подключения к хосту, который разрешает использование только IPv6 адресов.

На первом этапе тестирования станет понятно, межет ли пользовательская сеть выполнить IPv6 подключения. На втором этапе нам станет понятно, может ли DNS-сервер выполнять поиск AAAA записи. Тестирование нужно выполнять в строго установленном порядке, поскольку в противном случае мы не сможем проверить правильность DNS тестирования, ведь может быть нарушено соединение на уровне IP.

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

var ipv6_url = "http://[2600:1234::d155]/image-l.gif",
    host_url = "http://ipv6.foo.com/image-l.gif",
    timeout: 1200,

    ipv6_latency='NA', dnsv6_latency='NA',

    timers: {
        ipv6: { start: null, end: null },
        host: { start: null, end: null }
    };

var img,
    rnd = "?t=" + (new Date().getTime()) + Math.random(),
    timer=0, error = null;

img = new Image();

function HOST_loaded() {
    // 4. When image loads, record its time
    timers['host'].end = new Date().getTime();
    clearTimeout(timer);
    img.onload = img.onerror = null;
    img = null;

    // 5. Calculate latency
    done();
}

function error(which) {
    // 6. If any image fails to load or times out, terminate the test immediately
    timers[which].supported = false;
    clearTimeout(timer);
    img.onload = img.onerror = null;
    img = null;

    done();
}

function done() {
    if(timers['ipv6'].end !== null) {
        ipv6_latency = timers.ipv6.end - timers.ipv6.start;
    }
    if(timers['host'].end !== null) {
        dnsv6_latency = timers.host.end - timers.host.start;
    }
}

img.onload = function() {
    // 2. When image loads, record its time
    timers['ipv6'].end = new Date().getTime();
    clearTimeout(timer);

    // 3. Then load image with hostname that only resolves to ipv6 address
    img = new Image();
    img.onload = HOST_loaded;
    img.onerror = function() { error('host') };

    timer = setTimeout(function() { error('host') }, timeout);

    timers['host].start = new Date().getTime();
    img.src = host_url + rnd;
};

img.onerror = function() { error('ipv6') };
timer = setTimeout(function() { error('ipv6') }, timeout);
this.timers['ipv6'].start = new Date().getTime();
// 1. Load image with ipv6 address
img.src = ipv6_url + rnd;

Программный код может быть немного переработан д …

Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров

Comments are closed.