nine-it
msgbartop
msgbarbottom

29 Янв 10 Оптимізація веб систем

Для початку визначемо які цілі ставляться перед веб-додатком:

  • маштабованість — здатність вчасно реагувати на неперервний ріст навантаження і на непередбачуваний наплив користувачів;
  • доступність — надання доступу до додатку навіть у випадку надзвичайного стану;
  • працездатність — навіть найменша затримка при завантажені сторінки може залишити негативне враженя від сайту у користувача.

Основною темою статті є маштабованість, але і інші аспекти теж будуть розглядатися. Необхідно одразу зазначачити, що будь який сайт так чи інакше намагається досягнути того, що б функціонувати максимально стабільно, тобто бути доступним абсолютно усім своїм потенсійним відвідувачам в абсолютно кожний момент часу, але часом трапляються і непередачувані ситуації, які можуть стати причиною тимчасової не доступності. Для мінімізації потенсійних збитків необхідно уникати наявності компонентів в системі, потенсійни збій в яких привів би до недоступності будь-якого функціоналу або даних, чи навіть всього сайту в цілому. Таким чином кожний сервер, чи інший копмонент системи має мати хочаб одного дублера (не важливо в якому пержимі він працює: паралельно, чи один підстраховує іншого, знаходячить в пасивному режимі), а дані мають реплекуватися як мінімум в двох екземплярах, дотого ж бажано не на рівні RAID (Redundant Array of Independent Disks), а на фізично різих серверах. Збереження декількох резервних копій даних десь окремо від основної системи, напрклад на спеціальних сервісах, чи навіть на окремому кластері позбавить від багатьох проблем, якщо щось піде не так. Не варто забувати і про фінансову сторону питання: підстраховка на випадок збоїв потребує значних капітало вкладень в обладнання і ці затрати є зміст мінімізувати.

Основи маштабування

?Маштабування — це властивіть пристрою збільшувати свої можливості шляхом нарошувння числа функциональних блоків, які виконують одні і ті самі функції.

Зазвичай про маштабування починають думати тоді коди один сервер не може впоратися з покладеним на нього завданням. З чим саме він не може впоратися? Робота будь-якого web-сервера по великому рахунку зводиться до основного заняття компютерів — обробка данних. Відповідь на HTTP (чи інший) запит включає в себе деякі операції на деякими данними. Відповідно у нас є дві сутності:

  • данні (характерезуються своїм обємом);
  • підрахунки (характерезуються своєю складністю).

Сервер може не впоратися з своєю роботою по настпним причинам:

  • причині великого обєму данних (вони можуть фізично не поміститися на сервері);
  • причині великого наватаження під час обчислування.

В статті піде мова про сумарне навантаження — складність одного запиту може бути зовсім не велика, а от велика їх кількість може “завалити” сервер.

Ми будемо розглядати маштабування на прикладі типового web-проекта, який розвивається, однак розглянуті далі принцими підходять і для застосуваня в інших сферах. Для початку ми розглянемо акхітектуру проекта і просте розподілення її складових частин на декілька серверів, а потім розглянемо маштабування основних складових частин на різні сервери і маштабування обчислень і данних.
??

Типова архітектура сайту

Життя типового сайту починається з дуже простої архітектури — це один web-сервер (зазвичай в його ролі виступає apache), який займається усією роботою по обслуговуванню http-запитів, одержаних від відвідувачів. Від віддає клієнтам статичну інформацію (статику), тобто файли які зберігаються на жорсткому диску сервера і не потребують додаткової обробки:

  • малюнки (gif, jpg, png, …);
  • листи стилів (css);
  • клієнтські скрипти (js, swf).

Той же сервер відповідає на запити, які потребують обчислень — це за звичай формування 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-сесії), тобто варто подумати про переніс їх в загальне сховише, або про більш складному алгоритму розподілення запитів.

