У тебя есть 3 сервера. Приходит 100 запросов. Как их распределить? Вот возможные варианты:
Алгоритмы балансировки нагрузки
🔸 Round Robin (циклический)
- Запрос 1 —> на сервер A
- Запрос 2 —> на сервер B
- Запрос 3 —> на сервер C
- Запрос 4 —> снова на сервер A
- И так по кругу бесконечно
Когда использовать: все сервера одинаковые, запросы примерно равны по времени обработки. Самый простой вариант.
🔸 Weighted Round Robin (взвешенный циклический)
- Сервер A: 4 ядра, вес 4
- Сервер B: 8 ядер, вес 8
- Сервер C: 4 ядра, вес 4
- Из каждых 16 запросов: A получает 4, B — 8, C — 4
Когда использовать: мощности серверов разные, нужно распределять нагрузку пропорционально.
🔸 Least Connections (наименьшее количество соединений)
- Сервер A: 50 активных соединений
- Сервер B: 30 активных соединений
- Сервер C: 45 активных соединений
- Следующий запрос уходит на сервер B (у него меньше всего соединений)
Когда использовать: запросы обрабатываются разное время, есть долгоживущие соединения, например WebSocket.
🔸 Weighted Least Connections (взвешенный по соединениям)
- Сервер A: 50 соединений, 4 ядра → соотношение 12.5
- Сервер B: 30 соединений, 8 ядер → соотношение 3.75
- Сервер C: 45 соединений, 4 ядра → соотношение 11.25
- Следующий запрос идёт на сервер B (самое низкое соотношение)
Когда использовать: сервера разной мощности, при этом соединения держатся долго.
🔸 IP Hash (хеш по IP)
- IP пользователя: 192.168.1.100
- Этот IP хешируется и всегда маршрутизируется на сервер B
- Один и тот же пользователь всегда попадает на один и тот же сервер
Когда использовать: нужна привязка сессии к конкретному серверу, нет общего session storage. Sticky sessions.
🔸 Least Response Time (наименьшее время отклика)
- Сервер A: средний отклик 200 мс
- Сервер B: 150 мс
- Сервер C: 300 мс
- Следующий запрос уходит на сервер B (самый быстрый)
Когда использовать: производительность серверов разная, например, для чтения из реплик БД с разным lag.
🔸 Random (случайное распределение)
- Просто выбирается случайный сервер
- Ничего отслеживать не нужно
- На больших масштабах работает удивительно неплохо
Когда использовать: простые распределённые системы, stateless-сервисы, когда учёт состояния не оправдан.
В большинстве продакшн-систем хорошо себя показывает вариант Least Connections с весами.
👉 Java Portal
Алгоритмы балансировки нагрузки
- Запрос 1 —> на сервер A
- Запрос 2 —> на сервер B
- Запрос 3 —> на сервер C
- Запрос 4 —> снова на сервер A
- И так по кругу бесконечно
Когда использовать: все сервера одинаковые, запросы примерно равны по времени обработки. Самый простой вариант.
- Сервер A: 4 ядра, вес 4
- Сервер B: 8 ядер, вес 8
- Сервер C: 4 ядра, вес 4
- Из каждых 16 запросов: A получает 4, B — 8, C — 4
Когда использовать: мощности серверов разные, нужно распределять нагрузку пропорционально.
- Сервер A: 50 активных соединений
- Сервер B: 30 активных соединений
- Сервер C: 45 активных соединений
- Следующий запрос уходит на сервер B (у него меньше всего соединений)
Когда использовать: запросы обрабатываются разное время, есть долгоживущие соединения, например WebSocket.
- Сервер A: 50 соединений, 4 ядра → соотношение 12.5
- Сервер B: 30 соединений, 8 ядер → соотношение 3.75
- Сервер C: 45 соединений, 4 ядра → соотношение 11.25
- Следующий запрос идёт на сервер B (самое низкое соотношение)
Когда использовать: сервера разной мощности, при этом соединения держатся долго.
- IP пользователя: 192.168.1.100
- Этот IP хешируется и всегда маршрутизируется на сервер B
- Один и тот же пользователь всегда попадает на один и тот же сервер
Когда использовать: нужна привязка сессии к конкретному серверу, нет общего session storage. Sticky sessions.
- Сервер A: средний отклик 200 мс
- Сервер B: 150 мс
- Сервер C: 300 мс
- Следующий запрос уходит на сервер B (самый быстрый)
Когда использовать: производительность серверов разная, например, для чтения из реплик БД с разным lag.
- Просто выбирается случайный сервер
- Ничего отслеживать не нужно
- На больших масштабах работает удивительно неплохо
Когда использовать: простые распределённые системы, stateless-сервисы, когда учёт состояния не оправдан.
В большинстве продакшн-систем хорошо себя показывает вариант Least Connections с весами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
В Spring Boot аннотация
Тесты выполняются с использованием встроенной базы данных, например H2, а после каждого теста все транзакции автоматически откатываются.
👉 Java Portal
@DataJpaTest используется для изолированного тестирования JPA-репозиториев.@DataJpaTest поднимает только JPA-слой, не загружая весь контекст приложения.Тесты выполняются с использованием встроенной базы данных, например H2, а после каждого теста все транзакции автоматически откатываются.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Maven Plugin Tip — DepClean
DepClean автоматически чистит дерево зависимостей в Java-проектах. Он удаляет все зависимости, которые прописаны в дереве, но при сборке на самом деле не нужны.🔥
https://github.com/ASSERT-KTH/depclean
👉 Java Portal
DepClean автоматически чистит дерево зависимостей в Java-проектах. Он удаляет все зависимости, которые прописаны в дереве, но при сборке на самом деле не нужны.
https://github.com/ASSERT-KTH/depclean
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥2
Векторные базы данных простыми словами
Представь, у тебя есть 10 000 описаний товаров. Пользователь ищет "удобная уличная мебель".
Обычная база данных:
Ищет точные совпадения слов
Находит товары с "удобная" ИЛИ "уличная" ИЛИ "мебель"
Пропускает "уютные кресла для террасы", хотя это то же самое
Ключевые слова — тупой способ поиска
Векторная база данных:
Превращает запрос в набор чисел, отражающих смысл: [0.2, 0.8, 0.1, 0.9, ...]
Каждое описание товара тоже превращается в такие числа
Сравнивает эти "векторы" и ищет похожие по смыслу
Находит "уютные кресла для террасы", потому что векторы похожи
Смысловой поиск — умный поиск
Как это работает
Шаг 1. Превращаем текст в векторы (массивы чисел)
"comfortable chair" → [0.2, 0.7, 0.1, 0.4, ...]
"cozy seat" → [0.3, 0.8, 0.2, 0.5, ...]
Похожие фразы → похожие числа
Это делает AI-модель, например OpenAI embeddings
Шаг 2. Храним векторы
В обычной БД хранят текст
В векторной — массив чисел для каждого объекта
Индексируют их, чтобы быстро искать по схожести
Оптимизировано под "найди похожие", а не "найди точное"
Шаг 3. Ищем по схожести
Запрос: "outdoor furniture"
Превращается в [0.3, 0.6, 0.2, 0.8, ...]
Система ищет ближайшие векторы (через cosine similarity)
Результаты сортируются по степени похожести
Где это используется:
- Поиск товаров, который понимает смысл, а не только слова
- Поиск по документации, который находит релевантные ответы
- Рекомендательные системы
- Чатботы, ищущие похожие вопросы
- Обнаружение аномалий
Популярные векторные базы
Pinecone = управляемая, простая, но дорогая
Weaviate = опенсорс, с кучей функций
Milvus = быстрая и масштабируемая, но сложная
pgvector = расширение для Postgres, простое и удобное
Qdrant = быстрая, написана на Rust
Спорная, но практичная мысль
В большинстве проектов тебе не нужна отдельная векторная база.
Начни с Postgres + pgvector = этого хватает, пока у тебя меньше 1 миллиона векторов.
Когда масштаб вырастет, тогда уже смотри в сторону специализированных решений.
👉 Java Portal
Представь, у тебя есть 10 000 описаний товаров. Пользователь ищет "удобная уличная мебель".
Обычная база данных:
Ищет точные совпадения слов
Находит товары с "удобная" ИЛИ "уличная" ИЛИ "мебель"
Пропускает "уютные кресла для террасы", хотя это то же самое
Ключевые слова — тупой способ поиска
Векторная база данных:
Превращает запрос в набор чисел, отражающих смысл: [0.2, 0.8, 0.1, 0.9, ...]
Каждое описание товара тоже превращается в такие числа
Сравнивает эти "векторы" и ищет похожие по смыслу
Находит "уютные кресла для террасы", потому что векторы похожи
Смысловой поиск — умный поиск
Как это работает
Шаг 1. Превращаем текст в векторы (массивы чисел)
"comfortable chair" → [0.2, 0.7, 0.1, 0.4, ...]
"cozy seat" → [0.3, 0.8, 0.2, 0.5, ...]
Похожие фразы → похожие числа
Это делает AI-модель, например OpenAI embeddings
Шаг 2. Храним векторы
В обычной БД хранят текст
В векторной — массив чисел для каждого объекта
Индексируют их, чтобы быстро искать по схожести
Оптимизировано под "найди похожие", а не "найди точное"
Шаг 3. Ищем по схожести
Запрос: "outdoor furniture"
Превращается в [0.3, 0.6, 0.2, 0.8, ...]
Система ищет ближайшие векторы (через cosine similarity)
Результаты сортируются по степени похожести
Где это используется:
- Поиск товаров, который понимает смысл, а не только слова
- Поиск по документации, который находит релевантные ответы
- Рекомендательные системы
- Чатботы, ищущие похожие вопросы
- Обнаружение аномалий
Популярные векторные базы
Pinecone = управляемая, простая, но дорогая
Weaviate = опенсорс, с кучей функций
Milvus = быстрая и масштабируемая, но сложная
pgvector = расширение для Postgres, простое и удобное
Qdrant = быстрая, написана на Rust
Спорная, но практичная мысль
В большинстве проектов тебе не нужна отдельная векторная база.
Начни с Postgres + pgvector = этого хватает, пока у тебя меньше 1 миллиона векторов.
Когда масштаб вырастет, тогда уже смотри в сторону специализированных решений.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13
Самый прямолинейный способ вынести секреты во внешнее хранилище в Spring Boot приложении это использовать Spring Cloud Config Server.
Spring Cloud Config Server позволяет хранить конфигурацию приложения в централизованном репозитории (обычно Git).
В случае с Git репозиторием при старте приложение подтягивает конфигурационные файлы с Config Server, а не локально, а сам Config Server берет их из Git репозитория. Ниже пример конфигурации, чтобы сервер подключался к Git репо:
Конфигурация клиента может выглядеть примерно так:
Можно шифровать чувствительные данные в конфигурационных файлах в Git репо. Ниже пример с паролем для key-store, который используется для защищенного SSL соединения (обрати внимание на префикс
Альтернатива это использовать HashiCorp Vault
👉 Java Portal
Spring Cloud Config Server позволяет хранить конфигурацию приложения в централизованном репозитории (обычно Git).
В случае с Git репозиторием при старте приложение подтягивает конфигурационные файлы с Config Server, а не локально, а сам Config Server берет их из Git репозитория. Ниже пример конфигурации, чтобы сервер подключался к Git репо:
cloud:
config:
server:
git:
uri: https://github.com/username/spring-cloud-config-git-server-repo.git
username: ${github.username}
password: ${github.password}
Конфигурация клиента может выглядеть примерно так:
config:
import: "optional:configserver:"
Можно шифровать чувствительные данные в конфигурационных файлах в Git репо. Ниже пример с паролем для key-store, который используется для защищенного SSL соединения (обрати внимание на префикс
{cipher}, он обязателен)server:
port: ${PORT:8092}
ssl:
enabled: true
key-store: classpath:books.p12
key-store-password: '{cipher}AAQAB0P8AKMImyLncL3WUbLsn2J0DlHBeMbmylb0e5RMqr7QWrPhDwJ8xVMw...'
key-store-type: PKCS12:
Альтернатива это использовать HashiCorp Vault
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Нашёл минималистичный инструмент, который берет любую shell-команду и в реальном времени рисует по ней графики. Да, прямо у тебя в консоли. Красиво и без плясок с бубном.
Что может:
• Выполняет любые команды и сразу строит графики по их выводу
• Следит за базами, CPU, сетью, очередями, деплоем и чем угодно ещё
• Бьет в колокола, если метрика вылетела за пределы
• Настраивается через обычный YAML. Пара строк и ты уже смотришь, как машина дышит
• Работает локально, без облаков и лишних зависимостей
👉 Java Portal
Что может:
• Выполняет любые команды и сразу строит графики по их выводу
• Следит за базами, CPU, сетью, очередями, деплоем и чем угодно ещё
• Бьет в колокола, если метрика вылетела за пределы
• Настраивается через обычный YAML. Пара строк и ты уже смотришь, как машина дышит
• Работает локально, без облаков и лишних зависимостей
Please open Telegram to view this post
VIEW IN TELEGRAM
В Java строки после создания не меняются.
Вообще. Совсем.
Пишешь:
Кажется, что ты просто дописал кусочек. Но на деле появился новый объект, а старый остался как был.
Зачем так заморачиваться?
Строки одна из самых используемых штук в JVM: названия классов, SQL-запросы, адреса, токены безопасности, всё подряд. И этими строками спокойно шарятся между потоками.
Если бы любой поток мог внезапно изменить текст, который использует другой поток, то был полный бардак: баги из разряда «иногда, где-то, когда-то» и куча дыр в безопасности.
Поэтому неизменяемость даёт:
• Потоки не мешают друг другу. Никаких локов и синхронизации.
• Можно безопасно кешировать строки. Тот же String Pool — из этой оперы.
• JVM может оптимизировать работу с ними как ей вздумается, без риска сломать логику программы.
Если же нужно много править текст во время выполнения (например, большая сборка строки в цикле) то бери StringBuilder или, если сильно нужна потокобезопасность, StringBuffer.
Иммутабельность строки это не чудачество создателей языка. Это фундамент стабильности и безопасности Java.
👉 Java Portal
Вообще. Совсем.
Пишешь:
String saludo = "Hola";
saludo += " mundo";
Кажется, что ты просто дописал кусочек. Но на деле появился новый объект, а старый остался как был.
Зачем так заморачиваться?
Строки одна из самых используемых штук в JVM: названия классов, SQL-запросы, адреса, токены безопасности, всё подряд. И этими строками спокойно шарятся между потоками.
Если бы любой поток мог внезапно изменить текст, который использует другой поток, то был полный бардак: баги из разряда «иногда, где-то, когда-то» и куча дыр в безопасности.
Поэтому неизменяемость даёт:
• Потоки не мешают друг другу. Никаких локов и синхронизации.
• Можно безопасно кешировать строки. Тот же String Pool — из этой оперы.
• JVM может оптимизировать работу с ними как ей вздумается, без риска сломать логику программы.
Если же нужно много править текст во время выполнения (например, большая сборка строки в цикле) то бери StringBuilder или, если сильно нужна потокобезопасность, StringBuffer.
Иммутабельность строки это не чудачество создателей языка. Это фундамент стабильности и безопасности Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍2
Spring Boot 4 показывает нормальную работу null-safety в деле
Главная беда в том, что в Java null всегда был вещью по умолчанию и нигде явно не указан. Видишь метод типа:
User findUserByEmail(String email)
Вернет null? Кто его знает
Spring Boot 4 меняет правила игры с NullMarked (на базе JSpecify + NullAway). Одна аннотация на уровне пакета делает работу с null явной. IDE сразу подсвечивает потенциальные NPE еще на этапе компиляции. Больше никаких угадай-ок и сюрпризов на проде.
Инструменты подталкивают обрабатывать null там, где это действительно важно. Типы наконец начинают говорить правду.
Вот такая developer experience, которой давно ждали.
👉 Java Portal
Главная беда в том, что в Java null всегда был вещью по умолчанию и нигде явно не указан. Видишь метод типа:
User findUserByEmail(String email)
Вернет null? Кто его знает
Spring Boot 4 меняет правила игры с NullMarked (на базе JSpecify + NullAway). Одна аннотация на уровне пакета делает работу с null явной. IDE сразу подсвечивает потенциальные NPE еще на этапе компиляции. Больше никаких угадай-ок и сюрпризов на проде.
Инструменты подталкивают обрабатывать null там, где это действительно важно. Типы наконец начинают говорить правду.
Вот такая developer experience, которой давно ждали.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10❤5👍3
Spring Boot совет: если хочешь, чтобы DTO спокойно переживали лишние поля в JSON от клиента и не роняли API, добавляй аннотацию
Jackson тогда просто проигнорит поля, которых нет в твоем классе, вместо того чтобы кидать
Допустим, есть DTO:
Клиент шлёт такой JSON:
Jackson скажет что-то вроде:
Исправить просто: добавляем
И всё. Лишние поля тихонько проигнорятся, API не падает.
👉 Java Portal
@JsonIgnoreProperties(ignoreUnknown = true)Jackson тогда просто проигнорит поля, которых нет в твоем классе, вместо того чтобы кидать
UnrecognizedPropertyException. Удобно, когда фронты любят прислать что-нибудь от себя.Допустим, есть DTO:
public class UserDTO {
private String name;
private int age;
// getters/setters
}Клиент шлёт такой JSON:
{
"name": "Alice",
"age": 25,
"extraField": "not expected"
}Jackson скажет что-то вроде:
UnrecognizedPropertyException: Unrecognized field "extraField"
Исправить просто: добавляем
@JsonIgnoreProperties@JsonIgnoreProperties(ignoreUnknown = true)
public class UserDTO {
private String name;
private int age;
// getters/setters
}
И всё. Лишние поля тихонько проигнорятся, API не падает.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍5❤2
Исправляем ту самую ошибку на миллиарды долларов? 👀
Улучшения поддержки null-безопасности в Spring Boot 4 могут оказаться самым недооцененным нововведением предстоящего релиза.
Аннотации NonNull и Nullable теперь полноценные граждане во всем фреймворке. Spring постепенно переводит весь код на единый и последовательный подход.
Хватит гадать, вернет ли сервис null. IDE поймает потенциальный NPE уже на этапе компиляции, а не в рантайме.
То ли поправка, о которой мечтал Тони Хоар? Не полностью. Но это важный шаг к более безопасному Java-коду.
Самое приятное? Не нужно мигрировать за один заход. Можно двигаться постепенно, делая код надежнее и уверенно продвигаясь вперед.
Null-безопасность в Spring Boot 4 даст нам ту же уверенность в кодовой базе, что и тесты.👍
👉 Java Portal
Улучшения поддержки null-безопасности в Spring Boot 4 могут оказаться самым недооцененным нововведением предстоящего релиза.
Аннотации NonNull и Nullable теперь полноценные граждане во всем фреймворке. Spring постепенно переводит весь код на единый и последовательный подход.
Хватит гадать, вернет ли сервис null. IDE поймает потенциальный NPE уже на этапе компиляции, а не в рантайме.
То ли поправка, о которой мечтал Тони Хоар? Не полностью. Но это важный шаг к более безопасному Java-коду.
Самое приятное? Не нужно мигрировать за один заход. Можно двигаться постепенно, делая код надежнее и уверенно продвигаясь вперед.
Null-безопасность в Spring Boot 4 даст нам ту же уверенность в кодовой базе, что и тесты.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Подсказка по Spring Boot 4: коллекции с nullable-элементами (List<Nullable String>) помогают ловить NullPointerException на этапе компиляции вместо рантайма. Больше никаких сюрпризов при обработке API-ответов, где могут прилетать null.
👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
Недавно в регионе US-EAST-1 у AWS были сбои.
Как бы ты спроектировал деплой микросервиса и инфраструктуру вокруг, чтобы пережить падение одной инстансы, сбой базы данных или даже отказ целого дата-центра ?
Когда делаем систему с высокой доступностью, нужно сразу исходить из того, что все рано или поздно ломается. Поэтому закладываем автоматическое восстановление на каждом уровне.
Держим несколько одинаковых инстансов сервиса за нагрузочным балансировщиком. Деплоим их в разные зоны. Если одна инстанса упала, балансировщик просто перестает слать ей трафик и направляет запросы на оставшиеся живые экземпляры.
Для базы данных используем репликацию. Есть primary и хотя бы одна hot-standby реплика в другой физической зоне. Все записи в primary сразу копируются на standby.
Практикуем Chaos Engineering: намеренно ломаем часть продовой инфраструктуры, например, убиваем сервисы или добавляем сетевые задержки. Смотрим, что автоматический failover реально срабатывает как задумано, а не только на бумаге.
Please open Telegram to view this post
VIEW IN TELEGRAM
Видишь разницу между этими двумя кусками кода? 👀
На первый взгляд делают одно и то же, но…
В первом варианте все классы вынуждены реализовывать методы, которые им вообще не нужны.
Во втором интерфейсы разделены: каждый класс берет только то, что реально использует.
Принцип разделения интерфейсов (ISP)
👉 Java Portal
На первый взгляд делают одно и то же, но…
В первом варианте все классы вынуждены реализовывать методы, которые им вообще не нужны.
Во втором интерфейсы разделены: каждый класс берет только то, что реально использует.
Принцип разделения интерфейсов (ISP)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤2
5 ноября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
Не все данные обрабатываются одинаково. Понимание, когда подходит batch, а когда stream, решает, получится ли у тебя нормальная архитектура или скрытый тормоз внутри.
Batch Processing собирает данные и обрабатывает их пачками.
Подходит, когда нет требований к моментальной реакции: ежедневные отчеты, бухзакрытия, историческая аналитика.
Он проще, нормально тянет большие объемы и дешевле по деньгам,
но появляется задержка. Событие уже случилось, а ты обрабатываешь его потом.
Stream Processing работает с данными прямо в потоке.
Отлично для мониторинга, антифрода, рекомендаций в реальном времени.
Скорость выше, но инфраструктура сложнее и поддержка дороже.
Часто косячат: ставят stream там, где батча за глаза, или наоборот, лепят batch туда, где важна минимальная задержка.
Фишка не в том, чтобы выбрать самое модное, а в том, чтобы попасть в реальный ритм бизнеса и решить конкретную задачу.
А если ресурсы сильно ограничены, скорее всего, batch уже закрывает потребности.
👉 Java Portal
Batch Processing собирает данные и обрабатывает их пачками.
Подходит, когда нет требований к моментальной реакции: ежедневные отчеты, бухзакрытия, историческая аналитика.
Он проще, нормально тянет большие объемы и дешевле по деньгам,
но появляется задержка. Событие уже случилось, а ты обрабатываешь его потом.
Stream Processing работает с данными прямо в потоке.
Отлично для мониторинга, антифрода, рекомендаций в реальном времени.
Скорость выше, но инфраструктура сложнее и поддержка дороже.
Часто косячат: ставят stream там, где батча за глаза, или наоборот, лепят batch туда, где важна минимальная задержка.
Фишка не в том, чтобы выбрать самое модное, а в том, чтобы попасть в реальный ритм бизнеса и решить конкретную задачу.
А если ресурсы сильно ограничены, скорее всего, batch уже закрывает потребности.
Please open Telegram to view this post
VIEW IN TELEGRAM