Швидке веб-додаток - трепанація мережі

  Психологія — цікава і іноді корисна наука. Численні дослідження показують, що затримка у відображенні веб-сторінки довше 300 мс змушує користувача відволіктися від веб-ресурсу і задуматися: «що за хрень?». Тому прискориться веб-проект до психологічно невоспрінімаемих значень, можна ПРОСТО утримувати користувачів довше. І саме тому бізнес готовий витрачатися на швидкість: $ 80М — щоб зменшити latenсy всього на 1 мс .
 
Однак, щоб прискорити сучасний веб-проект, доведеться кровиночки пустити і грунтовно попорпатися в цій темі — тому базове знання мережевих протоколів вітається. Знаючи принципи, можна без особливих зусиль прискорити свою веб-систему на сотні мілісекунд всього за кілька підходів. Ну що, готові заощадити сотні мільйонів? :-) Наливайте кави.
 
 
 

Післясмак

Це дуже гаряча тема — як задовольнити користувача сайту — і юзабілістов швидше за все змусять мене випити коктейль Молотова, закусити гранатою без чеки і встигнути вигукнути перед вибухом: «несу єресь». Тому хочеться зайти з іншого боку. Широко відомо, що затримка у відображенні сторінки більше 0.3 сек — змушує користувача помітити це і… «прокинутися» від процесу спілкування з сайтом. А затримка у відображенні більше секунди — задуматися на тему: «а що я тут роблю взагалі? чого вони мене мучать і змушую чекати? ».
Тому віддамо юзабелістам їх «юзабелізм», а самі займемося вирішенням практичного завдання — як не турбувати «сон» клієнта і сприяти його роботі з сайтом якомога довше, без відволікань на «гальма».
 
 

Хто відповідає за швидкість

Ну хто, звичайно Ви :-) Інакше навряд чи б Ви почали читати пост. Якщо серйозно, то тут проблема — бо питання швидкості ділять на 2 слабо пов'язані і технологічно, і соціально частини: фронтенд і бекенда. І нерідко забувають про третю ключову складову — мережу.
 
 

Просто HTML

Для початку згадаємо, що перші сайти на початку дев'яностих були… набором статичних сторінок. І HTML — був простим, зрозумілим і лаконічним: спочатку текст, потім текст і ресурси. Вакханалія почалася з динамічною генерацією веб-сторінок і поширенням java, perl і в даний час — це вже плеяда технологій, в числі яких php.
Щоб знизити вплив цих перегонів на життєздатність мережі — навздогін приймають HTTP/1.0 в 1996, а через 3 роки — HTTP/1.1 в 1999. В останньому, нарешті, домовилися — що не потрібно ганяти TCP handshakes з ~ 2/3 швидкості світла (в оптоволокні) туди-суду для кожного запиту, встановлюючи нове з'єднання, а правильніше відкрити TCP-з'єднання один раз і працювати через нього.
 
 

бекенда

 
Додаток
Тут мало що змінилося за останні 40 років. Ну може «пародію» на реляційну теорію додали під назвою NoSQL — яка дає як плюси, так і мінуси. Хоча, як показує практика — користі бізнесу від неї начебто більше (але і безсонних ночей з пошуком відповіді на питання: «хто позбавив дані цілісності і під яким приводом» — стало скоріше більше).
 
     
  1. Додаток та / або веб-сервер (php, java, perl, python, ruby ​​і т.п.) — приймає запит клієнта
  2.  
  3. Додаток звертається до БД і отримує дані
  4.  
  5. Додаток формує html
  6.  
  7. Додаток та / або веб-сервер — віддає дані клієнту
  8.  
Тут все зрозуміло з точки зору забезпечення швидкості:
 
     
  • оптимальний код додатку, без зациклення на секунди
  •  
  • оптимальні дані в БД, індексація, денормализация
  •  
  • кешування вибірки з БД
  •  
 