Розподілення між декількома серверами можна не тільки роботу скріптів, але й обчислення самої бази данних. Якщо СУБД виконує багато складних запитів які займають процесорний час сервера, можна створити декілька копій баз даних на різних серверах. При цьому винакає питання синхронізації даних при зміні і тут є декілька підхоів:

  • синхронізація на рівні додатків. У цьому випадку наші скрипти самостійно записують зміни на всі копії бази даних (і самі несуть відповідальність за адекватність данних). Це не найкрашій варіант, оскільки він потребує обережності при реаізації і дуже нестійкий дод помилок;
  • реплікація — автоматичне теражування змін зроблених на одному сервері на всі інші. Зазвичай при використанні реплікацій зміни заносяться на один і тойже сервер (його називають master), а його копії — slave. В більшості СУБД є вбудовані методи для організації реплікації. Розрізняють :
  • синхронну реплікацію — в цьому випадку запит на зміну даних буде очікувати поки данні будуть скопійовані на всі копії бази даних і тільки при цьому завершиться вдало;
  • асінхронну — в цьому випадку зміни скопіюються на slave-сервер з затримкою, і через це запит на зміну виконується швидше.
  • Multi-master реплікація. Цей метод аналогічний попередніму, але ми можемо проводити зміни даних, звертаючись не до одного визначеного сервера, а до будь-якої копії бази. При цьому зміни синхронно, або асинхронно попадають на інші копії бази даних. Іноді таке схему називають терміном “кластер бази данних”.

Можливі різні варіанти розподілення системи між серверами. Наприклад, у нас може бути один сервер бази даних і декілька backend-серверів (дуже типова ситуація), або навпаки — один backend і декілька БД. А якщо ми маштабуємо і backend-сервери, і базу даних, то можливо обєднати backend і копію бази на одній машині. В будь-якому випадку у нас зявиться декілька екземплярів якогось сервера і виникає питання, як правельно розподілити нагрузку між ними.

Методи балансування

Нехай ми створили декілька серверів (будь якого призачення — http, даза даних і т.д.), кожний з яких може опрацьовувати запити. Перед нами постає питання — як розподілити між ними равантаження, як дізнатися на який сервер відпраляти запит? Можливо два осовних способа розподілення запитів:

  • Вузол балансування. В цьому випідку клієнт посилає запит на один фіксований, відомий йому сервер, а той вже перенаправляє запит на один з робочих серверів. Типовий приклад — сайт з один fronend і декількома backend-серверами, на які проксують запити. Однак клієнт може знаходитися і в середині нашої системи — наприклад скрипт може посилати запит до проксі-сервера бази даних, який передає запит одному з серверів СУБД. Сам вузол балансуваня може працюватияк і на окремомоу сервері, там і на одному з робочих серверів.Перевага цього підходу в тому що кліенту нічого не треба знати про внутрішню структура системи — про кількісь серверів, про їх адреси і особливостях — цією інформацією володіє тільки балансувальщик. Однак недолік в тому, що баласувальний вузол є єдтною точною відмови системи — якщо він вийде з ладу — то вся система стане не працездатною. Окрім того при великому навантаженні балансувальний вузол може просто перестати виконувати свою роботу, тому такий підхід не завжди є прийнятним;
  • Балансування на стороні клінта. Якшо ми хочемо позбавитися єдиної точки відмови, існує альтернативний варіант — доручити вибір сервера самому клінту. В цьому випадку клінт має знати про внутрішню структуру нашої системи, що б вміти правельно вибирати, до якого сервера йому звертатися. Незаперчним плюсом є відсутність точки відмови — при відмові одного з серверів клінт сможе звернутися до іншого. Однак платою за це є ускладнення логікі клінта і менша гнучкість балансування.
балансування за допомогою вузла балансування

балансування за допомогою вузла балансування

балансування на стороні клієнта

балансування на стороні клієнта

Зрозуміло, існує і комбіноції цих підходів. Наприклад, такий відомий метод розподілення нагрузки, як DNS-балансування, основана на тому, що визначенні IP-адрес сайту клієнту видається адреса одного з декількох однакових серверів. Тиким чином, DNS виступає в ролі вузла балансування, від якого клієнт отримує розподілення. Однак сама структура DNS-серверів передбачає відсутність точки відмови за рахунок дублювання — тобто тут використовується переваги обох методів. Звісно у такого способу балансування має і мінуси — наприклад, таку систему тяжко денамічно перебудовати.

Робота з сайтом зазвичай не обмежується одним запитом. Тому при проектування важливо зрозуміти, чи можуть послідовні запити клінта бути конектно опрацьовані серверами, чи клінт має бути привязаний до одного сервера на час роботи з сайтом. Це особливо важливо якщо, якщо на сайті зберігається тимчасова інформація про сесію роботи користувача (в цьому випадку також можливе відльне розподілення — однак тому необідно зберігати сесію в загальному для всіх серверів місці). “Привязати” відвідувача до конкретного сервера можна можна по його IP-адресі (яка, також може змінюватися), або по cookie (в яку зазделегідь записано ідентифікатор сервера), або навіть просто перенаправляти його на потрібний домен.

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

Розподілення даних

