Как стать автором
Обновить

«В идеале мы хотели бы вообще заменить Spring на Micronaut» — интервью с Грэмом Роше о перспективах развития Micronaut

Время на прочтение20 мин
Количество просмотров14K
Всего голосов 28: ↑27 и ↓1+26
Комментарии25

Комментарии 25

Спасибо за пост, Олег, это чрезвычайно интересная тема! А нельзя ли послушать запись интервью в оригинале? Было бы круто, чтоб не тратить драгоценное время на чтение. Текст довольно большой. Ну если нет, тогда придётся всё-таки читать.

Придется читать, сорри.

У Micronaut — устаревший подход. Кодо и классогенерация были популярны 10 лет назад.
Сейчас же большинство современных Java фреймворков генерируют код в рунтайме. Это и удобнее и больше простора для оптимизации.

Ага, а ещё замечательно увеличивается время старта сервера. И мешает делать AOT-компиляцию.

НЛО прилетело и опубликовало эту надпись здесь
Команды сейчас деплоят чаще, чем сервера падают. А с автоскейлингом в облаке скорость поднятия сервисов становится ещё важнее.
Я с трудом понимаю, как можно что-либо куда-то задеплоить, пусть даже на дев, не проверив 100 раз локально.
И почему лишняя секунда старта так важна — не совсем понятно.
Допустим разработчик, закрывает таску и деплоит на дев в конце рабочего дня. И что эта секунда даёт?
Представьте, что вам не хватает производительности и ваши сервисы трещат по швам в black friday, тут вам нужно переживать за скорость запуска новых инстансов сервиса. Если вы не видите зачем это всё, то у вас просто нет таких задач.
Если вам реально нужен real-time, то я сомневаюсь, что Java будет оптимальным выбором. Вы скорее всего выберете ОС реального времени такую как QNX, структуры данных с гарантированным временем доступа и язык без сборщика мусора. Но вообще мне кажется ваш пример сильно высосан из пальца.

Кроме того, если следовать вашей парадигме, то вам нужно ещё выкинуть Hibernate, аспекты и некоторые другие фреймворки.
Вот уж воистину преждевременная оптимизация — корень всех зол.

Риалтайм и скорость стартапа в случае катастрофы или масштабирования — это разные штуки. Скорость стартапа важна, когда гипервизор вашего облака например, ставит на паузу приложение на одном хосте и переподнимает на другом из снимка бизнес-состояния. Или если приложение упало, и гипервизор поднимает его с сейфпоинта. Или тем паче, если никаких сейфпоинтов нет, и все переподнимается с нуля.


Разница во времени там не в секунде. Spring Boot грузится пару секунд только если вы не включили ничего, требующего его обычных "умных" механик. Подключаете Spring Security — и вся скорость запуска сразу проседает, наворачиваете работу с БД, кастомный AOP — и всё, скорость запуска в полной жопе. Где. собственно, и должна быть — Spring это не про скорость запуска.

Вы хотите сказать, что включение Spring Security, поднятие соединений с БД и кастомный AOP на других фреймворках по волшебству происходит быстрее?

И сколько секунд вам надо на запуск?
Если вам не надо «умные» механики, то не включайте их. Зачем из-за это переходить на фреймворк заведомо ущербнее — непонятно.

Мне кажется вы ищете проблем не там где они есть. Если ваше приложение постоянно падает, вы не можете запустить несколько копий параллельно и ваше приложение страдает от производительности то это явно не спринг в этом виноват.
И сколько секунд вам надо на запуск?

Чем меньше — тем лучше. Желательно ноль =)


Вы хотите сказать, что включение Spring Security, поднятие соединений с БД и кастомный AOP на других фреймворках по волшебству происходит быстрее?

Нет, оно не происходит быстрее. Оно просто не происходит. Ты отказываешься от Spring Security, удобных универсальных рефлективных коннекторов до баз данных, и начинаешь мучиться и пердолиться до тех пор, пока не получится что-то приличное, что влезает в целевые SLA


Например, в какой-то момент придется отказаться от обычной джавы и перейти на GraalVM. А может быть, придется отказаться от джавы вообще и перейти на C++, Golang и Node.js.


