Прежде всего хочется спросить, почему вы не добавили статью в хаб Java, мне кажется, она в первую очередь ценна именно для джава разработчиков.
А ещё есть вопросы по содержимому статьи. Вы описываете проблему следующим образом.
в новые сервисы транзитивно попадают зависимости, несовместимые с имеющейся версией Spring.
Я так понял, что новый подход выбран как раз для того, чтобы такого не было, но ведь модуль order-open-feign-client тянет за собой спринг точно так же, как и order-open-client. Или я что-то не так понимаю?
Я пару раз прочитал статью и у меня создалось впечатление, что транзитивные зависимости создавали вам проблемы потому что сервисам, использующим ваш клиент, нужно было обновлять версии спринга синхронно с order-api. А перевести сервис на новую версию Спринга это может быть небыстро.
И тогда вы решили, что поддерживать две версии клиента будет дешевле, чем в авральном порядке переводить сервис на новый Спринг. Я правильно понял? Или всё-таки новые версии клиентов каким-то образом и правда не тащат за собой транзитивные зависимости?
Мне кажется из всех этих мотивов только у первого есть реальное обоснование зачем это нужно
А как же Collapse OS? Операционная система, специально сделанная, чтобы её можно было с минимальными усилиями самостоятельно запустить с любой периферией. И наверное даже портировать на любой процессор.
Но мы пытаемся сделать процесс разработки удобным и безопасным не только в контексте выкатки на прод, но и для разработчиков, верно?
Да, действительно. Поэтому накат миграций через liquibase при старте приложения на проде будет выключен средствами конфигурации. А в конфигурации для локального окружения разработчика он будет включен. И будет всё очень удобно.
На практике, конечно, когда у нас есть большая многокомпонентная высоконагруженная система, то скорее всего разработчики не будут разворачивать её локально, а будут запускать локально какой-то компонент и подключать его к удалённой среде. И тут автоматический прогон ликви скриптов конечно скорее вреден. В таком воркфлоу автоматом скрипты прогоняются только для того, чтобы создать стуруктуру БД под юнит тесты ))
Каким образом flywaydb, при запуске в виде <run-db-migrations> && <launch-the-app> в случае сбоя миграции на первом инстансе остановит дальнейшую раскатку приложения, которая выполняется одновременно и параллельно на нескольких инстансах?
Ну вы же сами написали, что не надо так делать )). Что надо раскатывать миграции через CI.
Однако, если вам интересно обсудить именно <run-db-migrations> && <launch-the-app>, то тут всё просто. flywaydb сделает так, что одновременно будет работать только одна миграция. Когда эта миграция упадёт с ошибкой, приложение, естественно, запущено не будет.
Но, как вы справедливо отметили, миграция одновременно запускается на нескольких инстансах. На одном она работает, остальные ждут. Когда миграция на одном инстансе упадёт, то сразу заработает такая же миграция на другом инстансе, которая сразу же упадёт, потому что начнётся с того места на котором закончил предыдущий инстанс. Всё попадает, деплой завершится неудачей, можно спокойно разобраться по логам, что пошло не так.
Плюс ещё есть небольшая вероятность, что первая миграция упала по таймауту. Допустим больше пяти минут работала. Вторая миграция тогда тоже скоре всего упадёт по таймауту, но впустую потратит при этом пять минут. И так далее, по пять бесполезных минут на инстанс
Для того, чтобы так не получалось обычно поступают следующим образом. Второй инстанс он же ждёт, пока первый закончит миграцию. Максимальное время ожидания — параметр, который можно задать в настройках. Если он будет равен, допустим четырём минутам, то после пятиминуной миграции на первом инстансе, остальные инстансы даже не будут пробовать, а сразу упадут по таймауту.
P. S. Да, если вас интересует подробности того, как liquibase добивается того, чтобы больше одной миграции не работало — то ответ простой. С помощью локов в специальной таблице в БД ))
Там же не только про то, что нельзя чтобы в один момент времени работало несколько миграций.
И у вас в статье не только про это и инструменты не только такую проблему закрывают ))
Там еще и про ретрайи, поэтому меня настораживает фраза у flywaydb про "Auto-migration on startup".
Вы наверное тут имели в виду, что миграция не должна накатываться два раза по какой-нибудь роковой случайности, да? liquibase это обеспечивает, flywaydb тоже. Хотя я сам использую только liquibase.
Наверняка существуют окружения в которых это допустимо, но если у нас традиционное веб-приложение на кластере — то я бы так не рисковал.
Ваш ответ сначала привёл меня в шок, потому что как раз для традиционных веб приложений liquibase это традиционное решение ))). Но потом я посмотрел на теги и не нашёл там java. Тут то всё и встало на свои места.
liquibase это в мире java считай стандартный инструмент для миграций. Или flywaydb, они делают плюс-минус одно и то же. Их можно интегрировать в приложение или запускать как отдельную утилиту. Если в вашем мире подобных стандартных утилит нет, то рекомендую попробовать.
Правда, для запуска пока что ещё нужна java. Думаю рано или поздно это починят и сделают бинарник без дополнительных зависимостей, но пока вот так.
Добавьте ещё liquibase и flywaydb в раздел про то, что нельзя, чтобы на БД в один момент времени работало больше одной миграции. Эти инструменты как раз помогают этого достичь
Спасибо, понимаю ваш пойнт. Не уверен, правда, что это можно считать багом.
Всё зависит от контекста. Если в вашем случае в потере нового аватара нет ничего страшного, то это действительно не баг ))
Например, в моей любимой парадигме "Continuous Deployment" откаты в таком виде вообще не делаются.
На откатах проще объяснять, но вообще точно такая же проблема будет когда на среде одновременно работает два инстанса с первой и второй версией кода. Вторая версия кода обновит аватар в avatar_url, а первая версия этого обновления не увидит, потому что будет смотреть на поле avatar.
Для каких-то случаев предложенный вами подход наверняка был бы полезен и помог бы дополнительно подстраховаться от сбоев. Однако, я не уверен что его стоит применять строго всегда и везде.
Вы о дополнительном шаге? Думаете в в вашем случае он не актуален?
На втором шаге из кода приложения полностью убирается работа с полем avatar. А на первом шаге чтение происходит именно из этого поля.
Если раскатать код из второго шага и дать ему совсем немного поработать, то он запишет новые значения в avatar_url. Дальше возможно придётся делать откат.
После отката старый код будет читать значения из поля avatar. А там значение устаревшее.
Чтобы такого не могло случиться, нужно делать дополнительный шаг. Вторым шагом не прекращать работу с полем avatar, а по прежнему писать и туда и туда, но читать уже из новой колонки.
Фаза 2 у вас соотвественно превращается в Фазу 3, а Фаза 3 в Фазу 4
Я очень рад, что для вас многое здесь является очевидным, серьезно :) Для многих разработчиков это, к сожалению, не так.
Полностью поддерживаю! Я сам, знаете ли, своего рода разработчик и написал практически точно такую же статью, как ваша, только другую ))). Правда ещё не опубликовал. И мне тоже многие говорят, что ничего нового тут нет и так далее.
И, наверное, самым красноречивым доказательством того, что такие статьи очень нужны будет тот факт, что у вас в процедуре миграции баг ))). Возможно не фатальный, но самый настоящий. Получается что те люди, которым содержимое вашей статьи кажется очевидным, его не заметили. А значит такие статьи нужны!
P. S. Я не стал рассказывать в чём баг, потому что возможно вам хочется самому разобраться где он. Если вам интересно, я скажу в каком месте он спрятался. Или могу сразу рассказать что за баг, где он и к чему может привести, только напишите )))
Ха. YAML нифига не человекочитаемый, а скорее беспощадный к любому огреху.
Плюс комментарию, плюс в карму!
Сначала был XML, в котором всё было понятно и только иногда случались холивары по поводу того, что тут поставить — атрибут или вложенный тег. И было куча инструментов. И DTD и XSL, всё было отлично. Но нам казалось, что это всё слишком многословно. Так оно, конечно и было, но всё же в формате были предусмотрены даже комментарии.
Потом появился JSON. Я помню, сильно радовался. Он казался таким элегантным, таким программистским, таким понятным. И не надо было ставить закрывающие теги, всё обходилось закрывающей фигурной скобкой. Я считал, что он идеален. И только потом выяснилось, что комментарии там не предусмотрены, валидация сложная, потому что типизации считай нет и ещё были какие-то проблемы. И ссылок не было предусмотрено, объекты приходилось копировать или придумывать велосипеды. Но по крайней мере там нельзя было полностью всё сломать, поставив лишний пробел. Однако и он показался нам слишком избыточным
И вот сделали YML. Про него в предыдущем комментарии неплохо написано. Хотя кто знает, может дело в том, что с xml и json я провёл гораздо больше времени )).
Жырный жырный плюс за статью! Что интересно я сам практически написал такую же, но только про мавен. Не опубликую никак.
Вопрос один меня мучает. Про эти gpg ключи. Там же получается, что ключ никак не привязан к аккаунту на Sonatype. Важно, чтобы он просто был в открытом хранилище ключей. Вот зачем он нужен этот ключ, что там проверяется? Подлинность файлов на случай mtm атаки, так выходит? Ну так атакующий наверное может просто переподписать всё своим ключом
Да, это на редкость странное утверждение, что бакеты различаются по ёмкости. Ёмкость это показатель относящийся ко всей HashMap.
Что касается вашего вопроса, то я всегда думал, что capacity это максимальное количество элементов во всей HashMap. То есть сумма элементов во всех бакетах.
Но, согласно документации, capacity это количество бакетов ))). То есть то же самое, что number of buckets. И формула capacity = number of buckets * load factor получается неправильная, если понимать слово capacity в том смысле, в котором оно используется в документации к HashMap
И максимальное количество элементов до перехеширования меньше либо равно capacity * load factor.
А load factor это среднее количество элементов в одном бакете. Ну или процент пустых бакетов при условии, что в заполненных по одному элементу. По умолчания там, кажется 0.75, то есть в среднем в каждом бакете должно быть меньше одного элемента
Прежде всего хочется спросить, почему вы не добавили статью в хаб Java, мне кажется, она в первую очередь ценна именно для джава разработчиков.
А ещё есть вопросы по содержимому статьи. Вы описываете проблему следующим образом.
Я так понял, что новый подход выбран как раз для того, чтобы такого не было, но ведь модуль order-open-feign-client тянет за собой спринг точно так же, как и order-open-client. Или я что-то не так понимаю?
Я пару раз прочитал статью и у меня создалось впечатление, что транзитивные зависимости создавали вам проблемы потому что сервисам, использующим ваш клиент, нужно было обновлять версии спринга синхронно с order-api. А перевести сервис на новую версию Спринга это может быть небыстро.
И тогда вы решили, что поддерживать две версии клиента будет дешевле, чем в авральном порядке переводить сервис на новый Спринг. Я правильно понял? Или всё-таки новые версии клиентов каким-то образом и правда не тащат за собой транзитивные зависимости?
А как же Collapse OS? Операционная система, специально сделанная, чтобы её можно было с минимальными усилиями самостоятельно запустить с любой периферией. И наверное даже портировать на любой процессор.
Ваш новый пароль слишком похож на старый пароль. Пожалуйста, придумайте новый пароль, который имеет больше отличий от старого.
Да, действительно. Поэтому накат миграций через liquibase при старте приложения на проде будет выключен средствами конфигурации. А в конфигурации для локального окружения разработчика он будет включен. И будет всё очень удобно.
На практике, конечно, когда у нас есть большая многокомпонентная высоконагруженная система, то скорее всего разработчики не будут разворачивать её локально, а будут запускать локально какой-то компонент и подключать его к удалённой среде. И тут автоматический прогон ликви скриптов конечно скорее вреден. В таком воркфлоу автоматом скрипты прогоняются только для того, чтобы создать стуруктуру БД под юнит тесты ))
Ну вы же сами написали, что не надо так делать )). Что надо раскатывать миграции через CI.
Однако, если вам интересно обсудить именно <run-db-migrations> && <launch-the-app>, то тут всё просто. flywaydb сделает так, что одновременно будет работать только одна миграция. Когда эта миграция упадёт с ошибкой, приложение, естественно, запущено не будет.
Но, как вы справедливо отметили, миграция одновременно запускается на нескольких инстансах. На одном она работает, остальные ждут. Когда миграция на одном инстансе упадёт, то сразу заработает такая же миграция на другом инстансе, которая сразу же упадёт, потому что начнётся с того места на котором закончил предыдущий инстанс. Всё попадает, деплой завершится неудачей, можно спокойно разобраться по логам, что пошло не так.
Плюс ещё есть небольшая вероятность, что первая миграция упала по таймауту. Допустим больше пяти минут работала. Вторая миграция тогда тоже скоре всего упадёт по таймауту, но впустую потратит при этом пять минут. И так далее, по пять бесполезных минут на инстанс
Для того, чтобы так не получалось обычно поступают следующим образом. Второй инстанс он же ждёт, пока первый закончит миграцию. Максимальное время ожидания — параметр, который можно задать в настройках. Если он будет равен, допустим четырём минутам, то после пятиминуной миграции на первом инстансе, остальные инстансы даже не будут пробовать, а сразу упадут по таймауту.
P. S. Да, если вас интересует подробности того, как liquibase добивается того, чтобы больше одной миграции не работало — то ответ простой. С помощью локов в специальной таблице в БД ))
И у вас в статье не только про это и инструменты не только такую проблему закрывают ))
Вы наверное тут имели в виду, что миграция не должна накатываться два раза по какой-нибудь роковой случайности, да? liquibase это обеспечивает, flywaydb тоже. Хотя я сам использую только liquibase.
Ваш ответ сначала привёл меня в шок, потому что как раз для традиционных веб приложений liquibase это традиционное решение ))). Но потом я посмотрел на теги и не нашёл там java. Тут то всё и встало на свои места.
liquibase это в мире java считай стандартный инструмент для миграций. Или flywaydb, они делают плюс-минус одно и то же. Их можно интегрировать в приложение или запускать как отдельную утилиту. Если в вашем мире подобных стандартных утилит нет, то рекомендую попробовать.
Правда, для запуска пока что ещё нужна java. Думаю рано или поздно это починят и сделают бинарник без дополнительных зависимостей, но пока вот так.
Добавьте ещё liquibase и flywaydb в раздел про то, что нельзя, чтобы на БД в один момент времени работало больше одной миграции. Эти инструменты как раз помогают этого достичь
Всё зависит от контекста. Если в вашем случае в потере нового аватара нет ничего страшного, то это действительно не баг ))
На откатах проще объяснять, но вообще точно такая же проблема будет когда на среде одновременно работает два инстанса с первой и второй версией кода. Вторая версия кода обновит аватар в avatar_url, а первая версия этого обновления не увидит, потому что будет смотреть на поле avatar.
Вы о дополнительном шаге? Думаете в в вашем случае он не актуален?
Он в сценарии переименования таблицы ))
На втором шаге из кода приложения полностью убирается работа с полем avatar. А на первом шаге чтение происходит именно из этого поля.
Если раскатать код из второго шага и дать ему совсем немного поработать, то он запишет новые значения в avatar_url. Дальше возможно придётся делать откат.
После отката старый код будет читать значения из поля avatar. А там значение устаревшее.
Чтобы такого не могло случиться, нужно делать дополнительный шаг. Вторым шагом не прекращать работу с полем avatar, а по прежнему писать и туда и туда, но читать уже из новой колонки.
Фаза 2 у вас соотвественно превращается в Фазу 3, а Фаза 3 в Фазу 4
Полностью поддерживаю! Я сам, знаете ли, своего рода разработчик и написал практически точно такую же статью, как ваша, только другую ))). Правда ещё не опубликовал. И мне тоже многие говорят, что ничего нового тут нет и так далее.
И, наверное, самым красноречивым доказательством того, что такие статьи очень нужны будет тот факт, что у вас в процедуре миграции баг ))). Возможно не фатальный, но самый настоящий. Получается что те люди, которым содержимое вашей статьи кажется очевидным, его не заметили. А значит такие статьи нужны!
P. S. Я не стал рассказывать в чём баг, потому что возможно вам хочется самому разобраться где он. Если вам интересно, я скажу в каком месте он спрятался. Или могу сразу рассказать что за баг, где он и к чему может привести, только напишите )))
Скажите, а это не вы стояли там в витрине, в башмаках с шипами и с ледорубом на плече?
Плюс комментарию, плюс в карму!
Сначала был XML, в котором всё было понятно и только иногда случались холивары по поводу того, что тут поставить — атрибут или вложенный тег. И было куча инструментов. И DTD и XSL, всё было отлично. Но нам казалось, что это всё слишком многословно. Так оно, конечно и было, но всё же в формате были предусмотрены даже комментарии.
Потом появился JSON. Я помню, сильно радовался. Он казался таким элегантным, таким программистским, таким понятным. И не надо было ставить закрывающие теги, всё обходилось закрывающей фигурной скобкой. Я считал, что он идеален. И только потом выяснилось, что комментарии там не предусмотрены, валидация сложная, потому что типизации считай нет и ещё были какие-то проблемы. И ссылок не было предусмотрено, объекты приходилось копировать или придумывать велосипеды. Но по крайней мере там нельзя было полностью всё сломать, поставив лишний пробел. Однако и он показался нам слишком избыточным
И вот сделали YML. Про него в предыдущем комментарии неплохо написано. Хотя кто знает, может дело в том, что с xml и json я провёл гораздо больше времени )).
А текст перевода не редактировали?
С Intellij Idea, кстати, странно, что не упомянута Community Edition
Жырный жырный плюс за статью! Что интересно я сам практически написал такую же, но только про мавен. Не опубликую никак.
Вопрос один меня мучает. Про эти gpg ключи. Там же получается, что ключ никак не привязан к аккаунту на Sonatype. Важно, чтобы он просто был в открытом хранилище ключей. Вот зачем он нужен этот ключ, что там проверяется? Подлинность файлов на случай mtm атаки, так выходит? Ну так атакующий наверное может просто переподписать всё своим ключом
А как там решена проблема, что комиссия за переводы получается настолько большая, что дешёвые покупки делать бессмысленно?
Всё вы правильно пишете. Единственное, что я успел за это время перечитать документацию и поправить свой комментарий ))
Да, это на редкость странное утверждение, что бакеты различаются по ёмкости. Ёмкость это показатель относящийся ко всей HashMap.
Что касается вашего вопроса, то я всегда думал, что capacity это максимальное количество элементов во всей HashMap. То есть сумма элементов во всех бакетах.
Но, согласно документации, capacity это количество бакетов ))). То есть то же самое, что number of buckets. И формула capacity = number of buckets * load factor получается неправильная, если понимать слово capacity в том смысле, в котором оно используется в документации к HashMap
И максимальное количество элементов до перехеширования меньше либо равно capacity * load factor.
А load factor это среднее количество элементов в одном бакете. Ну или процент пустых бакетов при условии, что в заполненных по одному элементу. По умолчания там, кажется 0.75, то есть в среднем в каждом бакете должно быть меньше одного элемента
С одной стороны, приятно почитать код, но с другой стороны нет jmh в тестах производительности, что, конечно, всё портит ((.
Было бы ещё прикольно посмотреть, как эти тесты проходит код с Reflection и погонять на разных версиях джавы, вплоть то 17.
Ещё тысяч 20 на блок питания с корпусом и охлаждение наверное. Это за новое железо так получится?