Худий на жир, тонкий, порожнистий та убер

Ось майже все, що ви хотіли б знати про ваші улюблені методи упаковки для Java - тонкі JAR, жирні/uber JAR, тонкі JARS і порожні JAR.

Приєднуйтесь до спільноти DZone та отримуйте досвід повного членства.

Нещодавно я бавився з різними техніками упаковки мікросервісів Java та запуску на OpenShift з використанням різних середовищ виконання та фреймворків, щоб проілюструвати їхні відмінності (WildFly Swarm проти WildFly, Spring Boot проти світу тощо). Приблизно в той самий час, коли я це робив, запалився внутрішній потік списку електронних адрес, обговорюючи деякі відмінності та використовуючи такі терміни, як Uber JAR, Тонкі ВІЙНИ, Худі ВІЙНИ та деякі інші. Деякі люди підкреслювали плюси і мінуси кожного, особливо переваги тонкого підходу WAR у поєднанні з шарами зображень докера.

І я подумав собі: чи це не те, що вже всі роблять? Чи справді розробникам доводиться думати про це? Але перед тим, як вникнути в це, я хочу визначити різні терміни, які я чув, і, принаймні, зрозуміти це у власній голові.

Кваліфікатори (у порядку збільшення логічного розміру):

  • Худий - Містить ТІЛЬКИ біти, які ви буквально вводите у свій редактор коду, і НІЩО ще.
  • Тонкий - Містить усі вищезазначені ПЛЮС прямі залежності програми від вашого додатка (драйвери db, бібліотеки службових програм тощо).
  • Порожнистий - Зворотній тонкий - Містить лише біти, необхідні для запуску вашого додатка, але НЕ містить самого додатка. В основному заздалегідь упакований «сервер додатків», на якому ви можете пізніше розгорнути свою програму, у тому ж стилі, що і традиційні сервери програм Java EE, але з важливими відмінностями ми перейдемо пізніше.
  • Жир/Uber - Містить біт, який ви буквально пишете собі ПЛЮС, прямі залежності вашого додатка ПЛЮС, біти, необхідні для запуску вашого додатка «самостійно».

тонкій

Тепер давайте визначимо, як кваліфікатори відображаються у світі програм Java та типів пакетів (JAR, WAR тощо).

Жир/Uber JAR

Maven і, зокрема, Spring Boot популяризували цей добре відомий підхід до упаковки, який включає все необхідне для запуску всієї програми в стандартному середовищі Java Runtime (тобто, щоб ви могли запускати програму за допомогою java -jar myapp.jar). Кількість додаткових матеріалів під час виконання, включених до Uberjar (та їх розмір файлу), залежить від фреймворку та функцій виконання, які використовує ваш додаток.

Тонка ВІЙНА

Якщо ви розробник Java EE, швидше за все, ви вже робите це. Це те, що ви робите більше десяти років, тож вітаємо, ви все ще круті! Тонкий WAR - це веб-програма Java EE, яка містить лише веб-вміст та бізнес-логіку, яку ви написали, разом із незалежними залежностями. Він не містить нічого, що забезпечується часом виконання Java EE, отже, він "тонкий", але не може працювати "самостійно" - його потрібно розгорнути на сервері додатків Java EE або контейнері сервлетів, що містить "останню милю" бітів запустити програму на JVM.

Тонкий JAR

Те саме, що і Тонка ВІЙНА, за винятком використання формату упаковки JAR. Як правило, це використовується спеціалізованими архітектурами додатків/плагінів, які використовують формат упаковки JAR для спеціально створених плагінів чи артефактів середовища виконання. Наприклад, формат .kjar із Drools.

Худа ВІЙНА

Хоча менш відомий, ніж його побратими, худий WAR тонший, ніж Thin WAR, оскільки він не включає жодної сторонньої бібліотеки, від якої залежить додаток. Він містить ТІЛЬКИ (байтовий) код, який ви як розробник буквально вводите у своєму редакторі. Це має великий сенс у докерному світі багатошарових зображень контейнерів, де розмір шару важливий для розумності DevOps, і Адам Бієн провів чудову роботу, продемонструвавши та пояснивши це. Про це далі.

Худий JAR

Те саме, що і Skinny WAR, за винятком використання упаковки JAR та фреймворків, побудованих навколо неї, таких як WildFly Swarm та Spring Boot. Це також має масу сенсу для осудності CI/CD (і вашого рахунку AWS) - просто запитайте Hubspot. Тут ви берете Тонку ВІЙНУ і видаляєте всі сторонні залежності. У вас залишилася найменша атомна одиниця програми (спроба перейти на менші звучить як жахлива ідея, але з Java 9/JPMS це можливо), і її потрібно розгорнути в середовищі виконання, яке очікує цього, і має всі інші необхідні біти для запуску програми (наприклад, Hollow JAR)

