Пісня про могутній Деплое: невпинний прозоре розгортання веб-сервісу

Пісня про могутній Деплое

Пролог
Прийшов час, коли нам — команди Ельби   захотілося поділитися з світом подробицями деяких магічних і загадкових деталей нашого продукту. Вирішили почати з одного з найскладніших проектів, який є предметом особливої гордості і легкого поклоніння. Він покритий нальотом таємниці і оповитий ореолом темної магії. Легенди про ньому передаються з вуст в уста. Лише мала частина знань задокументована в вікі або ютреке, велика    прихована в основи системи контролю версій. Премудрих старців, уміють розшифрувати цей таємний код, проекті все менше і менше. Прийшла пора записати всі магічні заклинання в докладному манускрипті. Мова піде про системі розгортання Ельби   могутньому Деплое.

Ельба — це веб-сервіс для підприємців, що допомагає вести бізнес. А робота могутнього Деплоя   оновлювати Ельбу. Коли буде готова нова версія сервісу, Деплой повинен явити її світу, тобто користувачам. Це означає, що всі частини системи повинні бути оновлені і запущені, а всі дані   конвертовані і підготовлені. Наш Деплой справляється зі своєю роботою добре   оновлення Ельби проходять абсолютно непомітно для користувачів, не перериваючи їх роботи. Це дозволяє викладати нові релізи так часто, як потрібно   міру їх готовності. Про те, як ми цього досягли, як безупинно і прозоро для користувачів оновлюється веб-сервіс, і буде розказано далі.

Глава перша. Походження
У давні часи Ельба складалася з невеликого веб-додатки на ASP.Net Web Forms і БД на MS SQL Server. Додаток дозволяло підприємцям з допомогою невеликого візарда підготувати і здати декларацію УСН в податкову інспекцію. З тих давніх пір змінилося багато епох   зараз Ельба дозволяє робити набагато більше. Що саме вона вміє і чим допомагає підприємцям, розповість наш маркетинг і захоплююче читання промосайта.

Нас більше цікавить технічна сторона. Коли Ельба була маленькою, процес доставки був простий і наївний. Додаток жило в датацентрі на двох хостах, захованих за балансировщиком. Щоб оновити обидва програми, програміст заходив руками RDP на продакшн-сервер і копіював в папки на обох хостах заздалегідь скомпільований код. Добрий IIS тут ж підхоплював зміни і перезапускал систему. Щоб оновити дані в базі, доводилося вручну запускати скрипти на SQL-сервері.

З часом кодова база розросталася і набирала силу. З'явилося багато фронтів, що виникли окремо живуть на власних хостах сервіси, роботи, замінюють людей і мріють одного разу захопити світ, додалися інтеграції з сторонніми продуктами і сервісами, ще багато всього різного і цікавого. Спочатку для релізів була написана пачка батников, які спрощували ручна праця при копіюванні. Сорочки розкладали новий дистрибутив всім хостам і запускали. Але незабаром коду стало так багато, що його час копіювання на всі хости непристойно зросла. Батниками стало складно управляти: підтримувати в них актуальний список сервісів і топологію. До   збільшенням кількості користувачів виріс і обсяг даних, який потрібно оновлювати перед новим релізом. Настав час автоматизації.

Ті стародавні часи були дуже суворі. Готових інструментів ніхто не знав, гуглити не вмів і все одно чуже використовувати не став би. Програмісти люблять писати код. Вирішили написати самі. І написали.

Перші версії Деплоя діяли як сокира. Людина запускав консольку, яка спершу збирала весь продукт релізний вигляд. Це включало в себе компіляцію коду і статики сервісів/роботів/фронтів і самого Деплоя. Потім готувалися продакшен-налаштування для всього цього добра: топологія майданчики, адреси, явки, паролі, прапорці, тумблери і магічні константи. Підготовлений дистрибутив передавався в датацентр спеціально навченому віддаленого сервісу, який тільки і умів, що після закінчення передачі запустити той самий чарівний Деплой.

