Java Geek
2.45K subscribers
272 photos
1 file
24 links
Практичные советы, лайфхаки и код для Java-разработчиков. Каждый пост — реальная польза. Учим Java на примерах.

По всем вопросам @evgenycarter
Download Telegram
🐳 Java Testing: Хватит мокать базы данных!

Вы всё еще используете H2 для тестов, а в продакшене стоит PostgreSQL? Или, может быть, вы поднимаете docker-compose руками перед запуском mvn test?


Как было раньше

Раньше нам приходилось делать трюки с @DynamicPropertySource, чтобы вручную прокинуть jdbc:url, username и password из поднятого контейнера в контекст Spring.


// Old School (Java 17 / Boot 2.7)
@DynamicPropertySource
static void registerPgProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
// ... куча ручного кода
}



Как сейчас

@ServiceConnection сама понимает, что это за контейнер (Postgres, Redis, Kafka, RabbitMQ), и автоматически прописывает нужные свойства в ваш application.properties на время теста.


@Testcontainers
@SpringBootTest
class OrderIntegrationTest {

// 1. Объявляем контейнер
@Container
@ServiceConnection // 👈 Вся магия тут!
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16-alpine");

@Autowired
private OrderRepository repository;

@Test
void shouldSaveOrder() {
// 2. Тест работает с РЕАЛЬНОЙ базой в Docker
var order = new Order("item-123", BigDecimal.TEN);
repository.save(order);

assertThat(repository.findAll()).hasSize(1);
}
}




Писать контейнер в каждом тестовом классе - дурной тон (и медленно, так как Docker будет стартовать каждый раз заново).
В Spring Boot 3.1 появился паттерн TestConfiguration, который позволяет переиспользовать контейнеры.

Создаем один файл конфигурации:


@TestConfiguration(proxyBeanMethods = false)
public class ContainersConfig {

@Bean
@ServiceConnection
public PostgreSQLContainer<?> postgresContainer() {
return new PostgreSQLContainer<>("postgres:16-alpine");
}

@Bean
@ServiceConnection
public KafkaContainer kafkaContainer() {
return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0"));
}
}



Теперь в любом тесте просто импортируем этот конфиг:


@Import(ContainersConfig.class)
@SpringBootTest
class AnyIntegrationTest { ... }




Вы можете использовать этот же конфиг, чтобы запустить само приложение локально с поднятыми контейнерами! Больше не нужно настраивать локальный Postgres.

В папке src/test/java создайте класс для запуска:


public class TestApplication {
public static void main(String[] args) {
SpringApplication.from(MyRealApplication::main)
.with(ContainersConfig.class) // Подключаем наши контейнеры
.run(args);
}
}



Запускаете TestApplication -> Spring сам поднимает Docker-контейнеры -> приложение коннектится к ним -> вы работаете.

🏁 Итог

Изоляция: Каждый прогон тестов - чистая среда.
Честность: Тестируйте на том, что будет в продакшене.
Удобство: @ServiceConnection убрал весь бойлерплейт.

#SpringTest #Testcontainers #Java #DevOps #Docker

👉 @java_geek
5👍3
⚖️ System Design: Балансировщик нагрузки (Load Balancer). Как не уронить сервера?

В прошлом посте мы поняли, что один сервер не справляется, и запустили еще три таких же. Но как пользователи узнают, к какому из них подключаться? Не выдавать же им три разных IP-адреса!

Здесь на сцену выходит Load Balancer (LB) - регулировщик вашего трафика.



LB становится единственной точкой входа. Он принимает на себя все запросы от пользователей и по-умному раскидывает их по вашим серверам. Но как именно он решает, куда отправить следующий запрос? Для этого есть алгоритмы.

🧠 Главные алгоритмы балансировки

1. Round Robin (Карусель)
Самый простой и популярный по умолчанию. Запросы раздаются по кругу: первому серверу, второму, третьему, снова первому.

Плюсы: Легко настроить, нулевая нагрузка на сам LB.

Минусы: Слепой алгоритм. Если 1-й сервер завис, генерируя тяжелый отчет, а 2-й свободен, LB всё равно кинет им запросы поровну. 1-й сервер умрет окончательно.

2. Least Connections (Кто свободнее?)
LB работает как умный менеджер: он считает, сколько активных соединений висит на каждом сервере прямо сейчас. Новый запрос летит туда, где меньше всего работы.

Идеально для: Приложений с долгими соединениями (чаты на WebSockets, потоковая передача видео, скачивание файлов).

3. IP Hash (Липкие сессии / Sticky Sessions)
LB берет IP-адрес пользователя, прогоняет через хэш-функцию и привязывает этот IP к конкретному серверу.

Зачем нужно: Если ваше (легаси) приложение хранит корзину товаров в оперативной памяти конкретного сервера, вам критически важно, чтобы юзер всегда попадал на один и тот же сервер. Иначе на следующем клике его корзина "опустеет".

Современный совет: Старайтесь избегать Sticky Sessions. Храните сессии в Redis, чтобы любой сервер мог обработать любой запрос.

4. Weighted алгоритмы (Система весов)
У вас в кластере два сервера: новый 32-ядерный монстр и старенькая 4-ядерная виртуалка. Если включить обычный Round Robin, старый сервер сгорит.
Вы задаете им "веса" (например, 8 и 1). Теперь мощный сервер будет получать 8 запросов на каждый 1 запрос к слабому.

🛠 Суперспособности балансировщиков

LB - это не только про алгоритмы. У него есть еще две критически важные функции:

🩺 Health Checks (Проверка пульса): Балансировщик постоянно "пингует" свои сервера (например, запрашивает /health). Если сервер не ответил 3 раза подряд, LB помечает его как "мертвый" и перестает слать на него трафик. Пользователи даже не заметят, что один из серверов сгорел.

🔒 SSL Termination: Расшифровка HTTPS-трафика отнимает много ресурсов процессора. Балансировщик может взять эту тяжелую криптографию на себя. Он расшифровывает запрос, а дальше внутри вашей приватной (безопасной) сети общается с серверами по быстрому и легкому HTTP.

#SystemDesign #Backend #LoadBalancer #Architecture #DevOps

👉 @java_geek
3👍2