Використання Amazon Web Services на прикладі wikipaintings.org

Використання Amazon Web Services на прикладі wikipaintings.org

Думаю, шановній спільноті буде цікаво дізнатися про мій досвід розробки інтернет проекту з використанням amazon web services.

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

Що таке wikipaintings.org - www.wikipaintings.org/ru/About

Зараз закінчується перший етап розробки та основні завдання наступного етапу - залучення волонтерів до наповнення сайту.

Якщо комусь здається, що картини - це нудно, оцініть творчість Archimboldo - www.wikipaintings.org/ru/giuseppe-arcimboldo/spring-1573#supersized-artistPaintings-184903

Якщо ж вам цікаво нарешті зрозуміти класифікацію стилів живопису, ласкаво просимо на www.wikipaintings.org/ru/paintings-by-style

Ну а тепер, після того як ви поклали сайт Хаббраеффектом (якщо ще не поклали - кидаємо посилання всім друзям), давайте перейдемо до головної - технічних порад.

Технологічна платформа

Цей проект виконано з використанням ASP.NET MVC, LINQ2SQL, MS SQL Server 2008 R2 і JQuery. Не секрет, що AWS більше орієнтований на JAVA/PHP розробників, але я не відчував себе особливо обділеним.

Пропоную до розгляду мої поради розробникам у порядку традиційних шарів веб додатків.

База даних

Ми почали з централізованої бази даних бізнес об'єктів - за нашими оцінками, досить потужний інстанс здатний обробити потрібну кількість типових запитів клієнтів в найближчому майбутньому (на даний момент це High Cpu Medium Instance). Для найпопулярніших HTTP запитів ми переконалися, що виконується рівно 1 SQL запит, який повертає всі необхідні дані - саме базу даних найскладніше відмасштабувати в даному сценарії.

Важливо сказати рішуче «ні» зберіганню файлів у базі даних. Незважаючи на просунуті можливості SQL Server 2008 це хибний шлях. Не випадково EC2 розшифровується як Elastic Computing Cloud - ваш сервер в першу чергу це просто процесор і його основне призначення вважати, а не зберігати.

Файлів користувачів спочатку буде занадто багато, щоб поміститися на будь-який диск - так що місце їм в S3 - нескінченному і дуже надійному сховищі файлів. Можливо, воно на початку здасться повільним, але його швидкість не змінюється буде з ним працювати 1 ваш процес або 1000.

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

Упаковуйте підлеглі об'єкти разом з основним. Наприклад, зображення зберігається як серіалізований XML у рядку Картини і такий самий XML у рядку художника. Так, це не дуже красиво, але кожен підзапрос це мінімум 0.0005 секунди, і коли ви малюєте все painting на сторінці то цей час потрібно множити на 200.

Також дуже корисна стаття «Відкриття прихованих даних для оптимізації продуктивності програм» http://msdn.microsoft.com/ru-ru/magazine/cc135978.aspx - я щотижня перевіряю, чи коректні індекси (впевнений, що у багатьох вона вже в закладках)

C# / Middle tier

Ведіть облік часу візуалізації сторінки та кожної серйозної операції. Нещодавно засвітився профайлер від stackoverflow, але в цілому можна швидко зробити щось простіше самостійно. У BeginRequest - ініціалізація, EndRequest - перевіряємо, не рендерилась сторінка більше N секунд. Якщо рендерилася більше - пишемо запис у лог помилок. Розставляйте код, що логує минулий час за додатком, коли потрібно зрозуміти, скільки який крок займає. Не завадить вивести такий лог наприкінці masterpage як html коментар, щоб наочно бачити ефект від тюнінгу продуктивності.

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

Обережно ставтеся до вкладених циклів. Нешкідливий на вигляд цикл відмальовки, який в кожному кроці проходить по масиву з використанням Where (), виконується десяту частку секунди. Такий же цикл, перед яким ми конвертуємо масив в Dictionary - виконується вже за соту частку секунди.

Повертайте декілька таблиць з однієї SP навіть якщо ви використовуєте Linq2sql - це можливо і це непогано працює. Я оцінюю накладні витрати за елементарною вибіркою об'єкта за PK в 0.005 секунди; якщо ж така операція йде циклом економія зростає багаторазово. Наприклад, збережена процедура повертає не тільки картину, а й художника, який її написав.

Вичитуйте дані пачками а не по одному запису. Так працює показ результатів пошуку картин. Після отримання списку картин у C # будуємо список id художників і вважаю їх одним підзапросом у словник, а потім призначаю лічені об'єкти відповідним картинам.

Не використовуйте компонентний підхід у його природному вигляді, прищепленому ASP.NET, до компонування сторінки. Це передбачає мінімум параметрів у кожного компонента, що на практиці веде до того, що кожен компонент вичитує юзера, перевіряє його права, читає свої приватні налаштування. Заведіть контекст системи, дійсний рівно на час запиту, куди в міру необхідності збирається вся необхідна інформація і читається вона рівно 1 раз.

