Обходимо обмеження браузера на число з'єднань, creative way projects

Активне (англ. Keep-alive) з'єднання стало справжнім проривом в специфікації HTTP 1.1: воно дозволяло використовувати вже встановлений канал для повторної передачі інформації від клієнта до сервера і назад (в HTTP 1.0 з'єднання закривалося відразу ж після передачі інформації від сервера, що додавало затримки , пов'язані з триступеневої передачею пакетів). У тому випадку, якщо проблема вільних ресурсів стоїть досить гостро, можна розглянути виставлення невеликого тайм-ауту для таких з'єднань (5-10 секунд).

Однак HTTP 1.1 додав веб-розробникам головного болю з іншого приводу. Давайте будемо розбиратися, як нам усунути і цю проблему.

Витрати на доставку об'єктів

Середня веб-сторінка містить більше 50 об'єктів, і витрати на число об'єктів домінують над усіма іншими затримками при завантаженні більшості веб-сторінок. Браузери, дотримуючись рекомендацій специфікації HTTP 1.1, зазвичай встановлюють не більше 2 одночасних з'єднань з одним хостом. При збільшенні числа HTTP- запитів, необхідних для відображення сторінки, з 3 до 23 - час, що витрачається саме на «чисту» завантаження об'єктів, від загального часу завантаження падає з 50% до всього 14%.

Якщо число об'єктів на сторінці перевищує 4, то витрати на очікування доступних потоків і розбір чанкі для надісланих об'єктів превалюють над загальним часом завантаження сторінки (від 80% до 86% для 20 і 23+ об'єктів, відповідно) в порівнянні з часом, яке йде на дійсну завантаження даних. Час ініціалізації плюс час очікування, викликане обмеженням на паралельні з'єднання, займають 50-86% від загального часу завантаження сторінки.

При збільшенні числа підключаються об'єктів понад 10 час, що витрачається на ініціалізацію з'єднання, зростає до 80% і більше від загального часу, що минає на отримання об'єктів. Варто відзначити, що можна істотно зменшити витрати на доставку великої кількості об'єктів (більш ніж 12 на сторінку) включенням для сервера keep-alive режиму і розподілом запитів за кількома хостів.

Обмеження специфікації HTTP / 1.1

Браузери створювалися в ту епоху, коли величезна безліч користувачів користувалися комутованим доступом з невисокою пропускною здатністю каналу, тому тоді було важливо обмежити користувачів невеликим числом одночасних з'єднань. Накладні витрати на перемикання між безліччю з'єднань при комутованому доступі створювали великі труднощі для обробки і завантаження кожного окремого запиту. До того ж в ту епоху веб- і проксі-сервери були недостатньо потужними, щоб підтримувати безліч з'єднань, тому таке жорстке обмеження числа одночасних з'єднань у браузера істотно знижувало ризик падіння мережевої інфраструктури в цілому.

  • Віддавати ваші об'єкти з кількох серверів
  • Створити кілька піддоменів для кількох хостів

Щоб знайти відповідний баланс, IE до версії 7 включно обмежують користувачів всього вісьмома одночасними з'єднаннями або двома з'єднаннями на хост для протоколу HTTP 1.1. HTTP 1.0 трохи відрізняється в цьому плані, але це вже зовсім інша історія, тому що всі вигоди від постійних з'єднань доступні тільки, якщо ми будемо використовувати HTTP 1.1 (або вже так робимо).

Часи змінюються

Природно, в реальному світі всі ці утилітарні рішення мають особливість застарівати, разом зі своїм часом і середовищем. Сьогодні у більшості користувачів широкосмуговий доступ в Інтернет, тому найбільш вузьким місцем є вже не клієнтська сторона (клієнтська сторона була, є і буде найбільш вузьким місцем в продуктивності наших веб-додатків, просто потрібно розуміти, як саме можна її оптимізувати у кожному конкретному випадку) , а пропускна здатність каналів в більшості випадків.

Зазвичай затримки при отриманні окремих об'єктів значно більше, ніж час на встановлення нового з'єднання і відправку запиту. Збільшуючи число одночасних з'єднань, ми можемо распараллелить це місце і набагато швидше пробитися через безліч об'єктів, які знаходяться в списку очікуваних до завантаження, що призведе, в результаті, до збільшення відчувається швидкості завантаження у користувача «до швидкості блискавки».

На жаль, покладатися на те, що користувачі самі будуть змінювати налаштування свого браузера (а про те, як це можна зробити, піде мова в восьмому розділі) - це буде не найкращою стратегією щодо оптимізації. Так що ж робити розробнику, щоб домогтися того ж ефекту зі свого боку?

«Ріжемо» з'єднання

Завантаження при двох соедіненіяхНебольшіе зображення (наприклад, товарів в магазині або фотографій до новин), за замовчуванням, завантажуються з батьківського хоста, тому вони також змушені використовувати ті ж два доступних з'єднання. Нижче представлена ​​приблизна діаграма завантаження об'єктів на сторінці.

Обходимо обмеження браузера на число з'єднань, creative way projects

Мал. 23. Завантаження зображень при двох з'єднаннях. Джерело: www.ajaxperformance.com

На цьому графіку добре видно, що для musicstore.ajaxperformance.com відкрито тільки 2 з'єднання (дана діаграма є модельною і справедлива тільки для IE, у всіх інших браузерах, за замовчуванням, відкривається великі з'єднань): C0 і C2. Ми використовуємо протокол HTTP 1.1, тому нам не потрібно відкривати окреме з'єднання для кожної картинки, але ми як і раніше втрачаємо купу часу на обслуговування індивідуальних запитів до об'єктів. Час на встановлення з'єднання (час до отримання першого байта, блакитна смужка на діаграмі) явно домінує над часом завантаження даних, яке не так велика (червона смужка на діаграмі).

