Мова Go, микросервисы і DevOps – хороша компанія?

Привіт, Хабр!

Нагадуємо, що всі охочі можуть придбати відмінну книгу Сема Ньюмена "Створення микросервисов". Оскільки наші очікування ця тема більш ніж виправдала, ми продовжуємо шукати пов'язану з нею літературу і не так давно звернули увагу на книгу про програмуванні микросервисов мовою Go



Цікаву статтю з обґрунтуванням цього підходу ми знайшли в блозі Agile Maverick, та її переклад розміщуємо під катом.

Приємного читання!



Зараз всі говорять про микросервисах і DevOps. Поставте ці слівця собі в профіль – і вас відразу почнуть осаджувати рекрутери. Я побував у Мюнхені на кількох цікавих митапах за микросервисам, і мене найбільш здивувало, що ця тема користується найбільшим інтересом у спільнотах Java і Scala. Здивувало тому, що Java і Scala – дуже насичені мови, в яких є з чого вибирати.

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

Я розумію микросервисную архітектуру в більш цілісному ключі. Я б сказав, що і вся екосистема повинна бути легше і компактніше. Реалізація – лише одна сторона медалі. Інша сторона – це час виконання та супутні фреймворки. Тут ми підходимо до теми DevOps – філософії, яка прагне пов'язати один з одним ці дві сторони.

Віртуальна машина Java оптимізована для роботи з довготривалими програмами, в ній діє одна з найбільш вивірених і вигадливих систем збирання сміття. Використовується в бойових умовах вже більше 10 років. Тим не менш, коли мені доводиться бачити сучасні высокодоступные архітектури – відразу напрошується питання: а чи потрібні довготривалі програми для реалізації абсолютної більшості існуючих сервісів?

Наведу приклад. Я брав участь у розробці програми для кодування відео, і це додаток як на зло повинно було працювати цілодобово з мінімальними затримками. Ми думали, зупинитися на стабільному мовою програмування начебто Java або написати на додаток Go, де використовувалися б наявні бібліотеки C для кодування і декодування, однак такий проект міг обернутися витоками в пам'яті. Нарешті, ми вирішили розділити програму на різні процеси; статичний бекенд майже не змінився, оскільки передавав інформацію практично не змінилося протоколу, а ще у нас була функціонально багата клієнтська частина, де існував ризик витоків. Обидві частини використовували поділювану пам'ять. Виявилося, що варіант хороший. Оскільки Go стартує швидко, ми перезапускали клієнтську частину раз на десять секунд. Виявилося, що проблема – не в витоках пам'яті, а в оперативних оновлення.

За багато років в Java склалося багато нетривіальних рішень – наприклад, фреймворк log4j для логування. На прикладі контейнерних рішень начебто OpenShift можна переконатися, що тепер знову прийнято працювати з stdout і stderr. Немає необхідності впроваджувати комплексні рішення для логування на рівні мови. Цей приклад дозволяє судити, як DevOps і нові середовища часу виконання змінюють правила гри.

Типовий docker-образ на Go docker має розмір близько 15 MB; порівняйте його з образом для JVM на Java, розмір якого — близько 300 MB. Різниця 1 до 10. Java JVM оптимізована під економна витрата пам'яті, але все одно вимагає приблизно в 10 разів більше пам'яті, ніж Go.

В Go не так багато успадкованих фреймворків, тому і залежностей зазвичай мало, а код залежностей входить до складу бінарного файлу. Тому відпадає необхідність в таких складних інструментах як Maven. У контейнерній середовищі реліз нового способу необхідний всякий раз, коли змінюється одна з залежностей в ланцюжку. А значить, на Java Java ми повинні оновлювати такі контейнери досить часто. Гірше того, залежно зазвичай заховані десь глибоко.

Java і Scala – це мови для об'єктно-орієнтованого програмування. Але при роботі в порівняно простих предметних областях такі рішення здаються мені досить витратними. «Гнучкий» аспект філософії Go дозволяє організувати розробку не тільки не гірше, але набагато зрозуміліше.

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

У 1990-ті був справжній бум серверів додатків Java – вважалося, що вони забезпечать незалежність розробки від операційної системи і апаратного забезпечення. Читаючи специфікацію JEE, ми також розраховували на простоту віддалених взаємодій компонент-орієнтовану розробку. Коли я бачу контейнер docker, на якому працюють Java-додатки, завжди згадую про нової версії EJB. В принципі, стек Java не спростився, але тепер він упакований в контейнер. Така упаковка даром не дається, оскільки додається ще один рівень складності; ви з ним зустрінетеся, як тільки спробуєте налагодити мережу такого docker-контейнера.

Go docker – варіант для масштабування сервісів, але складну середовище часу виконання він не рятує. Якщо у вас всього один простий сервіс, прості двійкові файли Go можна виконувати прямо на хості. Якщо ж мова йде про більш складному додатку, то сервіси можна покласти, наприклад, в контейнер і запускати їх в PaaS-середовищі начебто OpenShift. Щоб протестувати сервіс на ноутбуці розробника, контейнер не потрібен, всіляка пов'язана з ним магія – теж.

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

Go, де варіантів не так багато, допомагає швидше освоїтися з рішенням тим розробникам, які самі його не писали. Не потрібно заглиблюватися в філософію розробки. Зрозуміло, завжди можна реалізовувати сервіси і в більш простому стилі на більш насичених мовами, наприклад, Java або Scala, але в даному випадку потрібно навчитися самообмеження, обговорювати всі деталі з командою – відповідно, микросервисная архітектура обростає величезною документацією.

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

Думаю, просто ніхто не любить різких змін. Ми спробували змінити лише один вимір у багатовимірному світі програмування. Це вимір – розмір сервісу. З мого досвіду, змінити одне вимірювання ще недостатньо, щоб пішла еволюція. Оскільки всі вимірювання взаємопов'язані, вони впливають один на одного. Вирішивши спростити додаток, переробивши його у вигляді микросервисов, ми повинні також спростити і виконуючу середу, і мова програмування, з яким працюємо. Інакше отримаємо лише новий головний біль – наприклад, доведеться керувати відразу безліччю JVM, які займають купу місця в пам'яті і запускаються досить повільно. Або отримаємо безліч дрібних об'єктно-орієнтованих рішень, які будуть розподіленими, а значить – більш складними. Нарешті, ми просто заплутаємося з безліччю сервісів, що утворюють величезне дерево залежностей.

По-моєму, не змінюючи всіх вимірювань відразу, ми немов пересідаємо з коня на машину, але беремо з собою сідло і шпори.

Давайте не просто писати микросервисы, але і адаптувати під них всю архітектуру. Go відмінно для цього підходить. Якщо предметна область сервісу розшириться, ви завжди зможете додатково скористатися Java або Scala.

Джерело: Хабрахабр

0 коментарів

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