Першим ділом на фронтах з'являлася заглушка для зовнішнього світу «Йдуть технічні роботи». Під її прикриттям Деплой вбивав все, до чого міг дотягнутися. Гасив всю площадку. Вбивав роботів, сервіси, фронти, всі запущені процеси, не жаліючи ні батьківські, ні дочірні, залишаючи за собою випалену землю. Ельба більше не працювала. І на цих руїнах Деплой починав будувати новий, кращий світ. Не поспішаючи розкидав дистрибутив згідно із заданою топологією, підміняв налаштування, виконував скрипти, щоб оновити дані в базі. Потім потихеньку запускав все господарство назад. Після старту самого мееедленного сервісу заглушка знімалася, і радісні користувачі, нарешті, могли потрапити в оновлену систему.

Очевидно, що не всі користувачі і далеко не завжди були раді. У самому вдалому випадку час простою займало хвилин 10-20 пізно ввечері… І добре, коли все проходило добре. При невдалому становищі зірок Деплой несподівано помирав у самому невідповідному місці, не закінчивши роботу, і команда залишалася з розламаної в мотлох майданчиком. Десь щось працювало, де-то немає, а що працювало не як задумано. І в найближчі години чергової безсонної ночі доводилося терміново приводити все в порядок. Техпідтримка з насилу стримувала гнів користувачів, заспокоювала самих засмучених, отпаивая їх валеріаною прямо по телефоном гарячої лінії.

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

Сформувалися нові вимоги до Деплою:
  • мінімальний час простою Ельби, в ідеалі — його відсутність;
  • прозоре оновлення даних;
  • система повинна продовжувати працювати у у разі невдалого релізу;
  • повна автоматизація або мінімум ручних дій, щоб виключити людський фактор;
  • простий код для подальшого поліпшення та розвитку.
Розуміння вимог швидко призвело до усвідомлення того, що без підтримки у основному додатку затія приречена на провал. Не вийде зробити окрему систему розгортання. Треба в самій системі, в базовому коді, підтримувати сценарії релізів, дописувати інфраструктуру, потрібно встановлювати вимоги до коду, до даними, до топології.

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

На березі все звучало як магія, непідвладна смертним.

Настав той момент, коли програмістам в черговий раз довелося засукати рукави і показати світу новий, «кращий» Деплой, більшою магічною силою, позбавлений від недоліків і слабкостей своїх попередників.

Довго чи, коротко з допомогою великого gusev_p вашого покірного слуги з пилу і попелу народився він   могутній неспинний Деплой.

Глава друга. Оточення
Перед описом процесу розгортання і суто технічних подробиць, варто розповісти, з ніж ми мали справу:
  Ельба   веб-сервіс, продукт для Windows-стека, код написаний на C#;
  основне додаток (фронт) — ASP.Net веб-сайт для IIS. Частково Web Forms, частково MVC;
  десяток постійно піднятих standalone сервісів з http-інтерфейсом. Сервіси відтворена для балансування та відмовостійкості;
  десяток роботів, що запускаються планувальником розкладом;
  основне сховище   БД MS SQL Server;
  MongoDB для денормализованных даних і агрегації;
  ElasticSearch для повнотекстового пошуку;
  RabbitMQ для месседжинга.

База SQL використовується як append-only. У коді програми не використовуються UPDATE DELETE, а модифікація і видалення сутностей відбувається через додавання нової ревізії з зміненими полями або ознакою видалення. Номер ревізії   інкрементальний лічильник, наскрізний для одного типу сутностей. З допомогою ORM всередині коду програми з сховища вибираються тільки останні невидалені ревізії кожної конкретної сутності. У результаті такої схеми виходить версіонування і історія змін усіх даних, що дає +86 до магії, яку буде розказано нижче.

Глава третя. Школа магії
Приступаємо до опису роботи Деплоя. Для початку весь процес розгортання релізу був розбитий приблизно на 40 кроків. Кожен крок робить малу частину великої роботи і відповідає тільки за неї. Наступний крок запускається тільки після вдалого завершення попереднього. Більшість кроків може виконуватися паралельно працює Ельбі. У у разі невдачі крок, можливості, повертає систему до вихідного стану.