Порожнистий JAR

Це середовище виконання додатків Java, яке містить “достатньо” сервера додатків для запуску програм, але не містить жодних додатків. Він може працювати самостійно, але це не так корисно, коли він працює самостійно, оскільки він не містить додатків і не робить нічого, крім самоініціалізації. Деякі проекти, такі як WildFly Swarm, дозволяють налаштувати, скільки «просто достатньо», тоді як інші (наприклад, Paraya Micro або TomEE) пропонують заздалегідь побудовані розподіли популярних комбінацій компонентів середовища виконання, таких як ті, що визначені Eclipse MicroProfile.

Інші комбінації

  • Порожня війна - теоретично ви можете упакувати якусь програму для запуску на іншому сервері додатків, а потім розгорнути програми на цьому внутрішньому рівні. Удачі вам у цьому!
  • FAT/Uber WAR - Не має сенсу в загальній ідеї про те, що Fat/Ubers можна запускати за допомогою java-jar.
  • Файли EAR - за визначенням файл EAR не може бути порожнім, жирним або худим, тому все, що ви можете створити, - це Тонке EAR (що воно вже є, за визначенням). Рухайтесь далі, тут нічого не можна побачити, за винятком того, що файли EAR можуть бути транспортним засобом, який несе залежності для худих ВІЙ в межах EAR.

Чому турбувати?

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

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

Чудово. Просто підкажіть, який із них використовувати!

Це залежить. Про плюси/мінуси кожного обговорювали інші (тут, тут і тут). JAR-файли Fat/Uber привабливі завдяки своїй портативності, простоті виконання в середовищі IDE та характеристиці JRE, яка вам потрібна. Але чим більше ви зможете розділити шари (на худі/тонкі), тим більше ви заощадите на мережі/диску/процесорі далі. Також є додаткова перевага можливості незалежного виправлення всіх шарів, наприклад, передплати та швидкого розповсюдження виправлень про вразливі місця безпеки серед усіх ваших запущених програм). Отже, вам доведеться вирішити серед компромісів.

Приклад: Рой диких мух

WildFly Swarm - це механізм для упаковки Java-програм, які містять “достатньо” функціональних можливостей для запуску програми. У ньому є абстракція, яка називається дріб, кожна з яких втілює певну функціональність, необхідну додаткам. Ви можете вибрати, які дроби вам потрібні, та упакувати лише ті дроби разом із вашим додатком, щоб створити мінімізоване та спеціалізоване зображення, яке можна запускати для вашого додатка.

WildFly Swarm має можливість створювати багато з вищезазначених типів пакетних програм. Давайте подивимося, що він може зробити, і отриманий (і) розмір (и) різних варіантів упаковки, і як це застосовується у світі багатошарових зображень контейнерів Linux. Ми почнемо з JAR Fat/Uber і будемо рухатися вниз. Візьміть код і виконайте наступні дії:

JAR для жиру/Uber

Зразок програми - це проста кінцева точка JAX-RS, яка повертає повідомлення. Він має одну пряму залежність від Joda Time, яку ми використаємо пізніше. На даний момент давайте створимо FAT JAR (це режим за замовчуванням WildFly Swarm), використовуючи код у папці fat-thin /:

Ви можете перевірити це за допомогою java -jar target/weight-1.0-swarm.jar, а потім згорнути http: // localhost: 8080/api/hello в окремому вікні терміналу.

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

Тонкі ВІЙНИ

Як частина вищезазначеної збірки Fat JAR, WildFly Swarm також створив Тонку ВІЙНУ, тому не потрібно переробляти. Погляньте на Тонку ВІЙНУ:

Зараз ми кудись дійшли. Цю 512K Тонку ВІЙНУ можна розгорнути на будь-якому сервері додатків (наприклад, самому WildFly). Отже, якщо ви вкладете набагато менший файл у верхні шари докера, поки ваш рідко змінений сервер додатків живе в нижньому шарі (як Адам Бієн демонструє кілька разів), ви заощадите досить багато часу та енергії під час кількох збірок. Давайте продовжувати.

Худі ВІЙНИ

Можливо, ви помітили в демонстраційному додатку, що це надзвичайно просто - лише кілька рядків коду. То чому для його утримання потрібно 512 тис. Більшість із 512M у Тонкій ВІЙНІ зайнято нашими прямими залежностями - у цьому випадку бібліотекою Joda Time:

Якщо ми продовжимо додавати прямі залежності (наприклад, драйвери баз даних та інші речі, які знадобляться практично кожному виробничому додатку), наша Тонка ВІЙНА з часом також буде збільшуватися і збільшуватися. Хоча 512 тис. Непогано, ми можемо зробити набагато краще.