Ви можете, звичайно, налаштувати декілька серверів для обслуговування видачі картинок або інших об'єктів, щоб збільшити число паралельних завантажень. наприклад:

Завантаження при шести соедіненіяхimages3.yoursite.ru Однак кожен з цих піддоменів не зобов'язаний перебувати на окремому сервері.

Краще, більше, швидше

Щоб поліпшити продуктивність, можна створити CNAME-записи в DNS-таблиці для images1.yoursite.ru, images2.yoursite.ru і images3.yoursite.ru, кожна з яких вказує назад на основний хост.

При першому завантаженні продуктивність буде значно краще. Як можна бачити з наведеного нижче графіка, зараз використовується вже 6 з'єднань для завантаження наших картинок.

Обходимо обмеження браузера на число з'єднань, creative way projects

Мал. 24. Завантаження при шести з'єднаннях. Джерело: www.ajaxperformance.com

реальний виграш

Час завантаження сторінки при використанні зменшилася більше ніж на 40%. І ця техніка буде працювати у всіх випадках, коли у вас великий пул запитів до об'єктів, які розташовані на одному сервері.

Цей підхід можна також застосувати, щоб ізолювати окремі частини вашого застосування один від одного. Якщо деякі його елементи вимагають доступу до бази даних і їх завантаження затримується більше, ніж для статичних об'єктів, варто усунути їх з числа тих двох з'єднань, які будуть використовуватися для завантаження картинок на вашому сайті, наприклад, розмістивши їх на піддомені.

підводимо підсумки

Зараз середня веб-сторінка складається більш ніж з 50 об'єктів (для Рунета, за статистичними даними webo.in, ситуація досить схожа: число об'єктів коливається в межах 40-50), тому мінімізація витрат на доставку об'єктів є досить критичною для клієнтської продуктивності. Також можна зменшити число об'єктів на сторінці, якщо використовувати техніку CSS Sprites (або data: URI) і об'єднання текстових файлів на сервері. Так як в даний момент у користувачів досить швидкий канал, то можна досягти зменшення часу завантаження до 40-60% (залежить від загального числа об'єктів). Можна використовувати 2 або 3 хоста для обслуговування об'єктів з одного сервера, щоб «обдурити» браузери в їх обмеження на завантаження декількох об'єктів паралельно.

При цьому потрібно пам'ятати, що збільшення одночасних запитів спричинить задіяння додаткових ресурсів з боку сервера (це може бути, наприклад, як максимальне число відкритих з'єднань або портів, так і додаткові обсяги оперативної пам'яті). Тому даний підхід варто активно іспольовать тільки при наявності «легкого» сервера, який здатний одночасно підтримувати тисячі і десятки тисяч відкритих з'єднань без особливого збитку для продуктивності (наприклад, nginx або 0W).

Варто торкнутися ще одного, дуже цікавого, моменту в оптимізації часу завантаження шляхом збільшення числа паралельних потоків. Полягає він у вирівнюванні і збільшенні розміру одночасно завантажуваних об'єктів, щоб максимально використовувати наявні з'єднання. Наприклад, якщо у вас є 40 картинок по 5 Кб, то набагато вигідніше буде віддавати 10 картинок по 20 Кб з двох хостів, ніж 20 (по 10 Кб) з 4 хостів або 40 - з 8. Загальні затримки в першому випадку будуть мінімальними в силу максимізації ефективної швидкості завантаження даних клієнта.

Можна піти і далі і завантажувати, наприклад, 4 картинки по 50 Кб в 4 потоки, досягаючи просто феноменального прискорення. Однак тут вступає в роль психологічний фактор: користувачеві буде не комфортно, якщо він буде бачити сторінку взагалі без картинок весь час, поки вантажиться 50 Кб, і він може просто піти з сайту.