Например, можно написать на Java приложение в том же стиле, что на Ноде — у него есть основной fast event loop который стартует мгновенно, а всё остальное запускается в чисто асинхронном стиле. Тормоза будут происходить не на этапе старта, а на этапе выполнения каждого из запросов, особенно до прогрева локальных (по отношению к типу запроса) кэшей. Но при этом старт ивент лупа — это миллисекунды.


AOT мире своя система ценностей — "всё что можно вычить на этапе компиляции — должно быть вычислено на этапе компиляции". В C++ даже специальную фичу добавили — constexpr, завидуйте, кусайте локти джависты. Вон Micronaut Data может предвычислять какие-то SQL запросы, конечно. Благодаря этому, скорость выполнения таких действий в рантайме — тот самый ноль.


Другое дело, что на Spring Boot так не пишут. У Spring Boot есть вполне определенная система верований и ценностей. Есть понимание, что принято делать и как принято делать.


Если ваше приложение постоянно падает, вы не можете запустить несколько копий параллельно

Боюсь, мы тут говорим о совершенно разных вещах, отсюда такой рассинхрон. Я говорю о современных способах развертывания — это публичные и гибиридные облака, или приватные облака "как у Google", когда у тебя по полной используются технологии контейнеризации, включая кубернетисы, клауд-функции, и всё такое прочее. Не обязательно "тратить деньги на Амазон" (скорее экономить, но это другой разговор) — можно и у себя в гараже собрать точно такую же систему, опенстеки с кубернетисами в зубы и погали.


Если же речь идёт о том, чтобы поднять на Хецнере один-единственный сервак о сорока четырех ядрах и десяти терабайтах оперативки, и потом вдолбенить в него всю инфраструктуру компании, надеясь что сервак случайно не сотрут хостеры (как когда-то делали наши деды) — тут совершенно другой набор трейдоффов.

Мы ещё про джаву говорим? Я уже писал выше: если вам нужны милисекунды и вы автоматизируете системы управления ядерным рекатором, то используйте QNX, C и пр. Зачем вы пытаетесь натянуть сову на глобус?

Как вы выражаетесь «современных» способов развёртывания — миллион и одна штука. Если у вас нет дублирования, то ни один из них вам не поможет.

Вы, надеюсь, в курсе, что в кубернетисе можно поднять несколько инстансов из одного образа? И в Амазоне тоже.

Нужны не просто миллисекунды, а именно миллисекунды на запуск. Если что-то упало, было перемещено, временно поставлено на паузу, отправлено на реконфигурацию и так далее — когда настанет его час, оно должно взлететь и вернуться в строй моментально, как чертик из табакерки. Особенно это актуально для cloud functions, которые только то и делают что перезапускаются.


Это вопрос совершенно ортогональный риалтаймовости после выхода на рабочую нагрузку. Например, в условной черной пятнице у вас могут начать виснуть и перезапускаться приложения — и важно, чтобы они вернулись назад как можно скорее. Но при этом сами эти приложения не только не обязаны быть риалтаймовыми (в смысле QNX), а им это даже вредно. Им по профилю нагрузки положены ни разу не риалтаймовые корутины. Включая джавовый Project Loom, а задолго до него был и вполне себе использовался Quasar. Нужно, чтобы вначале напринимать десятки тысячи соединений от клиентов и не упасть, уйти в спячку на долгоиграющих запросах вроде базы данных и файловой системы, и потом уже когда получится — проснуться и вернуть результат.


Мы ещё про джаву говорим?

Конечно про джаву. Например, есть чудесный фреймворк Vert.x с ивент-лупами, построенный с использованием не менее чудесного Netty — оба event-driven и non-blocking.


Его даже можно собрать с помощью GraalVM, и запустить в Docker, так что имидж в памяти займет 5 мегабайт, на диске — 40, и всё это с условно-мгновенной скоростью запуска.


В него можно даже встроить Micronaut DI, потому что жить без DI очень неприятно.


Видите, это платформа с совершенно другим набором трейдоффов и практик, чем у Spring Boot. Еще более другие, чем у Micronaut.