Ми зрозуміли як розділяти обчислення, тому велика відвідуваність для нас вже не проблема. Однак обєм даних продовжує рости, зберігати та обробляти їх стає все більш складніше — а отже прийшов час будувати розподілене сховише данних. В цьому випадку у нас вже не буде одного чи декількох серверів, які місять повну копію бази даних. Замість цього, дані будуть розподілені по різних серверам. Які можливі схеми розподілення?

  • Ветрикальне розподіленя (vertical partitioning) — в найпростшому випадку є винесення окремих таблиць бази данних на інших сервер. При цьому нам знадобиться змінити скріпти, щоб звертатися до різних серверів за різними даними. В ідеалі ми можемо зберігати кожну таблицю на окремомжу сервері (хоча на практиці це навряд буде вигідно). Очевидно, що при такому розподіленю ми втрачаємо можливість робити SQL-запити, обєднуючі дані з різних таблиць, які знаходяться на різних серверах. За необхідності можна реалізувати логіку обєднання в програмі, але це буде не на стільки ефективно, як в СУБД. Тому при розбиті бази даних потрібно проаналізувати звязок між таблицями, що б рознести максимально незалежні таблиці. Більш складний випадок вертикального розмеження бази — це декомпозиція одної таблиці, коли частина її стовбців опиняється на одному сервері, а ініша на іншому. Такий прийом зустрічається рідше, але він може використовуватися наприклад для розокремлення маленьких даних, які часто використовуються від великого обєму даних які рідко використовуються.
  • Горизонтальне розділення (horizontal partitioning) — полягає в розподіленням даних одної таблиці на декілька серверів. Фактично на кожному сервері створюються таблиці такоїж структури і в них зберігається порція даних. Розподіляти дані між серверами можна по різних критеріям:
  • по діапазону (записи з id<10000 ідуть на сервер А, інші на сервер Б);
  • по списку значень (записи типу “ТОВ”, “ВАТ” ідуть на сервер А, ініші на сервер Б);
  • по значенню хеш-функції від деяких полів;
  • інші критерії.

Горизонтальне розбитя даних дозволяє зберігати необмежену кількість полів, однак укладнює вибірку. Найбільш ефективно можна вибрати записи тільки коли відомо, на якому сервері вони зберігаються.

Для вибору правельної схеми розподіленя даних необхідно уважно проаналізувати структуру бази. Існуючі таюлиці (і можливо окремі поля) можна класифікувати по частоті доступа до записів, по частоті обновлень і по взаємозвязкам (необіхності робити виборку з декількох таблиць).

Як вказалося више, окрім бази даних сайту часто необіхно сховише для бінарних файлів. Розподілення системи зберігання файлів (фактично, файлової системи) можна розділити на 2 класи:

  • ті які працюють на рівні операційної системи. При цьому для програми робота з файлом в такій сисемі не відрізняється від звичайної роботи з файлами. Обмін інформації між серверами бере на себе операційна система. В якості прикладів таких файлових систем можна навсети всім давно відоме сімейство NFS або менш відому, але більш сучасну систему Luster;
  • ті які працюють на рівні програми розподілені сховиша мають на увазі, що робота по обімну інформаціїєю виконує сама програма. Зазвичай функції роботи з сховишем для зручності виносять в окрему бібліотеку. Одним з якскраших прикладів такого сховиша є — MogileFS, розроблена творцями LiveJournal. Другий розповсюджений приклад — використання протокола WebDAV та підтримуючого його сховища.

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

В наступній статті розгляну приклади практичного застосуваня

Схожі пости на блозі

  • Оптимізація веб систем (Приклади практичного застосуваня)
    В попередній статті "Оптимізація веб систем" була більш теоритична частина. тепер розглянемо більш практичну частину. При розробці стратегій росту системи доводиться шукати компроміс між ціною, часом розробки, фінальною продуктивністю, стабільністю і щ...
  • Якби Ґугль був українським державним підприємством, то…
    Недавно наткнувся на кумендну статтю про наш улюблений гугл і вирішив викласти її: Якби Гугль був українським державним підприємством, то... Пошукові запити потрібно було б подавати у письмовій формі, на спеціальному бланку, у вівторок та четвер з дев...
  • Google опублікував рейтинг найбільш відвідуваних сайтів Мережі
    Google опублікував на сайті сервісу AdPlanner призначений для рекламодавців рейтинг тисячю найбільш відвідуваних ресурсів інтернету. Сайти в рейтингу відсортовані за кількістю унікальних користувачів на місяць. Крім того, зазначено кількість переглядів ст...

Теги: , , ,

Прокоментуй!

(Обов’язково)
(Обов’язково, не публікується)