Однокласники: архітектура та платформа проекту

У цьому пості розповімо про накопичений за 5 років досвіді по підтриманню високонавантаженого проекту. Сподіваємося, що колегам-розробникам буде цікаво дізнатися, що і як ми робимо, які проблеми і труднощі у нас виникають і як ми справляємося з ними.


Базова статистика

До 2.8 млн. користувачів в онлайні в години пік
7500000000 запитів в день (150 000 запитів в секунду в години пік)
2400 серверів, систем зберігання даних
Мережевий трафік в годину пік: 32 Gb / s


Архітектура


Листкова архітектура:

• presentation layer (презентаційний шар або попросту WEB сервера, що формують HTML)
• business services layer (сервера, що забезпечують підбір та обробку даних)
• caching layer (кешування часто використовуваних даних)
• persistence layer (сервера БД)
• common infrastructure systems (системи логування статистики, конфігурації додатків, локалізація ресурсів, моніторинг)


Презентаційний шар:

• Використовуємо свій фреймворк, який дозволяє будувати композицію сторінок на мові JAVA, використовуючи власні GUI фабрики (оформлення тексту, списки, таблиці, притулити).
• Композиція сторінок складається з незалежних блоків (зазвичай портлетів), що дозволяє оновлювати інформацію на екрані частинами, використовуючи AJAX запити. Такий підхід до навігації дозволяє позбутися від постійних перезавантажень сторінки, тим самим важливі функції сайту (Повідомлення, Обговорення та Сповіщення) завжди доступні користувачеві. Без javascript сторінка повністю працездатна, крім функціональностей, написаних на GWT – при переходах по посиланнях вона просто повністю перемальовується.
• Функціональні компоненти як Повідомлення, Обговорення та Сповіщення, а також всі динамічні частини (шорткати меню, фотомітки, сортування фотографій, ротирование подаруночків) написані, використовуючи фреймворк Google Web Toolkit.


Підбір, обробка та кешування даних:

Код написаний на Java. Є винятки – деякі модулі для кешування даних написані на C і C + +.
Java тому, що це зручний для розробки мову, багато напрацювань у різних сферах, бібліотек, open source проектів на Java.
На рівні бізнес логіки розташовуються порядку 25 типів серверів / компонентів і кешей, які спілкуються між собою через віддалені інтерфейси. Кожну секунду відбувається близько 3000000 віддалених запитів між цими модулями.
Для кешування даних використовується “самописних” модуль odnoklassniki-cache. Він надає можливість зберігання даних в пам’яті засобами Java Unsafe. Кешіруем всі дані, до яких відбувається часте звернення. Наприклад: інформацію з профайлів користувачів, групи користувачів, інформацію про самих групах, звичайно ж, граф зв’язків користувачів, граф зв’язків користувачів і груп, свята користувачів, деяку мета інформацію про фотографії і т.п.
Для прикладу, один із серверів, кешируючого граф зв’язків користувачів, в годину пік здатний обробити близько 16 600 запитів в секунду. CPU при цьому зайнятий до 7%, максимальний load average за 5 хвилин – 1.2. Кількість вершин графа> 85 мільйонів, зв’язків 2500 мільйона (два з половиною мільярди). У пам’яті граф займає 30 GB.


Розподіл і балансування навантаження:

• зважений round robin всередині системи;
• вертикальне і горизонтальне партіціонірованіе даних як в базах даних, так і на кешируючого рівні;
• сервера на рівні бізнес логіки розбиті на групи. Кожна група опрацьовує різні події. Є механізм маршрутизації подій, тобто будь-яка подія (або групу подій) можна виділити і направити на обробку на певну групу серверів.
Управління сервісами відбувається через централізовану систему конфігурації. Система самописні. Через WEB інтерфейс можна поміняти розташування портлетів, конфігурацію кластерів, змінити логіку деяких сервісів і т.д. Змінена конфігурація зберігається в базі даних. Кожен з серверів періодично перевіряє, чи є оновлення для додатків, які на ньому запущені. Якщо є – застосовує їх.


Дані, сервера БД, резервні копії:

Загальний обсяг даних без резервування – 160 TB. Використовуються два рішення для зберігання і сервірування даних – MS SQL і BerkeleyDB. Дані зберігаються як мінімум в двох копіях. Залежно від типів даних, копій може бути від двох до чотирьох. Є щодобовий бекап всіх даних. Кожні 15 хвилин робляться резервні копії накопичилися даних. В результаті такої стратегії резервного копіювання максимально можлива втрата даних – 15 хвилин.


Устаткування, датацентри, мережа:

Використовуються двопроцесорні, 4-х ядерні сервера. Об’єм пам’яті від 4 до 48 GB, залежно від функціонала. Залежно від типів і використання даних, вони зберігаються або в пам’яті серверів, або на дисках серверів, або на зовнішніх системах зберігання.
Все обладнання розміщене в 3 датацентрах. Всього близько 2400 серверів і систем зберігання даних. Датацентри об’єднані в оптичне кільце. На даний момент на кожному з маршрутів ємність становить 30 Gb / s. Кожен з маршрутів складається з фізично незалежних один від одного оптоволоконних пар. Ці пари агрегуються в загальну “трубу” на кореневих маршрутизаторах.
Мережа розділена на внутрішню і зовнішню. Мережі розділені фізично. Різні інтерфейси серверів підключені в різні комутатори і працюють в різних мережах. За зовнішньої мережі WEB сервера, спілкуються зі світом. За внутрішньої мережі все сервера спілкуються між собою.
Топологія внутрішньої мережі – зірка. Сервера підключені в L2 комутатори (access switches). Ці комутатори підключені як мінімум двома гігабітними лінками до agregation стеку маршрутизаторів. Кожен лінк йде до окремого комутатора в стек. Для того, щоб ця архітектура працювала, використовуємо протоколRSTP. При необхідності, підключення access комутаторів до agregation стеку здійснюються більш ніж двома лінками. Тоді використовується link aggregation портів.
Agregation комутатори підключені 10Gb лінками в кореневі маршрутизатори, які забезпечують як зв’язок між датацентрах, так і зв’язок із зовнішнім світом.
Використовуються комутатори і маршрутизатори від компанії Cisco. Для зв’язку із зовнішнім світом ми маємо прямі підключення з кількома найбільшими операторами зв’язку
Мережевий трафік в години пік – 32 Gb / s


Система статистики:

Існує бібліотека, що відповідає за логування подій. Бібліотека використовується у всіх модулях. Вона дозволяє агрегувати статистику і зберігати її в тимчасову БД. Саме збереження відбувається за допомогою бібліотеки log4j. Зазвичай зберігаємо кількість викликів, максимальне, мінімальне та середнє час виконання, кількість помилок, що виникли при виконанні.
З тимчасових баз вся статистика зберігається у DWH. Кожну хвилину сервера DWH ходять у тимчасові бази в production і забирають дані. Тимчасові бази періодично очищаються від даних.


Приклад коду, який зберігає статистику про відісланих повідомленнях:

public void sendMessage(String message) {
long startTime = LoggerUtil.getMeasureStartTime();
try {
/**
* business logic – send message
*/
LoggerUtil.operationSuccess(LogFactory.getLog({logs appender name}), startTime, “messageService”, “sendMessage”);
} catch (Exception e) {
LoggerUtil.operationFailure(LogFactory.getLog({logs appender name}), startTime, “messageService”, “sendMessage”);
}
}

Наша система DWH зберігає всю статистику і надає інструменти для її перегляду та аналізу. Система побудована на базі рішень від Microsoft. Сервера баз даних – MS SQL 2008, система генерації звітів – Reporting services. Зараз DWH – це 13 серверів, що знаходяться у відокремленій від production середовищі. Деякі з цих серверів забезпечують операційну статистику (тобто онлайн статистику). Деякі відповідають за зберігання та надання доступу до історичній статистиці. Загальний обсяг статистичних даних – 13 TB.
Планується впровадження мультіразмерного (multi-dimension) аналізу статистики на основі OLAP.


Моніторинг


Моніторинг розділений на дві складові:

1. Моніторинг сервісів і компонентів сайту
2. Моніторинг ресурсів (устаткування, мережа)
Первинний моніторинг сервісів. Система моніторингу своя, заснована на оперативних даних в DWH. Є чергові, чий обов’язок моніторити показники роботи сайту та в разі будь-яких аномалій вживати дії для з’ясування та усунення причин цих аномалій.
У випадку з моніторингом ресурсів, стежимо як за “здоров’ям” обладнання (температура, працездатність компонентів: CPU, RAM, дисків і т.д.), так і за показниками ресурсів серверів (завантаження CPU, RAM, завантаженість дискової підсистеми і т.п.). Для моніторингу “здоров’я” устаткування використаємо Zabbix, статистику по використанню ресурсів серверів і мережі накопичуємо в Cacti.
Сповіщення про найбільш критичних аномаліях приходять по смс, решта оповіщення відсилаються по емейлу.


Технології:

• Операційні системи: MS Windows, openSUSE
• Java, C, C +. Весь основний код написаний на Java. На С і С + написані модулі для кешування даних.
• Використовуємо GWT для додання динаміки WEB інтерфейсу. З використанням GWT написані такі модулі як Повідомлення, Обговорення та Сповіщення
• WEB сервера –Apache Tomcat
• Сервера бізнес логіки працюють підJBoss 4
• Балансувальник навантаження на WEB шарі –LVS. Використовуємо IPVS для балансування на Layer-4
• Apache Lucene для індексування і пошуку текстової інформації
• Бази даних:
MS SQL 2005 Std edition. Використовується багато в чому тому, що так історично склалося. Сервера з MS SQL об’єднані в failover кластера. При виході з ладу однієї з робочих нод, standby нода бере на себе її функції
BerkeleyDB – для роботи з BDB використовується своя, внутрішня бібліотека. Використовуємо BDB, C реалізацію, версії 4.5. Двухнодовие master-slave кластера. Між майстром і Слейв рідна BDB реплікація. Запис відбувається тільки в master, читання відбувається з обох нод. Дані зберігаємо в tmpfs, transaction логи зберігаються на дисках. Кожні 15 хвилин робимо бекап логів. Сервера одного кластера розміщені на різних променях харчування щоб не втратити обидві копії даних відразу.
У розробці нове рішення для зберігання даних. Нам необхідний ще більш швидкий і надійний доступ до даних.
• При спілкуванні серверів між собою використовуємо своє рішення, засноване наJBoss Remoting
• Спілкування з SQL базами даних відбувається за допомогою JDBC драйверів


Люди:

Над проектом працюють близько 70 технічних фахівців. З них 40 розробників, 20 системних адміністраторів та інженерів, 8 тестерів.
Всі розробники розділені на невеликі команди (1-3 чоловік). Кожна з команд працює автономно і розробляє або якийсь новий сервіс, або працює над поліпшенням існуючих. У кожній з команд є технічний лідер чи архітектор. Він відповідальний за архітектуру сервісу, вибір технологій та підходів. На різних етапах розробки до команди можуть примикати дизайнери, тестери і системні адміністратори.
Наприклад, існує окрема команда сервісу Групи. Або команда, що розробляє комунікаційні сервіси сайту (такі як системи повідомлень, обговорень, стрічку активності). Є команда платформи, яка тестує, обкатує та впроваджує нові технології, оптимізує вже існуючі рішення. У даний момент одне із завдань цієї команди – розробка та впровадження високошвидкісного і надійного рішення для зберігання даних.


Основні принципи і підходи в розробці

Розробка ведеться невеликими ітераціями. Як приклад життєвого циклу розробки можна привести 3-х тижневий цикл:
0 тиждень – визначення архітектури
1 тиждень – розробка, тестування на комп’ютерах розробників
2 тиждень – тестування на pre-production середовищі, реліз на production середу