Більше не будемо говорити про розгін «додатки» — про це написали багато книг і статей і все досить лінійно і просто.
Головне одне — щоб додаток було прозоро і можна було поміряти швидкість проходження запиту через різні компоненти програми. Якщо цього немає — далі можна не читати, не допоможе.
Як цього добитися? Шляхи відомі:
 
     
  • Стандартне логирование запитів (nginx, apache, php-fpm)
  •  
  • Логування повільних запитів БД (опція в mysql)
  •  
  • Інструменти фіксації вузьких місць при проходженні запиту. Для php це xhprof, pinba.
  •  
  • Вбудовані інструменти всередині веб-додатки, наприклад окремий модуль трасування .
  •  
Якщо логів у вас багато і ви заплутується в них — агрегує дані, дивіться процентилю і розподіл. Просто і прямолінійно. Виявили запит більше 0.3 секунди — починайте розбір польотів і так до переможного кінця.
  
 
Веб-сервер
Рухаємося назовні. Веб-сервер. Тут теж мало що сильно змінилося, але може тільки що костилізація — через установку зворотного проксі-веб-сервера перед веб-сервером (fascgi-сервером). Так, це звичайно допомагає:
 
     
  1. тримати значно більше відкритих з'єднань з клієнтами (за рахунок?… да, іншої архітектури кешуючого проксі — для nginx це використання мультиплексування сокетов невеликим числом процесів і низького обсягу пам'яті для одного з'єднання)
  2.  
  3. більш ефективно віддавати статичні ресурси безпосередньо з дисків, які не фільтруючи через код додатку
  4.  
Але питання залишилося — чому apache відразу не стали робити «правильно» і іноді доводиться ставити веб-сервери паровозиком :-)
 
 
Постійні з'єднання
Встановлення TCP-з'єднання займає 1 RTT. Роздрукуйте діаграмку і повісьте перед собою. Ключ до розуміння появи гальм — тут.
 
Ця величина досить тісно корелює з розташуванням вашого користувача щодо веб-сервера (так, є швидкість світла, тобто швидкість поширення світла в матеріалі, є маршрутизація) і може займати (особливо з урахуванням провайдера останньої милі) — десятки і сотні мілісекунд, що звичайно багато. І біда, якщо це встановлення з'єднання відбувається для кожного запиту, що було поширене в HTTP/1.0.
 
Заради цього за великим рахунком і починався HTTP 1.1 і в цьому напрямку розвивається і HTTP 2.0 (в особі spdy ). IETF з Google в даний час намагаються зробити все, щоб вичавити з поточної архітектури мережі максимум — не ламаючи її. А це можна зробити… ну да, максимально ефективно використовуючи TCP-з'єднання, використовуючи їх смугу пропускання якомога щільніше через мультиплексування , відновлення після втрат пакетів і ін
 
Тому обов'язково перевірте використання постійних з'єднань на веб-серверах і в додатку.
 
 
TLS
Без TLS , який спочатку зародився в надрах Netscape Communications як SSL — у сучасному світі нікуди. І хоча, кажуть, Остання «дірочка» в цьому протоколі змусила багатьох посивіти значно раніше терміну — альтернативи практично немає.
Але не всі чомусь пам'ятають, що TLS погіршує «післясмак» — додаючи 1-2 RTT додатково до 1 RTT з'єднанню через TCP. У nginx взагалі за замовчуванням кеш сесій TLS — вимкнений — що додає зайвий RTT.
 
Тому простежте, щоб TLS-сесії в обов'язковому порядку кешуватися — і так ми заощадимо ще 1 RTT (а один RTT таки залишиться, на жаль, як плата за безпеку).
Про бекенда, напевно, все. Далі буде складніше, але цікавіше.
 
 

Мережу. Відстань і пропускна здатність мережі

