Помилка наших JAR-кодів, чому ми припинили створення JAR-файлів із жиром

Бекенд-сервіси HubSpot майже всі написані на Java. Ми маємо понад 1000 мікропослуг, які постійно будуються та розгортаються. Коли настає час розгортання та запуску одного з наших програм Java, його залежності повинні бути присутніми на шляху до класу, щоб він працював. Раніше ми вирішували це за допомогою плагіна maven-shadow-для створення товстого JAR. Це об'єднує програму та всі її залежності та об'єднує їх в один масивний JAR. Цей JAR є незмінним і не має зовнішніх залежностей, що полегшує його розгортання та запуск. Протягом багатьох років ми упаковували всі наші програми Java, і це працювало досить добре, але мало деякі серйозні недоліки.

jar-кодів

Перше питання, яке ми вразили, полягає в тому, що JAR не призначені для агрегування таким чином. У декількох файлах JAR можуть бути файли з однаковим шляхом, і за замовчуванням плагін відтінків включає перший файл у жирному файлі JAR, а решту відкидає. Це спричинило деякі справді неприємні помилки, поки ми не зрозуміли, що відбувається (наприклад, Джерсі використовує файли META-INF/служб для автоматичного виявлення провайдерів, і це спричиняло нереєстрацію деяких постачальників). На щастя, плагін shadow підтримує трансформатори ресурсів, що дозволяють визначити стратегію злиття, коли він зустрічає дублікати файлів, тому ми змогли обійти цю проблему. Однак це все одно додаткова "помилка", якої повинні пам’ятати всі наші розробники.

Інша, велика проблема, з якою ми зіткнулися, полягає в тому, що цей процес є повільним та неефективним. На прикладі одного з наших додатків він містить 70 файлів класу на загальну суму 210 КБ, упакованих як JAR. Але після запуску плагіна тіней для зв’язку його залежностей ми отримуємо жирний JAR, який містить 101 481 файл і важить 158 МБ. Об’єднання 100 000 крихітних файлів в один архів відбувається повільно. Завантаження цього JAR на S3 в кінці збірки відбувається повільно. Завантаження цього JAR під час розгортання відбувається повільно (і може наситити мережеві карти на наших серверах додатків, якщо у нас багато одночасних розгортань).

За умови, що постійно виконують зобов’язання понад 100 інженерів, ми зазвичай робимо 1000–2000 побудов на день. З кожною з цих збірок завантажували жирний JAR, ми генерували 50-100 ГБ артефактів збірки на день . І найболючіша частина - це те, наскільки дублюється кожен з цих артефактів. Наші програми мають багато перекриттів з точки зору сторонніх бібліотек, наприклад, усі вони використовують Guice, Jackson, Guava, Logback тощо. Уявіть, скільки копій цих бібліотек ми маємо в S3!