Як і раніше, маленький спеціально навчений віддалений сервіс отримує новий дистрибутив Ельби і запускає Деплой. Той, не гаючи часу, починає робити свої перші кроки.

Працює стара версія. Фронт спілкується з сервісами. Роботи запущені.Початкові кроки не настільки цікаві. Перевіряється поточна конфігурація, готується файлова система, новий код сервісів копіюється в нові папки на відповідних хостах, готуються завдання в планувальнику. Однотипні завдання распараллелены всім хостам.

Далі Деплою необхідно зайнятися міграцією даних. &Nbsp;цей момент він вступає на територію магії.
У новому релізі програмісти добре попрацювали, написали багато нового коду, створили нові сутності і знатно порефакторили існуючі. У деяких з них змінилися умовчання, з'явилися нові властивості або пішли старі. Тепер замість старої сутності може використовуватися набір з кількох нових, пов'язаних між собою, або навпаки. Де була зв'язок «один-до-одного», могла з'явитися «багато-до-багатьох» і т. д. Проблема в те, що новий код не вміє працювати з старими даними. Перед запуском нового коду існуючі дані необхідно підготувати   мігрувати. При підготовці нового релізу програмісти пишуть відповідні скрипти і утиліти, які змінюють структуру даних в сховище, модифікують і трансформують поточні сутності.

Але старий код теж не вміє працювати з новими даними. І якщо вперед дані мігрувати зазвичай легко, то зворотна міграція складна, а  і неможлива. Якщо новий код запише сутності по-новому, звернути їх в старі не вийде. Відкочувати міграції даних не варто. Тому нехай старий код працює з старими даними, а з новими   лише не перетиналися під часу і просторі.

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

Заклинання #1
Дуже часто міграція   тривалий і не завжди детермінований часу процес. Може знадобитися перекачати мільйони рядків таблиць і гігабайти даних. Але користувачі не хочуть чекати, простий сервісу — це погано. І тут Деплой скористався першим магічним заклинанням   версионной структурою сховища. Вся міграція була розділена на два етапи.

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

Другий етап Деплой виконує окремим кроком перед самим перемиканням версій. На ньому відбувається домиграция нових ревізій сутностей, які з'явилися після першого етапу. Для цього виконуються всі ті ж скрипти і утиліти трансформації, але з зазначенням запам'ятованих раніше ревізій. Це забезпечує обробку тільки накопичених змін.
Половина сервісів оновлена. Роботи зупинені.Після первинної міграції Деплой зупиняє всіх роботів   роботою на час релізу можна пожертвувати. Потім сервіси. Але сервіси потрібні для роботи системи, не можна зупинити їх всі. Ми не захотіли змінювати топологію і налаштування при кожному релізі. Практично завжди топологія нового релізу збігається з топологією вже розгорнутої і працює Ельби. Більшості релізів ця вимога не заважає, бо топологія змінюється рідко, а при необхідності трохи ручних маніпуляцій її легко модифікують.

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

Заклинання #2
Довелося допрацювати базову інфраструктуру системи. Кожен сервіс запускається на визначеному наборі параметрів, в яких тепер з'явилася версія релізу, зростаюча з кожним новим розгортанням. Правильно вказати версію налаштуваннях сервісу та підтримувати журнал   завдання Деплоя. Всі сервіси, включаючи фронт, вміють спілкуватися тільки в межах однієї версії. Якщо один сервіс робить запит на інший старий або новий, замість обробки запиту повертається специфічну відповідь. Потім цей сервіс потрапляє в чорний список, а запит йде на іншу репліку.
Туман згущується. Деплой впритул підійшов до території самої темної магії. Підійшла черга оновлювати фронти. З ними, з зрозумілих причин, виникли основні складності. По-перше, з-за довгого старту нового додатка. Незрозуміло, що такого IIS робить, але підняття всіх збірок в пам'ять, кешування, оновлення метабази і т. п. з'їдає пристойну кількість секунд. По-друге, через http-запити від користувачів, працюючому додатку. Ми все ще не хочемо їх обривати, повертати заглушку, помилку або таймаут. Всі поточні запити повинні бути оброблені, так як і всі нові.

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

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