Практично весь новий функціонал робиться “відключається”. Типовий запуск нової “фічі” виглядає таким чином:
1. функціонал розробляється і потрапляє в production реліз
2. через централізовану систему конфігурації функціонал включається для невеликої частини користувачів. Аналізується статистика активності користувачів, навантаження на інфраструктуру
3. якщо попередній етап пройшов успішно, функціонал включається поступово на всі більшої аудиторії. Якщо в процесі запуску нам не подобається зібрана статистика, або недозволено зростає навантаження на інфраструктуру, то функціонал відключається, аналізуються причини, виправляються помилки, відбувається оптимізація і все повторюється з 1-го кроку


Best practices, tricks & tips


Специфіка роботи з СУБД:

• Ми використовуємо як вертикальне, так і горизонтальне партіціонірованіе, тобто різні групи таблиць розташовуються на різних серверах (вертикальне партіціонірованіе), а дані великих таблиці додатково розподіляються між серверами (горизонтальне партіціонірованіе). Вбудований в СУБД апарат партіціонірованія не використовується – вся логіка розташовується на рівні бізнес сервісів.
• Розподілені транзакції не використовуються – всі транзакції тільки в межах одного сервера. Для забезпечення цілісності, пов’язані дані поміщаються на 1 сервер або, якщо це неможливо, додатково програмується логіка відновлення даних.
• У запитах до БД не використовуються JOIN навіть серед локальних таблиць для мінімізації навантаження на CPU. Замість цього використовується денормализация даних або JOIN відбуваються на рівні бізнес сервісів. У цьому випадку JOIN відбувається як з даними з БД, так і з даними з кешу.
• При проектуванні структури даних не використовуються зовнішні ключі, збережені процедури і тригери. Знову ж для зниження навантаження на CPU серверів БД.
• SQL оператори DELETE також використовуються з обережністю – це найважча операція з DML. Намагаємося не видаляти дані зайвий раз або використовуємо видалення через маркер – запис спочатку відзначається як віддалена, а потім видаляється фоновим процесом з таблиці.
• Широко використовуються індекси. Як звичайні, так і кластерні. Останні для оптимізації найбільш частих запитів в таблицю.


Кешування:

• Використовуються кеш сервера нашої власної розробки, реалізовані на Java. Деякі набори даних, як наприклад профілі користувачів, соціальний граф, і т.п. цілком зберігаються в кеші.
• Дані партіціоніруются на кластер кеш серверів. Використовується реплікація партіцій для забезпечення надійності.
• Іноді вимоги до швидкодії настільки великі, що використовуються локальні короткоживучі кеши даних отриманих з кеш серверів, розташовані безпосередньо в пам’яті серверів бізнес логіки.
• Кеш сервера, крім звичайних операцій ключ-значення, можуть виконувати запити за даними, що зберігаються в пам’яті, мінімізують таким чином передачу по мережі непотрібних даних. Використовується map-reduce для виконання запитів і операцій на кластері. В особливо складних випадках, наприклад для реалізації запитів по соціальному графу, використовується мова C. Це допомагає підвищити продуктивність.
• Для зберігання великих обсягів даних в пам’яті використовується пам’ять поза купи Java (off heap memory) для зняття непотрібного навантаження з Java GC.
• Кеші можуть використовувати локальний диск для зберігання даних, що перетворює їх на високопродуктивний сервер БД.


Оптимізація швидкості завантаження та роботи сторінки

• Кешіруем всі зовнішні ресурси (Expires і Cache-Control заголовки). CSS і JavaScript файли мінімізуємо і стискаємо (gzip).
• Для зменшення кількості HTTP запитів з браузера, все JavaScript і CSS файли об’єднуються в один. Маленькі графічні зображення об’єднуються в спрайт.
• При завантаженні сторінки викачуються тільки ті ресурси, які насправді необхідні для початку роботи.
• Ніяких універсальних CSS селекторів. Намагаємося не використовувати типові селектори (по імені тега).
• Якщо необхідні CSS expressions, то пишемо “одноразові”. По можливості уникаємо фільтрів.
• Кешіруем звернення до DOM дереву, а так само властивості елементів, що призводять до reflow. Оновлюємо DOM дерево в “оффлайні”.
• У GWT використовуємо UIBinder і HTMLPanel для створення інтерфейсів.

Корисного читання! Будемо раді питань.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*