У вас очень странные практики.
Это определённо ненормально лезть на прод посреди рабочего дня, чтобы чего-то там переконфигурить вручную без тестирования и быстро перезапуститить пока никто не заметит.

Нормальная практика — это когда мы деплоим новую версию приложения (например в куберентис), настраиваем, тестируем, а затем постепенно переводим трафик со старой версии на новую.
Если же у нас стартует нагрузка ты мы увеличиваем число инстанцев заранее.

Если же у меня вдруг начинает виснуть приложение, то мне надо отключить его от лоад балансера, сделать все дампы, собрать логи и пофиксить ошибку, чтобы такого больше не повторялось. А не в панике перезапускать, считая секунды

Перезапускаешь и переконфигурируешь не ты-как-человек, а гипервизор, каким бы он ни был. Условно говоря, в кубере можно сказать restartPolicy: "OnFailure", maxRetries: "100500" и наслаждаться результатом.


Приложение обычно нельзя отключить, даже если оно падает или виснет. Потому что им пользуются люди, и они не оценят. Скажем так, приложение всегда при каких-то условиях падает и виснет, не бывает идеальных приложений, это не повод чтобы отключить всё от балансировщика, разрегистрироваться в интернете и убить себя об стену :)

Люди пользуются не напрямую, а через load балансер.
В кубере можно указать что угодно, но пользователь этого всё равно не заметит, когда есть дублирование. О чём вообще речь??
У вас нет дублирования? Так и скажите: мы не проходили теорию надёжности в университете и про дублирование не слышали.

И в случае failure надо собирать дампы и логи, анализировать и выпускать фиксы, а не заниматься бездумным перезапуском и прочей ерундой. Чтобы собрать memory дамп, к примеру, требуется намного больше чем 10 секунд, я вас уверяю.

Идеальных приложений не бывает, но нормальное приложение падает не чаще чем раз в год (условно), а не всегда. И в этом случае лишняя секунда даунтайма ничего не решает.
Я уж молчу, что при этом рвутся сессии, сбрасываются кэши и случается куча других неприятностей помимо даунтайма.
Грамотно написанное спринговое приложение с embeded сервером стартует за пару секунд. А вот насколько увеличивается время компиляции при Micronaut кодогенерации — это отдельный вопрос.
НЛО прилетело и опубликовало эту надпись здесь

Если не относиться к фреймворкам исключительно как объектам моды (почему бы тогда не заняться коллекционированием шляп?), то подход может быть "подходящий" и "неподходящий" ;)


Есть же не только дихотомия на AOT vs JIT. Например, медленно компилирующее в AOT приложение — так же неудобно разрабатывать, как и жирную муть на Spring Boot которая стартует по минуте. Тебе как разработчику какая разница где ждать — один фиг ждать придется. Надо сюда ещё добавить как минимум ось про скорость фидбека, и еще одну ось про микросервисы против жирносервисов, и еще, и еще… короче, проблема куда больше

Если микросервис — действительно микро, а не монолит запиленный как микросервис, то разница между двумя "легковесами" вряд ли будет значительна.
С другой стороны заказчик на уменьшение счетов за облака обязательно скажет ееее, давай еще. Если крупный — ему экономия, а если мелкий, может вообще захочет на лямбдах AWS — и что тогда делать?
И вот, выбирая между хотелками разработчика и хотелками заказчика есть очень ненулевой шанс, что заказчик будет первичен.
Вообще, спринг (особенно бут) последних лет нередко монструозен. Это вряд ли будет продолжаться вечно. В разработке — да, удобен, но этот плюс ведь не главное, правда?

История циклична :)

Все бы ничего, но основная задача так и не решена: приложение на Micronaut все-равно стартует долго. Когда все статично слинковано, и в рантайме отсутствует всякая кодогенерация, ожидание, что все запустится очень шустро. Но вот пустые Helidon и Quarkus почему-то стартуют быстрее.

… и ЧТО замеряет — это Micronaut 2.0 M2 на пустом Rest. Берем Javalin/SparkFramework и получаем то же самое, но быстрее. А как начнем наваливать технологии, запуск опять сильно просядет.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий