Для початку визначемо які цілі ставляться перед веб-додатком:
Основною темою статті є маштабованість, але і інші аспекти теж будуть розглядатися. Необхідно одразу зазначачити, що будь який сайт так чи інакше намагається досягнути того, що б функціонувати максимально стабільно, тобто бути доступним абсолютно усім своїм потенсійним відвідувачам в абсолютно кожний момент часу, але часом трапляються і непередачувані ситуації, які можуть стати причиною тимчасової не доступності. Для мінімізації потенсійних збитків необхідно уникати наявності компонентів в системі, потенсійни збій в яких привів би до недоступності будь-якого функціоналу або даних, чи навіть всього сайту в цілому. Таким чином кожний сервер, чи інший копмонент системи має мати хочаб одного дублера (не важливо в якому пержимі він працює: паралельно, чи один підстраховує іншого, знаходячить в пасивному режимі), а дані мають реплекуватися як мінімум в двох екземплярах, дотого ж бажано не на рівні RAID (Redundant Array of Independent Disks), а на фізично різих серверах. Збереження декількох резервних копій даних десь окремо від основної системи, напрклад на спеціальних сервісах, чи навіть на окремому кластері позбавить від багатьох проблем, якщо щось піде не так. Не варто забувати і про фінансову сторону питання: підстраховка на випадок збоїв потребує значних капітало вкладень в обладнання і ці затрати є зміст мінімізувати.
?Маштабування — це властивіть пристрою збільшувати свої можливості шляхом нарошувння числа функциональних блоків, які виконують одні і ті самі функції.
Зазвичай про маштабування починають думати тоді коди один сервер не може впоратися з покладеним на нього завданням. З чим саме він не може впоратися? Робота будь-якого web-сервера по великому рахунку зводиться до основного заняття компютерів — обробка данних. Відповідь на HTTP (чи інший) запит включає в себе деякі операції на деякими данними. Відповідно у нас є дві сутності:
Сервер може не впоратися з своєю роботою по настпним причинам:
В статті піде мова про сумарне навантаження — складність одного запиту може бути зовсім не велика, а от велика їх кількість може “завалити” сервер.
Ми будемо розглядати маштабування на прикладі типового web-проекта, який розвивається, однак розглянуті далі принцими підходять і для застосуваня в інших сферах. Для початку ми розглянемо акхітектуру проекта і просте розподілення її складових частин на декілька серверів, а потім розглянемо маштабування основних складових частин на різні сервери і маштабування обчислень і данних.
??
Життя типового сайту починається з дуже простої архітектури — це один web-сервер (зазвичай в його ролі виступає apache), який займається усією роботою по обслуговуванню http-запитів, одержаних від відвідувачів. Від віддає клієнтам статичну інформацію (статику), тобто файли які зберігаються на жорсткому диску сервера і не потребують додаткової обробки:
Той же сервер відповідає на запити, які потребують обчислень — це за звичай формування html-сторінок, хоча іноді динамічно створуються і зображення і інші файли. Найчастіше відповіді на такі запити формуються скриптами написаними на php, perl, або інших мовах.
Мінуси такої простої схеми роботи в тому що різні по характеру запити обробляються одним і тим же web-сервером:
Обчислювальні запити потребують тримати постійно в памяті багато інформації і можуть займати багато обчислювальних ресурсів:
Видача статичної інформації, навпаки потребують мало ресурсів процесора, але можуть займати великий проміжок часу, якщо у користувача повільний канал звязку.
Внутрішя структура сервера apache зроблена таким чином, що кожне зєднання опрацьовується окремим запитом. Це дуже зручно для роботи скриптів, ожнак не оптимально для опрацювання простих запитів. Отже виходить, що тяжкі процеси apache магато часу проводять в режимі очікування (зпочатку при отриманні запиту, потім при відправки відповіді), дарма займають память сервра.
Вирішення цієї проблеми — розподілення роботи по обробці запитів між двома серверами, тобто розділення на frontend та backend. Легкий frontend-сервер виконує задачі по віддачі статичної інформації, а інші запити перенапрвляє (проксує) на backend, де виконується формування сторінок. Очікування повільних клієнтів бере на себе frontend, і якщо він використовує мультиплексування (коли один процес обслуговує декілька клієнтів — так працюють наприклад nginx та lighttpd), то очікування практично нічого не вартує.
Серед інших компоентів сайту варто відмітити базу данних, в яких зазвичай зберігаються основні данні системи, найпополярніші безкоштовні СУБД це MySQL та PostgreSQL. Часто також виділяють сховише бінарних файлів, де зберігаються малюнки (напрклад ілюстарції до сайту, аватари, фотографії) або інші файли.
Таким чином ми отримали схему архітектури, яка складається з декілької компонент.
Зазвичай на початку життя сайту всі компоненти архітектури розташовуються на одному сервері. Якщо він перестає справятися з нагрузками, то є просте рішення — винести на інший сервер частини архітектури, які найлегше відділяються. Найпростіше розпочати з бази днних — перенести на окремий сервер і змінити реквізити доступа до бази данних в скриптах. Доречі в цей момент ми зіштовхуваємося з важливістю правельної архітектури програмного коду. Якщо робота з базою данних винесена в окремий модуль, загальний для всього сайту — то підправити параметри зєднання буде дуже просто.
Шлях подальшого розмеження компонет вже зрозмілий — наприклад можна винести frontend на окремий сервер. Але зазвичай frontend потребує мало системних ресурсів і на цьому етапі його відділення не дасть суттевого приросту продуктисності. Найчастіше сайт вперається в продуктивність скриптів — тобто формування відповіді (html-сторінки) займає занадто багато часу. Тому наступним кроком зазвичай є маштабування backend-сервера.
?
Типова ситуація для сайту який росте — база данних вже винесена на окремий сервер, розділено frontend та backend, однак відвідуваність продовжує підніматися і backend не встигає обробляти запти від користувачів. Це означає, що нам необхідно розподілити обчисленя на декілька серверів. Зробити це доволі просто — достатньо купити другий сервер і поставити на нього програми і скрипти, які необхідно для роботи backend. Після цього потрібно зробити так що б запити від користувачів розподілялися (балансували) мід отриманими серверами. Про різні способи балансування буде розказано нише, а покишо відмітемо що зазвиай цим займається frontend, який налаштовують так що б запити рівномірно розподілялися між серверами.
Важливо що б усі backend-сервери були у взмозі правельно відповідати на запити. Однак для цього необхідно що б кожний з них працював з одними і тим же актуальними данними. Якщо ми зберігаємо всю інформацію в єдиній базі данних, тоді СУБД сама забезпечить сумістний доступ і узгоджувати данні. Однак є деякі данні, які зберігаються локально на сервері (наприклад php-сесії), тобто варто подумати про переніс їх в загальне сховише, або про більш складному алгоритму розподілення запитів.
Розподілення між декількома серверами можна не тільки роботу скріптів, але й обчислення самої бази данних. Якщо СУБД виконує багато складних запитів які займають процесорний час сервера, можна створити декілька копій баз даних на різних серверах. При цьому винакає питання синхронізації даних при зміні і тут є декілька підхоів:
Можливі різні варіанти розподілення системи між серверами. Наприклад, у нас може бути один сервер бази даних і декілька backend-серверів (дуже типова ситуація), або навпаки — один backend і декілька БД. А якщо ми маштабуємо і backend-сервери, і базу даних, то можливо обєднати backend і копію бази на одній машині. В будь-якому випадку у нас зявиться декілька екземплярів якогось сервера і виникає питання, як правельно розподілити нагрузку між ними.
Нехай ми створили декілька серверів (будь якого призачення — http, даза даних і т.д.), кожний з яких може опрацьовувати запити. Перед нами постає питання — як розподілити між ними равантаження, як дізнатися на який сервер відпраляти запит? Можливо два осовних способа розподілення запитів:
Зрозуміло, існує і комбіноції цих підходів. Наприклад, такий відомий метод розподілення нагрузки, як DNS-балансування, основана на тому, що визначенні IP-адрес сайту клієнту видається адреса одного з декількох однакових серверів. Тиким чином, DNS виступає в ролі вузла балансування, від якого клієнт отримує розподілення. Однак сама структура DNS-серверів передбачає відсутність точки відмови за рахунок дублювання — тобто тут використовується переваги обох методів. Звісно у такого способу балансування має і мінуси — наприклад, таку систему тяжко денамічно перебудовати.
Робота з сайтом зазвичай не обмежується одним запитом. Тому при проектування важливо зрозуміти, чи можуть послідовні запити клінта бути конектно опрацьовані серверами, чи клінт має бути привязаний до одного сервера на час роботи з сайтом. Це особливо важливо якщо, якщо на сайті зберігається тимчасова інформація про сесію роботи користувача (в цьому випадку також можливе відльне розподілення — однак тому необідно зберігати сесію в загальному для всіх серверів місці). “Привязати” відвідувача до конкретного сервера можна можна по його IP-адресі (яка, також може змінюватися), або по cookie (в яку зазделегідь записано ідентифікатор сервера), або навіть просто перенаправляти його на потрібний домен.
З іншої сторони, обчислювальні сервери можуть бути і не рівноправними. В деяких випаках вигідно робити навпаки, виділити окремий сервер для обробки якогось одного питу — і отримати вертикальне розділення функції. Тоді клієнт або вузол балансування будуть вибирати сервер в залежності від типа отриманого запиту. Такий підхід дозволить відділити важливі (або навпаки, не критичні, але тяжкі) запити від інших.
Ми зрозуміли як розділяти обчислення, тому велика відвідуваність для нас вже не проблема. Однак обєм даних продовжує рости, зберігати та обробляти їх стає все більш складніше — а отже прийшов час будувати розподілене сховише данних. В цьому випадку у нас вже не буде одного чи декількох серверів, які місять повну копію бази даних. Замість цього, дані будуть розподілені по різних серверам. Які можливі схеми розподілення?
Горизонтальне розбитя даних дозволяє зберігати необмежену кількість полів, однак укладнює вибірку. Найбільш ефективно можна вибрати записи тільки коли відомо, на якому сервері вони зберігаються.
Для вибору правельної схеми розподіленя даних необхідно уважно проаналізувати структуру бази. Існуючі таюлиці (і можливо окремі поля) можна класифікувати по частоті доступа до записів, по частоті обновлень і по взаємозвязкам (необіхності робити виборку з декількох таблиць).
Як вказалося више, окрім бази даних сайту часто необіхно сховише для бінарних файлів. Розподілення системи зберігання файлів (фактично, файлової системи) можна розділити на 2 класи:
Треба відмітити, що розділення даних виріщує не тільки питання зберігання, але й частково питання розділення навантаження — на кожному сервері опиняється менше записів, і тому опрацьовуються вони швидже. Комбінування методів розподілення обчислень і даних дають можливість побудувати потенсійно необмежено-маштабуючу архітектуру, здатну працювати з будь-якою кількістю даних і будь-якими навантаженями.
В наступній статті розгляну приклади практичного застосуваня
Теги: internet, web, оптимізація, цікаві статті