Всі фронти і працюють сервіси отримують від Деплоя сигнал про початку перемикання релізів, що призводить до помітних метаморфоз у  роботі. З моменту отримання сигналу всередині коду програми встановлюється той самий «блок». Всі нові http-запити на фронтах встають на паузу, чекаючи його зняття. «Блок» забороняє додавання нових записів в базу даних, щоб забезпечити свободу для фінальної міграції. Якщо поточний запит, який потрапив у додаток до встановлення «блоку», намагається здійснити запис, то з найдальших глибин інфраструктурного коду вилітає виняток, виконання запиту на фронті повторюється, і він впирається в   «блок», як нові.

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

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

Заклинання #3
Крок з зняттям «блоку» для запитів вважається фінальним кроком розгортання. Світ змінився. Працює новий код, і повернення до минулого неможливий. Будь-який крок до цього можна без наслідків відкотити. При виникненні будь-якій надзвичайній ситуації до моменту перемикання фронтів Деплой відкочує кроки в зворотному порядку, від до поточного першому, повертаючи всю систему в працездатний вигляд. Вимикаються нові сервіси, включаються старі, запускаються зупинені роботи і тощо
Новий додаток так само проксирует запити на допоміжнеРобота Деплоя поки не закінчена. Жити з двома додатками і проксированием не дуже-то зручно. Деплой перемикає дефолтний додаток в IIS на папку з новим додатком   ту саму, якою запущено «допоміжне». Цей процес знову займає у IIS час, зазвичай який обчислюється секундами. Все це час запити надходять в старе додаток і проксируются на «допоміжне». Нове «робоче» додаток тим часом стартує, і, як зазвичай після старту, йому треба дати час на «прогрів». Тому вступники http-запити новий додаток не обробляє, а на час прогріву також проксирует на «допоміжне».

Заклинання #4
У якийсь момент на одному хості в одному IIS працюють одночасно три додатки Ельби. Старе, яке встигло прийняти вхідний запит до перемикання IIS і проксирует його на «допоміжне» нове. Третє, новий, тільки що запущений після перемикання Стара версія зупинена. Працює нова.повністю ідентично другого «допоміжним». Третє проксирует запити другого на час свого прогріву. Після остаточного «прогріву» додаток припиняє проксіювання і починає обробляти запити самостійно. Інші програми відмирають, коли потік запитів до вичерпується ним. У врешті залишається тільки одне.
 останніх кроках Деплою залишилося зупинити все ще працює половину реплік старих сервісів, запустити замість них нові, включити в планування нових роботів, дочекатися прогріву нових фронтів і написати в балці про успіх релізу. Deploy done!


Епілог
У цієї статті описані основні ідеї і досить специфічні прийоми, які дозволили Ельбі за нетривалий час запровадити практику швидкого невпинного оновлення.
Залишилося за кадром, як ми мігруючи дані в монжа і эластике, забезпечуємо правильний відкат записів, синхронізуємо горезвісний «блок», боремося з IIS, робимо UI Деплоя вирішуємо безліч інших дрібних технічних проблем. Якщо ви зацікавитесь подробицями, ми з задоволенням відповімо в коментарях.

Зрідка Ельба оновлюється під «заглушкою», але це зазвичай пов'язано з переїздом заліза, апгрейдом ОС, інфраструктурних сервісів і, вже майже ніколи, релізами нової функціональності.
У результаті розробки нового Деплоя ми отримали практично те, чого бажали,   невпинне розгортання нового релізу, повністю прозоре для користувачів. Клієнт може зайти на сторінку в старому додатку, оновити її і опинитися в новому. Весь процес розгортання займає менше 10 хвилин, а максимальний час затримки з відповіддю на запит не більше 3-4 секунд. При цьому, весь код Деплоя   наш. Ми продовжуємо його допрацьовувати і поліпшувати, впроваджувати нові фічі і розвивати його функціональність.

Кінець
Джерело: Хабрахабр

0 коментарів

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