Худа ВІЙНА: Видалення прямих залежностей

За допомогою Maven ви можете видалити пряму залежність із отриманої Тонкої ВІЙНИ, оголосивши, що вона повинна бути надана, що означає, що час виконання (в даному випадку WildFly) повинен забезпечувати цю залежність. Через природу серверів додатків та модульного завантажувача класів WildFly, щоб WildFly забезпечував цю залежність, коли ваша програма розгортається до неї, вам потрібно буде створити власне визначення модуля JBoss у вашій конфігурації Wildfly та оголосити залежність від цього модуля у вашому додатку.

WildFly Swarm забезпечує кращий спосіб, коли не потрібно взагалі торкатися бітів сервера додатків. Ми можемо створити власний модуль під назвою дріб. Фракції - це першокласні громадяни WildFly Swarm, і вона має особливу логіку, яка пов’язує код усередині фракцій з кодом програми під час виконання. Роблячи це, наш додаток справді не має залежностей і стає Худою ВІЙНОЮ.

Я створив фракцію для розміщення бібліотеки Joda Time у joda-fraction/folder у джерелі прикладу програми. Давайте побудуємо його та скопіюємо до нашого репозиторію Maven для подальшого посилання:

Тепер, коли фракція побудована, відновіть худу версію програми (у худі/папці):

Зараз ми кудись дійшли! Наша Худа ВІЙНА 2243 байти. Це настільки мало, наскільки воно стає, оскільки буквально містить лише наш код:

Однак він повністю непридатний для використання. Для цього потрібен не тільки сервер додатків з підтримкою JAX-RS, але і сервер, який може забезпечити нашу пряму залежність від Joda Time. WildFly Swarm надає ще одну можливість для створення такого середовища виконання сервера, яке міститиме достатньо достатньо сервера додатків ПЛЮС, нашу недавно відокремлену залежність Joda Time. Це називається Hollow JAR.

Порожнисті JAR

Щоб створити порожнистий JAR, придатний для запуску нашої зразкової програми, ми можемо використовувати властивість WildFly Swarm, щоб доручити плагіну Maven побудувати його:

Є порожній сервер вагою в 44 мільйони, а наша тонка ВІЙНА - 2243 байти (утиліта Linux du повідомляє дисковий простір, виділений в одиницях розміру блоку файлової системи, який у моїй системі становить 4 КБ, але будьте впевнені, що худа ВІЙНА справді становить 2243 байти при передачі через мережу буде надіслано лише 2243 байти).

Тепер ви можете набити порожнистий JAR у шар контейнера Linux, а потім набити худий WAR зверху. Коли ви відновлюєте свій проект за допомогою нового коду, припускаючи, що ви не додаєте більше залежностей на сервер додатків, буде відновлена ​​лише ваша худенька ВІЙНА, що заощадить час, дисковий простір, дерева та ваш розум під час тих 2 мільярдів перебудов контейнерів, які ви виконуєте кожен тиждень.

Щоб запустити ваш худий додаток і переконатися, що він все ще працює разом із порожнім сервером, який ви щойно створили:

І в іншому терміналі:

Як щодо Spring Boot?

За замовчуванням Spring Boot за замовчуванням також створює жирову банку, тому давайте розглянемо приклад програми Boot:

Набагато краще, ніж WildFly Swarm в 45M. Але куди ми звідси підемо? Це ще 14 мільйонів для програми привіт світу.

Хоча можна відокремити код програми від коду Spring і створити ефект, подібний до порожнистого дуету JAR/худий WAR WildFly Swarm, він вимагає, щоб ви порушили Четверту стіну та знали про внутрішні елементи Spring Boot Uberjar і писали сценарій на отриману банку FAT, щоб розділити її вміст уздовж межі програми, визначеної Boot. Результат - дуже тісно пов’язані та не переносні програми та сервери додатків, практично без надії на оновлення та без можливості розгортати на ньому що-небудь, крім програми, з якої вона виникла. Бігові порожнисті JAR не вважаються першокласним громадянином у весняному світі.

Резюме

Ми скоротили наш додаток від 45M → 512K → 2243 байт за допомогою WildFly Swarm. За допомогою цього підходу ми можемо відокремити наш додаток від його залежностей виконання та розмістити їх в окремих шарах зображень контейнерів Linux. Це зробить ваші конвеєри CI/CD швидкими, але також пришвидшить розробників при редагуванні/побудові/тестуванні та забезпечить впевненість у тому, що ви тестуєте з тими самими бітами, які потраплять у виробництво. Безпрограшний виграш у моїй книзі.

Опубліковано в DZone з дозволу Джеймса Фолкнера, DZone MVB. Дивіться оригінальну статтю тут.

Думки авторів DZone є їхніми власними.