Часто можна почути — у нас 50МБіт / с, 100Мбіт / с, 4G дасть ще більше… Але рідко можна побачити розуміння, що для типового веб-додатки пропускна здатність не особливо важлива (якщо тільки файли не качати) — набагато важливіше lantency, т. к. робиться багато невеликих запитів по різних з'єднанням і TCP-вікно просто не встигає розгойдатися.
І зрозуміло, чим далі клієнт від веб-сервера, тим довше. Але буває що не можна інакше або важко. Саме тому придумали:
 
     
  1. CDN
  2.  
  3. Динамічне проксінг (CDN-навпаки). Коли в регіоні ставиться наприклад nginx, що відкриває постійні коннекти на веб-сервер і терминирующего ssl. Зрозуміло навіщо? Саме — у рази прискорюється встановлення з'єднань від клієнта з веб-проксі (хендшейкі починають літати), а далі використовується прогріте TCP-з'єднання.
  4.  
Що ще можна зробити… збільшити TCP's initial congestion window — так, це нерідко допомагає, тому що веб-сторінка віддається одним набором пакетів без підтвердження. Спробуйте.
 
Увімкніть відладчик браузера, подивіться час завантаження веб-сторінки і подумайте про latency і способах її зменшення.
 
 
Пропускна здатність
Пам'ятайте, що TCP-віконце з'єднання повинно розігнатися спочатку. Якщо веб-сторінка завантажується менше секунди — віконце може не встигнути збільшитися. Середня пропускна здатність мережі в світі — трохи перевищує 3 Мбіт \ с. Висновок — передавайте через одне встановлене з'єднання якомога більше, «розігрів» його.
 
Допомогти тут може звичайно мультиплексування HTTP-ресурсів усередині одного TCP-з'єднання: передача декількох ресурсів упереміш як в запиті, так і відповіді. І навіть цю техніку включили в стандарт, але недоопісалі і в підсумку вона не злетіла (у chrome її не так давно взагалі прибрали). Тому тут можна поки спробувати spdy, чекати HTTP 2.0 або використовувати таки pipelining — але не з браузера, а з програми безпосередньо.
 
 
 
Шардінг доменів
А як же дуже популярна техніка шардінга доменів — коли браузер / додаток долає обмеження в> = 6 з'єднань на домен, відкриваючи ще по> = 6 і більше сполук на фіктивні домени: img1.mysite.ru, img2.mysite.ru…? Тут весело, тому що з точки зору HTTP/1.1 — це вас найімовірніше прискорить, а з точки зору HTTP/2.0 — це антіпаттерн, т.к. мультиплексування HTTP-трафіку через TCP-з'єднання може забезпечити кращу пропускну здатність.
Так що поки — Шарді домени і чекаємо HTTP/2.0 щоб цього більше не робити. І звичайно — краще виміряти конкретно для вашого веб-додатки та зробити обгрунтований вибір.
 
 

Фронденд

Про відомі речі типу швидкості рендеринга веб-сторінки і розміру зображень і JavaScript, порядку завантаження ресурсів і т.п. — Писати не цікаво. Тема побита і убита. Якщо коротко і неточно — Кешуйте ресурси на стороні веб-браузера, але… з головою. Кешувати 10МБ js-файл і парсити його всередині браузера на кожній веб-сторінці — розуміємо до чого приведе. Включаємо відладчик браузера, наливаємо кави і до результату дня — тренди наявності. Накидаємо план і реалізуємо. Просто і прозоро.
Набагато більш гострі підводні камені можуть ховатися за досить новими і бурхливими мережевими можливостями веб-браузера. Про них і поговоримо:
 
     
  1. XMLHttpRequest
  2.  
  3. Long Pooling
  4.  
  5. Server-Sent Events
  6.  
  7. Web Sockets
  8.  
 
 
Браузер — як операційна система
Спочатку браузер сприймався як клієнтську програму для відображення HTML-розмітки. Але з кожним роком відбувалося перетворення його в центр управління плеядою технологій — у підсумку HTTP-сервер і веб-додаток за ним тепер сприймається лише як допоміжний компонентік всередині браузера. Цікавий технологічне зрушення акцентів.
Більш того, з появою вбудованої в браузер «телестудії» WebRTC і засобів мережевої взаємодії браузера з зовнішнім світом — питання забезпечення продуктивності плавно перемістився від серверної інфраструктури до браузеру. Якщо ця внутрішня кухня у клієнта буде гальмувати — про php на веб-сервері або join в БД ніхто і не згадає :-)
Розберемо на запчастини цей непрозорий моноліт.
 
 
XMLHttpRequest
Це всім відомий AJAX — здатність браузера звертатися до зовнішніх ресурсів по HTTP. З появою CORS — почався досконалий «бєспрєдєл». Тепер щоб визначити причину гальмування, потрібно лазити по всіх ресурсах і дивитися логи скрізь.
Якщо серйозно, технологія безсумнівно підірвала можливості браузера, перетворивши його на потужну платформу динамічного рендеринга інформації. Писати про неї немає сенсу, тема багатьом відома. Однак опишу обмеження:
 
     
  1. знову відсутність мультиплексування декількох «каналів» змушує неефективно і не повністю використовувати пропускну здатність TCP-з'єднання
  2.  
  3. немає адекватної підтримки streaming (відкрив з'єднання і висиш, чекаєш), тобто залишається смикати сервер і дивитися що він відповів
  4.  
 
Проте, технологія дуже популярна і зробити її прозорою з точки зору моніторингу швидкості — нескладно.
 
 
Long Pooling
Як зробити веб-чат? Так, потрібно якось передавати з боку сервера в браузер інформацію про зміни. Напряму через HTTP — не можна, не вміє. Тільки: запит і відповідь. Ось в лоб люди і вирішили: зробити запит і чекати відповідь, секунду, 30 секунд, хвилину. Якщо що-небудь прийшло — віддати у відповідь і розірвати з'єднання.
 
Так, купа антіпаттернов, милиць — але технологія дуже широко поширена і працює завжди. Але, т.к. Ви відповідаєте за швидкість — знайте, навантаження на сервери при такому підході — дуже висока, і може зіставлятися з навантаженням від основної відвідуваності веб-проекту. А якщо оновлення від сервера до браузерів поширюються часто — то може основне навантаження перевищувати в рази!
Що робити-то?
 
 
Server-Sent Events
Тут відкривається TCP-з'єднання з веб-сервером, не закривається і в нього сервер пише різну інфу в UTF-8. Не можна правда бінарні дані передавати оптимально без попереднього Base64 (+33% збільшення в розмірі), але як канал управління в одну сторону — чудове рішення. Правда в IE — не дозволені (див. пункт вище, який скрізь працює).
 
 
Плюси технології в тому, що вона:
 
     
  1. дуже проста
  2.  
  3. не потрібно після отримання повідомлення заново перевідкривати з'єднання з сервером
  4.  
 
 
Web Sockets
Для системного адміністратора це навіть не звір, а скоріше нічний некроморфами . «Хитрим» способом через HTTP 1.1 Upgrade браузер змінює «тип» HTTP з'єднання і воно залишається відкритим.
 
 
Потім по з'єднанню в ОБИДВІ (!) Сторони можна почати передавати дані, оформлені в повідомлення (frames). Повідомлення бувають не тільки з інформацією, а й контрольні, в т.ч. типу «PING», «PONG». Перше враження — знову винайшли велосипед, знову TCP на базі TCP ;-)
З точки зору розробника — звичайно це зручно, з'являється двобічний канал між браузером і веб-додатком на сервері. Хочеш streaming, хочеш messages. Але:
 
     
  1. не дозволені html-кешування, т.к. працюємо через бінарний framing-протокол
  2.  
  3. не дозволені стиск, його потрібно реалізувати самостійно
  4.  
  5. страшні глюки і затримки при роботі без TLS — через застарілі проксі серверів
  6.  
  7. немає мультиплексування, в результаті чого кожне bandwidth кожного з'єднання використовується неефективно
  8.  
  9. на сервері з'являється багато висячих і роблять щось «бридке з базою даних» прямих TCP-з'єднань від браузерів
  10.  
 
Як відстежувати продуктивність Web Sockets? Дуже гарне питання, залишений спеціально на закуску. З боку клієнта — сніффер пакетів WireShark, з боку сервера і з включеним TLS — ми вирішуємо задачу через патчінга модулів для nginx, але мабуть є більш просте рішення.
Головне розуміти, як Web Sockets влаштовані зсередини, а Ви вже це знаєте і контроль за швидкістю — буде забезпечений.
Так що ж краще: XMLHttpRequest, Long Pooling, Server-Sent Events або Web Sockets? Успіх — в грамотному поєднанні цих технологій. Наприклад, можна управляти додатком через WebSockets, а завантажувати ресурси з використанням вбудованого кешування через AJAX.
 
 

Що тепер робити?

Навчитися вимірювати і реагувати на перевищення заданих значень. Обробляйте логи веб-додатки, розбирайтеся з повільними запитами в них. Швидкість на стороні клієнта теж стало можливим міряти завдяки Navigation timing API — ми збираємо дані по продуктивності в браузерах, відправляємо їх засобами JavaScript в хмару, агрегируя в pinba і реагуємо на відхилення. Дуже корисне API, користуйтеся обов'язково.
 
 
 
В результаті ви знайдете себе в оточенні системи моніторингу типу nagiоs , з десятком-другим автоматичних тестів, на яких видно, що зі швидкістю роботи вашої веб-системи все в порядку. А в разі спрацьовувань — команда збирається і приймається рішення. Кейси можуть бути, наприклад, такими:
 
     
  • Повільний запит до БД. Рішення — оптимізація запиту, денормалізація в разі крайньої необхідності.
  •  
  • Повільна відпрацювання коду програми. Рішення — оптимізація алгоритму, кешування.
  •  
  • Повільна передача тіла сторінки по мережі. Рішення (в порядку збільшення вартості) — збільшуємо tcp initial cwnd, ставимо динамічний проксі поряд з клієнтом, переносимо сервери ближче
  •  
  • Повільна віддача статичних ресурсів клієнтам. Рішення — CDN.
  •  
  • Блокування в очікуванні з'єднання з серверами в браузері. Рішення — шардінг доменів.
  •  
  • Long Pooling створює навантаження на сервери, велику ніж хіти клієнтів. Рішення — Server-Sent Events, Web Sockets.
  •  
  • Гальмують, нестійкий працюють Web Sockets. Рішення — TLS для них (wss).
  •  
і т.д.
 
 

Підсумки

Ми пройшлися по основних компонентах сучасного веб-додатки. Дізналися про тренди HTTP 2.0, контрольних точках, які важливо розуміти і навчитися вимірювати для забезпечення швидкості відповіді веб-додатки по можливості нижче 0.3 сек. Заглянули в суть сучасних мережевих технологій, що використовуються в браузерах, позначили їх достоїнства і вузькі місця.

Зрозуміли, що розуміти роботу мережі, її швидкість, latency і пропускну здатність — важливо. І що пропускна здатність важлива далеко не завжди.

Стало зрозуміло, що тепер недостатньо «протюніть» веб-сервер і базу даних. Потрібно розбиратися в букеті мережевих технологій, що використовуються браузером, знати їх зсередини і ефективно ізмерять.Поетому сніффер TCP-трафіку повинен тепер стати вашою правою рукою, а моніторинг ключових показників продуктивності в логах серверів — лівою ногою :-)

Можна спробувати вирішити задачу обробки запиту клієнта за «0.3 сек» по-різному. Головне — визначити метрики, автоматично збирати їх і діяти в разі їх перевищення — докопуватися до кожному конкретному випадку до кореня. У нашому продукті " ми вирішили завдання забезпечення максимально низькою latency завдяки комплексній технології кешування, об'єднуючу технології статичного і динамічного сайту

На закінчення, запрошуємо відвідати нашу технологічну конференцію, яка пройде вже скоро, 23 травня. Всім удачі та успіхів у нелегкій справі забезпечення продуктивності веб-проектів!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.