Не покладайтеся на outputcache. Це круто, швидко, і це потрібно використовувати - він дозволить знизити навантаження на сервер, але це не панацея. Наприклад, 18 травня 2010 року було 19K page views, з них - 8500 РІЗНИХ (за даними гугл аналітика). До того ж, outputcache власний у кожного процесу - значить, витрати на пам'ять будуть пропорційно кількості об'єктів в системі x кількість серверів. Для головних сторінок, у яких немає параметрів, тривалість кешування може бути досить великою (15 хвилин), а для рідкісних сторінок ми ставимо 30 секунд на випадок публікації цього посилання на хабеолог. З іншого боку добре кешуються ajax запити - у них не так багато параметрів, вони часто повторюються, і їх результат, як правило, менше ніж у HTML сторінки.

Виносьте складні частини в окремі проекти. Типовий сервер хмари досить слабкий, але їх може бути декілька. Наприклад, ми винесли генерацію thumbnails в окремий веб сервіс, що дало нам можливість розмістити його на іншому сервері і захистити швидкість загруки картин при імпорті.

Відкладайте те, що можна зробити не зараз - Амазон надає відмінний, швидкий нескінченний і дешевий (наші витрати на цей сервіс менше 10 центів на місяць) інструмент черга (див. вихідний код № 2).

Використовуйте спільну пам'ять. Наприклад, на сторінці картини (http://www.wikipaintings.org/ru/giuseppe-arcimboldo/portrait-of-eve-1578) ми показуємо інші картини цього художника, які однакові для різних сторінок. Зберігши мінімально необхідну коротку інформацію про картини по кожному художнику в пам'яті ми зменшили час генерації цієї сторінки в 2,5 рази. Можна, звичайно, використовувати Velocity але для нас стала проблемою відсутність підтримки Windows 7, на якій ми розробляємо. Ми написали власний windows service з яким веб додатки спілкуються за remoting. По суті, це приблизне повторення System.Web.Caching.Cache але воно підтримує набір даних однаковий для всіх інстансів.

Клієнтська частина

Перевіряйте ваш висновок різними інструментами - такі утиліти як YSlow, Pagespeed, Firebug - ваші найкращі друзі.

Все що можна ми перекладаємо на cloudfront. Очевидно - картини, thumbnails, але також ми записуємо туди зібраний в 2 файли CSS - один звичайний, 1 - gzip. Важливо саме розширення .gzip, так як .gz Safari не розуміє. Даний прийом продемонстрований у прикладі коду № 1.

Призначайте Expiration - за замовчуванням S3 цього не робить (див. приклад коду № 1). Ви заощадите час користувача і гроші на трафіку. Для цієї операції і керування статичними файлами на s3 взагалі рекомендую cloudberry.

Важливим нюансом для підвищення швидкості завантаження сторінок стало рознесення запитів по різних піддоменах. Протокол http не дозволяє більше 2х запитів до одного сервера одночасно; хоч браузери і роблять до 5ти запитів, завантаження сторінки з 100 + картинками займало більше 10 секунд. Ми рознесли картинки по піддоменах і тепер, за умови наявності хорошого каналу, така ж сторінка завантажується до 8 разів швидше. Для цього створіть в cloudfront набір доменів (у нас - uploads0, uploads1,... uploads8) і вибирайте псевдовипадковий спосіб. Ще краще зареєструвати для цього окремий домен щоб при кожному запиті не передавалися куки але ми визнали це параною.

Не завантажуйте більше інформації, ніж потрібно щоб показати сторінку - все інше можна завантажити потім по ajax. Чим швидше вантажиться сторінка - тим більша лояльність користувача. Головне, зробити симпатичну і адекватну анімацію при підвантаженні даних.

Рекомендації щодо розгортання

Ми використовуємо 1 інстанс централізовано для бази даних, і набір micro інстансів які займаються рендерингом сторінок під управлінням load balancing (Див. статтю про настрій Windows Server 2008 R2 Core.

Сам Load balancing дуже зручний у використанні - для роботи з ним є GUI. Бажано передбачити сторінку стану системи, яку амазон перевірятиме з інтервалом від 6 до 60 секунд (задається). У разі двох (можна більше) негативних результатів (таймаут або код помилки) інстанс оголошується «нездоровим» і запити йдуть на інші сервери. Після того як працездатність відновлюється він знову включається в роботу.

1 load balancing протягом першого року надається безкоштовно.

Бакап бази робиться щодня на окремий EBS диск. Щоб не сталося з вузлом системи, або самою windows, середовищами панелі керування можна буде відключити цей диск від одного віртуального сервера, підключити до нового, підняти бакап і продовжити роботу. Як подальші кроки з підвищення стійкості системи до надзвичайних подій можна створювати snapshot цього диска автоматично.

Процес розробки

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

Під час ітерації вся команда була сконцентрована навколо 3-4 основних завдань, над якими ми продовжували працювати до тих пір, поки не були задоволені.

Після запуску чергової версії реальне життя і реальні користувачі часто вносили корективи, і 1-2 функції йшли на чергову халепу.

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

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

Висновки

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

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

Корисні посилання

1. Робота з S3

2. Робота з SQS

3. Налаштування Windows Server 2008 R2 Core для Micro Intsance

4. SQL Server - Відкриття прихованих даних для оптимізації продуктивності програм

5. Міні профайлер для веб-програм від stackoverflow

Image