Spring Boot с одной БД работает гладко. Но как только подключаешь вторую, то всё ломается. Почему и как это правильно настроить?
С одной базой Spring Boot сам автоконфигурит нужные компоненты:
Когда баз становится две, фреймворк не понимает, какую взять за основную. Автоконфигурация перестаёт работать, и нужно явно объявить бины для каждой, одну пометить как✏️
У кого так было?👍
👉 Java Portal
С одной базой Spring Boot сам автоконфигурит нужные компоненты:
DataSource, JdbcTemplate, EntityManagerFactory
и т.д.Когда баз становится две, фреймворк не понимает, какую взять за основную. Автоконфигурация перестаёт работать, и нужно явно объявить бины для каждой, одну пометить как
@Primary
. А дальше подключать их через @Qualifier
там, где требуется. У кого так было?
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍4❤3
Скучаешь? Попробуй собрать что-нибудь своё:
• 3D игру
• 3D-рендерер
• Свой язык для JVM
• свой первый блокчейн на Java
• Android-приложение для Reddit
И это только начало, вот целая подборка✌️
👉 Java Portal
• 3D игру
• 3D-рендерер
• Свой язык для JVM
• свой первый блокчейн на Java
• Android-приложение для Reddit
И это только начало, вот целая подборка
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Когда ты создаешь бин в Spring, его scope определяет, сколько времени он будет жить и как именно шариться между разными частями приложения.
По умолчанию все бины работают как singleton. Это значит, что Spring поднимает один экземпляр при старте и потом везде отдает именно его. Такой вариант подходит для сервисов и репозиториев, где не нужно хранить состояние.
Есть вариант prototype. В этом случае при каждом запросе Spring возвращает новый экземпляр. Но если прототип внедрен внутрь singleton, то на деле получится один и тот же объект, потому что сам singleton создается один раз и сохраняет то, что ему подкинули при инициализации.
В веб-приложениях добавляются дополнительные варианты.
Request создает новый бин на каждый HTTP-запрос.
Session закрепляет бин за конкретной пользовательской сессией, так что один и тот же объект сохраняется для одного пользователя между запросами.
Application делает бин общим для всего приложения, по сути работает как singleton, но привязан к контексту сервлета.
Websocket создает бин, живущий столько, сколько длится одно websocket-соединение.
Если свести все в одно короткое объяснение, singleton глобален, prototype всегда создает новый объект, а веб-скоупы зависят от времени жизни запроса или сессии.🍺
👉 Java Portal
По умолчанию все бины работают как singleton. Это значит, что Spring поднимает один экземпляр при старте и потом везде отдает именно его. Такой вариант подходит для сервисов и репозиториев, где не нужно хранить состояние.
Есть вариант prototype. В этом случае при каждом запросе Spring возвращает новый экземпляр. Но если прототип внедрен внутрь singleton, то на деле получится один и тот же объект, потому что сам singleton создается один раз и сохраняет то, что ему подкинули при инициализации.
В веб-приложениях добавляются дополнительные варианты.
Request создает новый бин на каждый HTTP-запрос.
Session закрепляет бин за конкретной пользовательской сессией, так что один и тот же объект сохраняется для одного пользователя между запросами.
Application делает бин общим для всего приложения, по сути работает как singleton, но привязан к контексту сервлета.
Websocket создает бин, живущий столько, сколько длится одно websocket-соединение.
Если свести все в одно короткое объяснение, singleton глобален, prototype всегда создает новый объект, а веб-скоупы зависят от времени жизни запроса или сессии.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍9
Уровни изоляции в базах данных за 5 минут
ACID описывает свойства, гарантирующие надежность транзакций. Но даже если СУБД заявляет поддержку ACID, по умолчанию она может использовать более слабый уровень изоляции.
Разным приложениям нужно разное, где-то важна скорость и можно потерпеть небольшие несостыковки, а где-то критична строгая целостность данных. Проблема в том, что параллельное выполнение транзакций без контроля ведет к аномалиям: dirty read, non-repeatable read, phantom read
Уровни изоляции определяют, насколько одна транзакция защищена от последствий других, выполняющихся одновременно.
• Read Uncommitted (минимальный уровень)
Транзакции вообще не изолированы. Видно изменения других транзакций даже до их коммита. Это может привести к dirty reads.
• Read Committed
Транзакция видит только закоммиченные данные. Dirty reads исключены, но non-repeatable reads остаются возможны.
• Repeatable Read
Транзакция работает с "замороженным снимком" базы на момент старта. Изменения других транзакций ей не видны. Реализация бывает через блокировки (shared locks) или MVCC (мультиверсии строк). Это убирает non-repeatable reads.
• Serializable
Максимальная строгость. Всё выглядит так, будто транзакции идут последовательно одна за другой. Для этого применяются жесткие блокировки вроде range/predicate locks.
Чем выше уровень изоляции, тем больше гарантий целостности, но тем сильнее удар по производительности. Нужно выбирать баланс под конкретную задачу.😣
👉 Java Portal
ACID описывает свойства, гарантирующие надежность транзакций. Но даже если СУБД заявляет поддержку ACID, по умолчанию она может использовать более слабый уровень изоляции.
Разным приложениям нужно разное, где-то важна скорость и можно потерпеть небольшие несостыковки, а где-то критична строгая целостность данных. Проблема в том, что параллельное выполнение транзакций без контроля ведет к аномалиям: dirty read, non-repeatable read, phantom read
Уровни изоляции определяют, насколько одна транзакция защищена от последствий других, выполняющихся одновременно.
• Read Uncommitted (минимальный уровень)
Транзакции вообще не изолированы. Видно изменения других транзакций даже до их коммита. Это может привести к dirty reads.
• Read Committed
Транзакция видит только закоммиченные данные. Dirty reads исключены, но non-repeatable reads остаются возможны.
• Repeatable Read
Транзакция работает с "замороженным снимком" базы на момент старта. Изменения других транзакций ей не видны. Реализация бывает через блокировки (shared locks) или MVCC (мультиверсии строк). Это убирает non-repeatable reads.
• Serializable
Максимальная строгость. Всё выглядит так, будто транзакции идут последовательно одна за другой. Для этого применяются жесткие блокировки вроде range/predicate locks.
Чем выше уровень изоляции, тем больше гарантий целостности, но тем сильнее удар по производительности. Нужно выбирать баланс под конкретную задачу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
Задумывался, почему случайные числа в Java на самом деле не совсем случайные? 😏
В Java они генерируются с помощью так называемого псевдослучайного генератора чисел. Ключевое слово тут «псевдо» - числа выглядят случайными, но на самом деле вычисляются на основе исходного значения - seed (зерна).
Seed задаёт начальное состояние генератора. Если создать два генератора с одинаковым seed, они будут возвращать абсолютно одинаковую последовательность чисел. Это делает случайные числа воспроизводимыми, что удобно для тестов или симуляций.
Если seed явно не указывать, Java использует текущее системное время для инициализации. Поэтому при каждом запуске результат будет разным.
👉 Java Portal
В Java они генерируются с помощью так называемого псевдослучайного генератора чисел. Ключевое слово тут «псевдо» - числа выглядят случайными, но на самом деле вычисляются на основе исходного значения - seed (зерна).
Seed задаёт начальное состояние генератора. Если создать два генератора с одинаковым seed, они будут возвращать абсолютно одинаковую последовательность чисел. Это делает случайные числа воспроизводимыми, что удобно для тестов или симуляций.
Если seed явно не указывать, Java использует текущее системное время для инициализации. Поэтому при каждом запуске результат будет разным.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥2
JEP 519: Compact Object Headers готов к релизу вместе с Java25
А ещё подъехали Compact Source Files
👉 Java Portal
А ещё подъехали Compact Source Files
Please open Telegram to view this post
VIEW IN TELEGRAM
😁14❤7
В работе с API на Spring Boot часто встречаются три термина: DTO, ModelMapper, Jackson. Разберём, что это и зачем нужно.
1. DTO
DTO это простой Java-класс, который используется для передачи данных между слоями (Controller <-> Service <-> Client).
Почему не использовать Entity напрямую?
- В Entity часто есть лишние поля (ID из БД, служебные поля аудита), которые клиенту видеть не нужно.
- Можно случайно засветить чувствительные данные.
- DTO позволяет держать API-контракты стабильными, даже если структура базы поменялась.
Пример DTO:
2. ModelMapper
ModelMapper это библиотека для автоматического маппинга DTO <-> Entity.
Без него пришлось бы вручную писать:
С ModelMapper это превращается в:
Плюсы: меньше шаблонного кода.
Минусы: для сложных кейсов нужна настройка, а ещё можно легко пропустить баг в маппинге, если полагаться только на автоматику.
3. Jackson
Jackson это библиотека, которую Spring Boot использует для (де)сериализации JSON.
Что делает:
- Превращает Java-объекты в JSON (ответ API).
- Превращает JSON в Java-объекты (тело запроса).
Пример:
автоматически маппится в UserDTO в контроллере.
Как они работают вместе:
- Jackson: JSON <-> DTO
- ModelMapper: DTO <-> Entity
- DTO: слой-контракт между внешними клиентами и внутренними моделями
DTO защищает доменную модель, Jackson работает с JSON, а ModelMapper убирает рутину маппинга.
👉 Java Portal
1. DTO
DTO это простой Java-класс, который используется для передачи данных между слоями (Controller <-> Service <-> Client).
Почему не использовать Entity напрямую?
- В Entity часто есть лишние поля (ID из БД, служебные поля аудита), которые клиенту видеть не нужно.
- Можно случайно засветить чувствительные данные.
- DTO позволяет держать API-контракты стабильными, даже если структура базы поменялась.
Пример DTO:
class UserDTO {
private String name;
private String email;
}
2. ModelMapper
ModelMapper это библиотека для автоматического маппинга DTO <-> Entity.
Без него пришлось бы вручную писать:
dto.setName(entity.getName());
dto.setEmail(entity.getEmail());
С ModelMapper это превращается в:
UserDTO dto = modelMapper.map(userEntity, UserDTO.class);
Плюсы: меньше шаблонного кода.
Минусы: для сложных кейсов нужна настройка, а ещё можно легко пропустить баг в маппинге, если полагаться только на автоматику.
3. Jackson
Jackson это библиотека, которую Spring Boot использует для (де)сериализации JSON.
Что делает:
- Превращает Java-объекты в JSON (ответ API).
- Превращает JSON в Java-объекты (тело запроса).
Пример:
{ "name": "Sumit", "email": "sumit@email.com" }
автоматически маппится в UserDTO в контроллере.
Как они работают вместе:
- Jackson: JSON <-> DTO
- ModelMapper: DTO <-> Entity
- DTO: слой-контракт между внешними клиентами и внутренними моделями
DTO защищает доменную модель, Jackson работает с JSON, а ModelMapper убирает рутину маппинга.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍7
Ты на собеседовании на бэкенд-разработчика. Интервьюер спрашивает:
В чем разница между
Обычно на это отвечают размыто. Давай разложим по полочкам.
Что такое Future
• Появился в Java 5 вместе с Executor framework.
• Представляет результат асинхронного вычисления.
• Обычно ты отдаешь
С ним можно:
• вызвать
• вызвать
• вызвать
И на этом все.
Что добавляет CompletableFuture
• Появился в Java 8, реализует
• Все еще является
• Поддерживает неблокирующие коллбеки (
• Позволяет комбинировать задачи (
• Умеет завершаться вручную через
• Даёт более гибкую обработку ошибок (
Главная разница
С
👉 Java Portal
В чем разница между
Future
и CompletableFuture
в Java?Обычно на это отвечают размыто. Давай разложим по полочкам.
Что такое Future
• Появился в Java 5 вместе с Executor framework.
• Представляет результат асинхронного вычисления.
• Обычно ты отдаешь
Callable
в ExecutorService
, который возвращает Future<T>
.С ним можно:
• вызвать
get()
→ блокирует поток, пока задача не завершится• вызвать
isDone()
→ проверить, закончилась ли задача• вызвать
cancel()
→ попытаться отменить выполнениеИ на этом все.
Future
дает контроль над ожиданием, но никак не управляет тем, что делать, когда результат готов.Что добавляет CompletableFuture
• Появился в Java 8, реализует
Future
и CompletionStage
.• Все еще является
Future
(можно блокироваться, если хочется), но гораздо функциональнее.• Поддерживает неблокирующие коллбеки (
thenApply, thenAccept, thenRun
).• Позволяет комбинировать задачи (
thenCombine, allOf, anyOf
).• Умеет завершаться вручную через
complete()
, чего у Future
нет.• Даёт более гибкую обработку ошибок (
exceptionally, handle
).Главная разница
С
Future
ты просто ждешь результат. С CompletableFuture
ты описываешь, что должно произойти, когда результат появится.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤4
This media is not supported in your browser
VIEW IN TELEGRAM
Полезная находка для разработчиков и студентов - - Wokwi, онлайн-симулятор Arduino и других микроконтроллеров.
Платформа позволяет собирать и запускать проекты прямо в браузере с использованием виртуальных компонентов и встроенных инструментов отладки. Поддерживаются Arduino, ESP32, STM32 и Raspberry Pi Pico.
Wokwi уже набирает популярность в сообществе, так что можно протестировать идеи без физического железа💪
Попробовать можно тут: wokwi.com
👉 Java Portal
Платформа позволяет собирать и запускать проекты прямо в браузере с использованием виртуальных компонентов и встроенных инструментов отладки. Поддерживаются Arduino, ESP32, STM32 и Raspberry Pi Pico.
Wokwi уже набирает популярность в сообществе, так что можно протестировать идеи без физического железа
Попробовать можно тут: wokwi.com
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4👀2
Аннотация
Это не баг, а классическая особенность Spring AOP по дизайну.
Знаешь, почему транзакция вообще не стартует?
Проблема в том, как Spring AOP создаёт прокси. Когда ты ставишь
Этот прокси перехватывает внешние вызовы метода, запускает транзакцию и потом делегирует вызов реальному методу бина.
Это отлично работает, когда внешний бин вызывает твой публичный транзакционный метод, потому что вызов проходит через прокси.
Но при самовызове внутри класса (например,
Чтобы исправить, самое чистое и продакшен-готовое решение это вынести транзакционный метод в отдельный Spring-бин и инжектить его. Тогда вызов всегда будет внешним и пройдёт через прокси, корректно поднимая транзакцию каждый раз.🙈
👉 Java Portal
@Transactional
не работает, когда ты вызываешь метод из другого метода в том же классе?Это не баг, а классическая особенность Spring AOP по дизайну.
Знаешь, почему транзакция вообще не стартует?
Проблема в том, как Spring AOP создаёт прокси. Когда ты ставишь
@Transactional
на метод, Spring не правит байткод класса. Вместо этого он создаёт прокси-объект, который оборачивает твой бин.Этот прокси перехватывает внешние вызовы метода, запускает транзакцию и потом делегирует вызов реальному методу бина.
Это отлично работает, когда внешний бин вызывает твой публичный транзакционный метод, потому что вызов проходит через прокси.
Но при самовызове внутри класса (например,
this.someTransactionalMethod()
) ты вызываешь метод напрямую на целевом объекте (this
), а не через прокси. Транзакционный advice прокси полностью обходится, поэтому транзакция не стартует. Это фундаментальное следствие прокси-based AOP.Чтобы исправить, самое чистое и продакшен-готовое решение это вынести транзакционный метод в отдельный Spring-бин и инжектить его. Тогда вызов всегда будет внешним и пройдёт через прокси, корректно поднимая транзакцию каждый раз.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
Stateful vs Stateless дизайн
Stateless-дизайн сделал возможным простые, но при этом масштабируемые и быстрые приложения. Вместо хранения состояния в памяти сервера, каждый запрос несет все данные для своей обработки. Это убрало лишние накладные расходы и позволило легко масштабировать системы.
Stateful-приложения работают иначе. Они хранят данные вроде user ID, сессий и настроек, что дает персонализацию и избавляет от передачи повторяющейся информации. Но из-за этого тяжело масштабироваться горизонтально.
Stateless-подход стал основой для микросервисов, serverless и REST API. Он ускоряет работу CDN и повышает эффективность сервисов. Но у него есть минусы - - большие размеры запросов, избыточная передача данных и сложности в сценариях, где состояние критично.
На практике чаще выбирают гибрид — сочетание stateful и stateless. Баланс позволяет сделать систему масштабируемой, простой и быстрой, не жертвуя функциональностью💪
👉 Java Portal
Stateless-дизайн сделал возможным простые, но при этом масштабируемые и быстрые приложения. Вместо хранения состояния в памяти сервера, каждый запрос несет все данные для своей обработки. Это убрало лишние накладные расходы и позволило легко масштабировать системы.
Stateful-приложения работают иначе. Они хранят данные вроде user ID, сессий и настроек, что дает персонализацию и избавляет от передачи повторяющейся информации. Но из-за этого тяжело масштабироваться горизонтально.
Stateless-подход стал основой для микросервисов, serverless и REST API. Он ускоряет работу CDN и повышает эффективность сервисов. Но у него есть минусы - - большие размеры запросов, избыточная передача данных и сложности в сценариях, где состояние критично.
На практике чаще выбирают гибрид — сочетание stateful и stateless. Баланс позволяет сделать систему масштабируемой, простой и быстрой, не жертвуя функциональностью
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3
Твой запрос не попадает напрямую в контроллер. Он проходит через цепочку фильтров — Filter Chain. Это основа Spring Security.
Когда HTTP-запрос попадает в Java-приложение, он никогда не идет напрямую в контроллер. Сначала он проходит через Filter Chain — упорядоченную последовательность фильтров, которые могут проверить, изменить или заблокировать запрос до того, как выполнится твой код.
Эта идея пришла из Servlet API. Фильтр реализует метод doFilter(request, response, chain). Внутри можно сделать предобработку (например, логирование или проверку заголовков), вызвать chain.doFilter(request, response), чтобы передать запрос дальше, или прервать выполнение, фактически заблокировав запрос (например, вернув 403 Forbidden).
Spring Security расширяет это через FilterChainProxy, который управляет одним или несколькими SecurityFilterChains. Каждая цепочка применяется к своим URL-паттернам и содержит строго упорядоченный набор фильтров.
Примеры:
• Аутентификационные фильтры (например, UsernamePasswordAuthenticationFilter или кастомный JWT-фильтр) определяют личность пользователя.
• Фильтр авторизации проверяет права и роли.
• Фильтр управления сессией отвечает за логин-сессии.
• CSRF-фильтр защищает от подделки запросов.
• Фильтр перевода исключений гарантирует, что ошибки безопасности вернут правильный ответ.
Порядок имеет значение: аутентификация должна происходить раньше авторизации, CSRF-проверка — до обработки запроса, а обработка исключений должна оборачивать всю цепочку. Поэтому Spring предоставляет методы addFilterBefore и addFilterAfter для кастомизации.
Только после прохождения всех нужных проверок запрос попадает в контроллер.
Простой поток:
Request → Filter Chain → Controller → Response → Filter Chain → Client
👉 Java Portal
Когда HTTP-запрос попадает в Java-приложение, он никогда не идет напрямую в контроллер. Сначала он проходит через Filter Chain — упорядоченную последовательность фильтров, которые могут проверить, изменить или заблокировать запрос до того, как выполнится твой код.
Эта идея пришла из Servlet API. Фильтр реализует метод doFilter(request, response, chain). Внутри можно сделать предобработку (например, логирование или проверку заголовков), вызвать chain.doFilter(request, response), чтобы передать запрос дальше, или прервать выполнение, фактически заблокировав запрос (например, вернув 403 Forbidden).
Spring Security расширяет это через FilterChainProxy, который управляет одним или несколькими SecurityFilterChains. Каждая цепочка применяется к своим URL-паттернам и содержит строго упорядоченный набор фильтров.
Примеры:
• Аутентификационные фильтры (например, UsernamePasswordAuthenticationFilter или кастомный JWT-фильтр) определяют личность пользователя.
• Фильтр авторизации проверяет права и роли.
• Фильтр управления сессией отвечает за логин-сессии.
• CSRF-фильтр защищает от подделки запросов.
• Фильтр перевода исключений гарантирует, что ошибки безопасности вернут правильный ответ.
Порядок имеет значение: аутентификация должна происходить раньше авторизации, CSRF-проверка — до обработки запроса, а обработка исключений должна оборачивать всю цепочку. Поэтому Spring предоставляет методы addFilterBefore и addFilterAfter для кастомизации.
Только после прохождения всех нужных проверок запрос попадает в контроллер.
Простой поток:
Request → Filter Chain → Controller → Response → Filter Chain → Client
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤2
Ты тоже путаешься в этих двух терминах Reverse Proxy и Load Balancer, давай разберёмся
Reverse proxy ставится перед твоими серверными приложениями и проксирует к ним клиентские запросы, его задачи не ограничиваются распределением трафика, он также может делать SSL termination и обрабатывать HTTPS, выполнять аутентификацию и авторизацию, кэшировать ответы, скрывать внутренние детали инфраструктуры, трансформировать запросы и ответы. Примеры NGINX, Apache, HAProxy
Load balancer это частный случай reverse proxy, но с более узкой задачей, распределять входящий трафик между несколькими серверами, он сфокусирован на производительности и доступности, балансировщик следит чтобы ни один сервер не был перегружен и берёт на себя фейловер если один из них отваливается. Примеры HAProxy, AWS ELB, F5
Разница в том что reverse proxy умеет много всего, безопасность, кэширование, роутинг, а load balancer в основном занимается только распределением трафика между серверами. Коротко, все load balancer являются reverse proxy, но не все reverse proxy это load balancer
👉 Java Portal
Reverse proxy ставится перед твоими серверными приложениями и проксирует к ним клиентские запросы, его задачи не ограничиваются распределением трафика, он также может делать SSL termination и обрабатывать HTTPS, выполнять аутентификацию и авторизацию, кэшировать ответы, скрывать внутренние детали инфраструктуры, трансформировать запросы и ответы. Примеры NGINX, Apache, HAProxy
Load balancer это частный случай reverse proxy, но с более узкой задачей, распределять входящий трафик между несколькими серверами, он сфокусирован на производительности и доступности, балансировщик следит чтобы ни один сервер не был перегружен и берёт на себя фейловер если один из них отваливается. Примеры HAProxy, AWS ELB, F5
Разница в том что reverse proxy умеет много всего, безопасность, кэширование, роутинг, а load balancer в основном занимается только распределением трафика между серверами. Коротко, все load balancer являются reverse proxy, но не все reverse proxy это load balancer
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3
Самые ходовые аннотации в Spring Boot
Если ты работал со Spring Boot, то наверняка встречал эти теги на каждом шагу. Вот топ-10:
I)
II)
III)
IV)
V)
VI)
VII)
VIII)
IX)
X)
❓ Сколько из них ты реально использовал в продакшн-коде?
👉 Java Portal
Если ты работал со Spring Boot, то наверняка встречал эти теги на каждом шагу. Вот топ-10:
I)
@SpringBootApplication
II)
@RestController
III)
@RequestMapping
/ @GetMapping
/ @PostMapping
IV)
@Autowired
V)
@Component
VI)
@Service
VII)
@Repository
VIII)
@Configuration
IX)
@Bean
X)
@Value
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥2
«Что такое CAP-теорема и почему она важна в распределённых системах?»
CAP-теорема утверждает, что в распределённой базе данных одновременно можно гарантировать только два свойства из трёх - Consistency, Availability и Partition Tolerance. Так как сетевые разделения неизбежны, приходится выбирать между консистентностью и доступностью.
Consistency означает, что каждое чтение возвращает самую последнюю запись, независимо от того, на какой реплике выполняется запрос. Для сильной консистентности обычно требуется координация между узлами перед тем, как подтвердить ответ.
Availability означает, что каждый запрос получает ответ, даже если это не самые свежие данные. Система остаётся доступной и отвечает на запросы, несмотря на сбои отдельных узлов.
Partition Tolerance означает, что система продолжает работать даже при сетевых разрывах или потере сообщений. В реальности разделения всегда происходят, поэтому это свойство нельзя исключить.
Так как P всегда должно выполняться, в реальных системах приходится выбирать между CP и AP.
CP-системы отдают приоритет консистентности и устойчивости к разделению, жертвуя доступностью во время сбоев. Примеры — ZooKeeper, Google Spanner, CockroachDB.
AP-системы делают ставку на доступность и устойчивость к разделению, во время проблем могут отдавать устаревшие или несовпадающие данные, но со временем данные приходят к единому состоянию. Примеры — Cassandra, Riak, DynamoDB.
CP имеет смысл для финансовых и критически важных приложений, где важна корректность данных. AP лучше подходит для масштабных систем, где приоритет — чтобы сервис всегда отвечал, даже ценой временной рассогласованности. Многие современные базы позволяют настраивать уровень консистентности под конкретные задачи.
👉 Java Portal
CAP-теорема утверждает, что в распределённой базе данных одновременно можно гарантировать только два свойства из трёх - Consistency, Availability и Partition Tolerance. Так как сетевые разделения неизбежны, приходится выбирать между консистентностью и доступностью.
Consistency означает, что каждое чтение возвращает самую последнюю запись, независимо от того, на какой реплике выполняется запрос. Для сильной консистентности обычно требуется координация между узлами перед тем, как подтвердить ответ.
Availability означает, что каждый запрос получает ответ, даже если это не самые свежие данные. Система остаётся доступной и отвечает на запросы, несмотря на сбои отдельных узлов.
Partition Tolerance означает, что система продолжает работать даже при сетевых разрывах или потере сообщений. В реальности разделения всегда происходят, поэтому это свойство нельзя исключить.
Так как P всегда должно выполняться, в реальных системах приходится выбирать между CP и AP.
CP-системы отдают приоритет консистентности и устойчивости к разделению, жертвуя доступностью во время сбоев. Примеры — ZooKeeper, Google Spanner, CockroachDB.
AP-системы делают ставку на доступность и устойчивость к разделению, во время проблем могут отдавать устаревшие или несовпадающие данные, но со временем данные приходят к единому состоянию. Примеры — Cassandra, Riak, DynamoDB.
CP имеет смысл для финансовых и критически важных приложений, где важна корректность данных. AP лучше подходит для масштабных систем, где приоритет — чтобы сервис всегда отвечал, даже ценой временной рассогласованности. Многие современные базы позволяют настраивать уровень консистентности под конкретные задачи.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤4
Почему устойчивые микросервисы продолжают работать даже когда их зависимости рушатся? У них есть общий приём Circuit Breaker и в Spring Boot это делается довольно просто.
В распределённых системах - отказы обычное дело, базы могут подвисать, API уходить в таймауты, сеть лагать. Без защиты такие сбои начинают цепной реакцией сжирать потоки и валить сервис. Circuit Breaker решает проблему когда количество ошибок превышает порог он размыкается и быстро возвращает фолбэк вместо того чтобы долбиться в нерабочий ресурс.
В Spring Boot для этого используют лёгкую и современную библиотеку Resilience4j. Там настраиваются порог ошибок, время ожидания и правила восстановления. Как только выключатель уходит в open все запросы режутся. По истечении тайм аута он переключается в half open и пропускает несколько тестовых вызовов. Если они проходят успешно, схема снова закрывается и трафик идёт как обычно. Если нет возвращается в open.
В итоге сервис остаётся отзывчивым даже если его зависимости лежат. В паре с таймаутами, ретраями и bulkhead изоляцией, это превращается в полноценный набор для отказоустойчивости. Польза очевидна, вместо падения всей системы - аккуратная деградация и стабильность, что и отличает продакшен уровень.
👉 Java Portal
В распределённых системах - отказы обычное дело, базы могут подвисать, API уходить в таймауты, сеть лагать. Без защиты такие сбои начинают цепной реакцией сжирать потоки и валить сервис. Circuit Breaker решает проблему когда количество ошибок превышает порог он размыкается и быстро возвращает фолбэк вместо того чтобы долбиться в нерабочий ресурс.
В Spring Boot для этого используют лёгкую и современную библиотеку Resilience4j. Там настраиваются порог ошибок, время ожидания и правила восстановления. Как только выключатель уходит в open все запросы режутся. По истечении тайм аута он переключается в half open и пропускает несколько тестовых вызовов. Если они проходят успешно, схема снова закрывается и трафик идёт как обычно. Если нет возвращается в open.
В итоге сервис остаётся отзывчивым даже если его зависимости лежат. В паре с таймаутами, ретраями и bulkhead изоляцией, это превращается в полноценный набор для отказоустойчивости. Польза очевидна, вместо падения всей системы - аккуратная деградация и стабильность, что и отличает продакшен уровень.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥4❤1
Почему логи уже не спасают в мире микросервисов
Когда один запрос может пролетать через 10+ сервисов, по логам не всегда поймёшь, где именно произошёл затык или фейл.
Тут на сцену выходит OpenTelemetry — современный cloud-native стандарт для распределённого трейсинга.
Он умеет работать с Jaeger, Tempo, Zipkin, Prometheus, Grafana и собирает не только трейсинг, но ещё и метрики с логами — всё в одном месте.
Логи отвечают на вопрос что произошло.
Трейсы показывают где это произошло.
А ты уже внедрял OpenTelemetry в свои сервисы?🍺
👉 Java Portal
Когда один запрос может пролетать через 10+ сервисов, по логам не всегда поймёшь, где именно произошёл затык или фейл.
Тут на сцену выходит OpenTelemetry — современный cloud-native стандарт для распределённого трейсинга.
Он умеет работать с Jaeger, Tempo, Zipkin, Prometheus, Grafana и собирает не только трейсинг, но ещё и метрики с логами — всё в одном месте.
Логи отвечают на вопрос что произошло.
Трейсы показывают где это произошло.
А ты уже внедрял OpenTelemetry в свои сервисы?
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍5
Задумывались ли вы, что поддерживает приложение Spring Boot в живом состоянии и работоспособном? ❔
Это
Объясняю проще:
В Spring Boot
Он отвечает за загрузку конфигураций, создание и связывание бинов, управление их жизненным циклом и предоставляет такие сервисы, как загрузка ресурсов, интернационализация, доступ к окружению/профилям и публикация событий приложения.
Когда контекст обновляется (например, при старте приложения), он читает источники конфигурации (аннотации, свойства, XML и автоконфигурацию), регистрирует
Обычно вы взаимодействуете с бинами через dependency injection, а не через их поиск, но вы можете получить бин программно с помощью
Spring Boot строится поверх Spring, используя
Существуют различные реализации
Вкратце,
👉 Java Portal
Это
ApplicationContext
, настоящее сердце Spring Boot.Объясняю проще:
В Spring Boot
ApplicationContext
это центральный контейнер времени выполнения, который управляет компонентами вашего приложения, называемыми beans (бинами).Он отвечает за загрузку конфигураций, создание и связывание бинов, управление их жизненным циклом и предоставляет такие сервисы, как загрузка ресурсов, интернационализация, доступ к окружению/профилям и публикация событий приложения.
Когда контекст обновляется (например, при старте приложения), он читает источники конфигурации (аннотации, свойства, XML и автоконфигурацию), регистрирует
BeanPostProcessors
и BeanFactoryPostProcessors
, и по умолчанию заранее создаёт синглтон-бины, чтобы они были готовы к использованию.Обычно вы взаимодействуете с бинами через dependency injection, а не через их поиск, но вы можете получить бин программно с помощью
getBean
Spring Boot строится поверх Spring, используя
ApplicationContext
для регистрации и конфигурации авто-конфигурируемых бинов, что позволяет использовать конвенции "из коробки".ConfigurableApplicationContext
предоставляет операции жизненного цикла, такие как refresh() и close(), а также публикует события жизненного цикла, такие как ContextRefreshedEvent
Существуют различные реализации
ApplicationContext
для разных случаев использования, например, AnnotationConfigApplicationContext для Java-конфигурации и WebApplicationContext для веб-приложений.Вкратце,
ApplicationContext
это сердце Spring Boot, потому что многое из поведения фреймворка, включая управление бинами, конфигурацию и точки интеграции, организовано и обслуживается через него. Он поддерживает иерархии контекстов для изоляции в модульных приложениях и обеспечивает надёжное разрешение ресурсов.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3
Выбор структуры данных
I. Быстрый поиск → HashMap
II. Отсортированный порядок → Сбалансированное BST (AVL, Красно-Чёрное дерево)
III. FIFO / LIFO → Очередь / Стек
IV. Поиск по префиксу → Trie
V. Связность → Union-Find
VI. Запросы по диапазону → Segment Tree
VII. Медиана потока → Две кучи (Two Heaps)
VIII. Скользящее окно → Deque
IX. Вытеснение кэша → LRU Cache
👉 Java Portal
I. Быстрый поиск → HashMap
II. Отсортированный порядок → Сбалансированное BST (AVL, Красно-Чёрное дерево)
III. FIFO / LIFO → Очередь / Стек
IV. Поиск по префиксу → Trie
V. Связность → Union-Find
VI. Запросы по диапазону → Segment Tree
VII. Медиана потока → Две кучи (Two Heaps)
VIII. Скользящее окно → Deque
IX. Вытеснение кэша → LRU Cache
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍4
Ты на интервью по системному дизайну. Спрашивают: «Как бы ты спроектировал слой кэширования для высоконагруженного веб-приложения?»
Вот подробный подход:
I. Что кэшировать → Кэшируй дорогие запросы к БД, горячие данные с большим количеством чтений и статические ресурсы; избегай очень динамичных, гигантских объектов или чувствительной PII, если только она не зашифрована и не защищена доступом.
II. Хранилище кэша → Используй Redis или Memcached для распределённого in-memory кэша, CDN для статики на краю сети, локальные in-process кэши (например, Caffeine) для сверхнизкой задержки L1.
III. Паттерн и запись → По умолчанию Cache-Aside: читаем из кэша, при промахе читаем из БД и заполняем кэш. Для сильной консистентности чтения — Write-Through (пишем одновременно в кэш и БД). Всегда сначала коммитим БД, потом обновляем/инвалидируем кэш, чтобы не дать устаревшим данным просочиться.
IV. Истечение и вытеснение → TTL для каждого типа данных, чтобы держать кэш свежим, политики вытеснения (LRU/LFU) для управления памятью, negative caching для промахов, чтобы не перегружать БД. Ограничивай размер объектов, чтобы не создавать проблемы с памятью и сборкой мусора.
V. Масштабирование и «горячие ключи» → Масштабируй через consistent hashing и реплики для пропускной способности чтения. Многоуровневый кэш (edge→regional→local). Горячие ключи — локальные L1 кэши, отдельные кэши для горячих ключей, либо rate-limiting запросов.
VI. Надёжность и наблюдаемость → Предотвращай «каскады» промахов через request coalescing, короткие блокировки (SETNX + expiry) или serve-stale-while-revalidate с jittered TTL. Мониторь hit rate, latency, eviction, память и replication lag с алертами.
👉 Java Portal
Вот подробный подход:
I. Что кэшировать → Кэшируй дорогие запросы к БД, горячие данные с большим количеством чтений и статические ресурсы; избегай очень динамичных, гигантских объектов или чувствительной PII, если только она не зашифрована и не защищена доступом.
II. Хранилище кэша → Используй Redis или Memcached для распределённого in-memory кэша, CDN для статики на краю сети, локальные in-process кэши (например, Caffeine) для сверхнизкой задержки L1.
III. Паттерн и запись → По умолчанию Cache-Aside: читаем из кэша, при промахе читаем из БД и заполняем кэш. Для сильной консистентности чтения — Write-Through (пишем одновременно в кэш и БД). Всегда сначала коммитим БД, потом обновляем/инвалидируем кэш, чтобы не дать устаревшим данным просочиться.
IV. Истечение и вытеснение → TTL для каждого типа данных, чтобы держать кэш свежим, политики вытеснения (LRU/LFU) для управления памятью, negative caching для промахов, чтобы не перегружать БД. Ограничивай размер объектов, чтобы не создавать проблемы с памятью и сборкой мусора.
V. Масштабирование и «горячие ключи» → Масштабируй через consistent hashing и реплики для пропускной способности чтения. Многоуровневый кэш (edge→regional→local). Горячие ключи — локальные L1 кэши, отдельные кэши для горячих ключей, либо rate-limiting запросов.
VI. Надёжность и наблюдаемость → Предотвращай «каскады» промахов через request coalescing, короткие блокировки (SETNX + expiry) или serve-stale-while-revalidate с jittered TTL. Мониторь hit rate, latency, eviction, память и replication lag с алертами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤4🔥2