Docker это не мини-виртуальные машины
Многие пользуются Docker каждый день, но не особо понимают, что происходит под капотом. Это становится очевидно, когда начинаются проблемы с производительностью, правами доступа или сетью.
1. Docker — это не виртуалка
Когда ты запускаешь docker run ubuntu, ты не создаешь «мини-компьютер».
Никакого нового ядра нет.
Контейнер использует то же ядро, что и хост — просто в изоляции.
Поэтому он стартует за миллисекунды и ест меньше оперативки, чем виртуальная машина.
2. Изоляция достигается через namespaces
Namespace говорит системе:
«Этот процесс видит только вот этот кусочек мира».
Примеры:
PID namespace — контейнер думает, что его процесс 1 — единственный.
NET namespace — у контейнера своя сеть и интерфейсы.
MNT namespace — своя файловая система с примонтированными ресурсами.
Так несколько контейнеров могут спокойно жить рядом, не мешая друг другу.
3. Cgroups ограничивают ресурсы
Контейнер может считать, что владеет всей машиной…
но control groups (cgroups) ставят реальные лимиты:
- максимум CPU (--cpus=2)
- максимум памяти (--memory=1g)
- лимиты на I/O или количество процессов
Если контейнер пытается выйти за рамки, ядро его просто отрубает😅
4. Файловая система и слои (UnionFS)
Образ это не один файл, а набор слоев.
Каждая инструкция RUN, COPY или ADD в Dockerfile создает новый слой.
Когда контейнер запускается, поверх монтируется временный слой для записи.
Вот почему все изменения исчезают после удаления контейнера —
временный слой просто выкидывается.
5. Как контейнеры общаются между собой
Docker создает виртуальные сети внутри хоста.
Каждый контейнер получает свой внутренний IP.
Когда ты используешь --link или docker-compose,
ты просто задаешь внутренние DNS-имена.
Во внешний мир трафик не выходит,
пока ты сам не пробросишь порт через -p 8080:80.
6. Безопасность -изоляция не идеальна
Поскольку ядро общее, защита не такая жесткая, как у виртуалки.
Для этого и придуманы штуки вроде:
gVisor — песочница для системных вызовов
SELinux или AppArmor
rootless Docker
Если запускаешь сторонние контейнеры — лучше использовать их.
Так что же такое Docker на самом деле?
Это оркестратор изоляции:
- прячет ресурсы через namespaces
- ограничивает их через cgroups
- управляет файловой системой через UnionFS
- эмулирует сеть через network namespaces
Он ничего не эмулирует по-настоящему,
он просто создает очень правдоподобную иллюзию👏
Понимание этого полностью меняет подход к дебагу и оптимизации.
Контейнер жрет всю оперативку? → смотри cgroups.
Не может подключиться к сети? → проверь network namespace.
Билды весят по 5 ГБ? → разбери слои образа.
👉 Java Portal
Многие пользуются Docker каждый день, но не особо понимают, что происходит под капотом. Это становится очевидно, когда начинаются проблемы с производительностью, правами доступа или сетью.
1. Docker — это не виртуалка
Когда ты запускаешь docker run ubuntu, ты не создаешь «мини-компьютер».
Никакого нового ядра нет.
Контейнер использует то же ядро, что и хост — просто в изоляции.
Поэтому он стартует за миллисекунды и ест меньше оперативки, чем виртуальная машина.
2. Изоляция достигается через namespaces
Namespace говорит системе:
«Этот процесс видит только вот этот кусочек мира».
Примеры:
PID namespace — контейнер думает, что его процесс 1 — единственный.
NET namespace — у контейнера своя сеть и интерфейсы.
MNT namespace — своя файловая система с примонтированными ресурсами.
Так несколько контейнеров могут спокойно жить рядом, не мешая друг другу.
3. Cgroups ограничивают ресурсы
Контейнер может считать, что владеет всей машиной…
но control groups (cgroups) ставят реальные лимиты:
- максимум CPU (--cpus=2)
- максимум памяти (--memory=1g)
- лимиты на I/O или количество процессов
Если контейнер пытается выйти за рамки, ядро его просто отрубает
4. Файловая система и слои (UnionFS)
Образ это не один файл, а набор слоев.
Каждая инструкция RUN, COPY или ADD в Dockerfile создает новый слой.
Когда контейнер запускается, поверх монтируется временный слой для записи.
Вот почему все изменения исчезают после удаления контейнера —
временный слой просто выкидывается.
5. Как контейнеры общаются между собой
Docker создает виртуальные сети внутри хоста.
Каждый контейнер получает свой внутренний IP.
Когда ты используешь --link или docker-compose,
ты просто задаешь внутренние DNS-имена.
Во внешний мир трафик не выходит,
пока ты сам не пробросишь порт через -p 8080:80.
6. Безопасность -изоляция не идеальна
Поскольку ядро общее, защита не такая жесткая, как у виртуалки.
Для этого и придуманы штуки вроде:
gVisor — песочница для системных вызовов
SELinux или AppArmor
rootless Docker
Если запускаешь сторонние контейнеры — лучше использовать их.
Так что же такое Docker на самом деле?
Это оркестратор изоляции:
- прячет ресурсы через namespaces
- ограничивает их через cgroups
- управляет файловой системой через UnionFS
- эмулирует сеть через network namespaces
Он ничего не эмулирует по-настоящему,
он просто создает очень правдоподобную иллюзию
Понимание этого полностью меняет подход к дебагу и оптимизации.
Контейнер жрет всю оперативку? → смотри cgroups.
Не может подключиться к сети? → проверь network namespace.
Билды весят по 5 ГБ? → разбери слои образа.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤2
Представим, что тебе нужно посчитать максимальную зарплату сотрудников по отделам на Java. Код мог бы выглядеть так:
Но этот цикл можно записать гораздо короче:
Метод Map.merge() работает так:
Первый параметр — это ключ, по которому ты хочешь добавить или обновить значение в Map.
Второй параметр — новое значение, которым нужно обновить сохранённое.
Если для этого ключа значение отсутствует (или там null), Map просто сохраняет новое значение.
Третий параметр — это функция. Если в Map уже есть значение для этого ключа, функция вызывается с двумя аргументами: старым и новым значением. То, что вернёт эта функция, и будет записано как новое значение для ключа.
👉 Java Portal
List<Employee> employees = new ArrayList<>();
Map<String, Long> maxMap = new HashMap<>();
for (Employee employee : employees) {
Long maxSalaryForDepartment = maxMap.get(employee.department);
if (maxSalaryForDepartment == null || maxSalaryForDepartment < employee.salary) {
maxMap.put(employee.department, employee.salary);
}
}
Но этот цикл можно записать гораздо короче:
for (Employee employee : employees) {
maxMap.merge(employee.department, employee.salary, Math::max);
}Метод Map.merge() работает так:
Первый параметр — это ключ, по которому ты хочешь добавить или обновить значение в Map.
Второй параметр — новое значение, которым нужно обновить сохранённое.
Если для этого ключа значение отсутствует (или там null), Map просто сохраняет новое значение.
Третий параметр — это функция. Если в Map уже есть значение для этого ключа, функция вызывается с двумя аргументами: старым и новым значением. То, что вернёт эта функция, и будет записано как новое значение для ключа.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤3
Экосистема разработки API с открытым исходным кодом
https://github.com/hoppscotch/hoppscotch/
👉 Java Portal
https://github.com/hoppscotch/hoppscotch/
Please open Telegram to view this post
VIEW IN TELEGRAM
Паттерны микросервисов для Java / Backend-разработчиков
Для Java и backend-разработчика знание паттернов микросервисов — это базовый навык.
Он делает тебя сильнее как инженера и помогает уверенно проходить собеседования.
Сохрани, выучи и применяй, и ты будешь на шаг впереди остальных.
Освой эти паттерны и ты поймёшь, как проектировать надёжные, масштабируемые и поддерживаемые системы.
👉 Java Portal
Для Java и backend-разработчика знание паттернов микросервисов — это базовый навык.
Он делает тебя сильнее как инженера и помогает уверенно проходить собеседования.
Сохрани, выучи и применяй, и ты будешь на шаг впереди остальных.
🔸 Application Architecture Patterns
Высокоуровневые схемы структуры систем:
- Monolithic architecture
- Microservice architecture🔸 External API Patterns
Подходы к проектированию API для сторонних разработчиков:
- API Gateway
- Backends for Frontend (BFF)🔸 Decomposition Patterns
Как разделить большую систему на независимые сервисы:
- Decompose by business capability
- Decompose by subdomain🔸 Testing Patterns
Подходы к проверке корректности микросервисов:
- Consumer-driven contract test
- Consumer-side contract test
- Service component test🔸 Messaging Style Patterns
Схемы асинхронного взаимодействия сервисов:
- Messaging
- Remote Procedure Invocation (RPI)🔸 Security Patterns
Решения для аутентификации и авторизации:
- Access Token🔸 Reliable Communication Patterns
Техники обработки сбоев при взаимодействии сервисов:
- Circuit Breaker🔸 Cross-cutting Concerns Patterns
Обработка общих функций вроде логирования и метрик:
- Externalized Configuration
- Microservice Chassis🔸 Service Discovery Patterns
Как сервисы находят друг друга в сети:
- 3rd Party Registration
- Client-side Discovery
- Self-registration
- Server-side Discovery🔸 Observability Patterns
Как понять, что происходит внутри системы:
- Application Metrics
- Audit Logging
- Distributed Tracing
- Exception Tracking
- Health Check API
- Log Aggregation🔸 Transactional Messaging Patterns
Обеспечение согласованности данных между сервисами:
- Polling Publisher
- Transaction Log Tailing
- Transactional Outbox🔸 Deployment Patterns
Подходы к безопасному релизу новых версий сервисов:
- Deploy as Container
- Deploy as VM
- Language-specific Packaging
- Service Mesh
- Serverless Deployment
- Sidecar🔸 Data Consistency Patterns
Как управлять целостностью данных в распределённых БД:
- Saga🔸 Business Logic Design Patterns
Как организовать доменную модель и бизнес-логику:
- Aggregate
- Domain Event
- Domain Model
- Event Sourcing
- Transaction Script🔸 Refactoring to Microservices Patterns
Как поэтапно мигрировать монолит в микросервисы:
- Transaction Script
- Strangler Application🔸 Querying Patterns
Как извлекать данные из нескольких сервисов:
- API Composition
- CQRS (Command Query Responsibility Segregation)
Освой эти паттерны и ты поймёшь, как проектировать надёжные, масштабируемые и поддерживаемые системы.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Как отладить медленный API
Твой API тормозит. Пользователи жалуются. И ты не понимаешь, с чего вообще начать. Вот пошаговый подход, который поможет вычислить, что именно душит производительность.
Главное действовать системно. Не бросайся фиксить вслепую. Сначала измерь, найди конкретное узкое место — потом исправляй.
👉 Java Portal
Твой API тормозит. Пользователи жалуются. И ты не понимаешь, с чего вообще начать. Вот пошаговый подход, который поможет вычислить, что именно душит производительность.
1. Начни с сети.
Высокая задержка? Поставь CDN перед статикой. Слишком большой payload? Сжимай ответы. Это простые решения, не требующие правки кода.
2. Проверь бэкенд.
Чаще всего проблема там. Тяжелые по CPU операции нужно выносить в фон. Сложная бизнес-логика — упрощать. Синхронные блокирующие вызовы — делать асинхронными. Прогони профилирование, найди узкие места и оптимизируй.
3. Загляни в базу данных.
Отсутствующие индексы — классическая причина тормозов. Ещё одна ловушка — N+1 запросы, когда вместо одного батч-запроса база получает сотни одинаковых обращений.
4. Не забудь про внешние API.
Вызовы вроде Stripe или Google Maps не под твоим контролем. Где возможно — запускай их параллельно. Настрой агрессивные таймауты и ретраи, чтобы один медленный сторонний сервис не тормозил весь ответ.
5. Проверь инфраструктуру.
Если серверы забиты под завязку — настрой авто-масштабирование. Подкорректируй лимиты connection pool. Иногда дело не в коде, а в том, что ты пытаешься обслужить 10 000 запросов на ресурсах, рассчитанных на 100.
Главное действовать системно. Не бросайся фиксить вслепую. Сначала измерь, найди конкретное узкое место — потом исправляй.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥3
На реальном собеседовании по Java задать вот такой простой вопрос — не лучший способ проверить, насколько кандидат реально разбирается в теме. Поэтому часто добавляют сценарий, чтобы оценить глубину понимания.
Как заставить три потока — T1, T2 и T3 — выполняться строго по очереди, один за другим?
Сценарий:
Ты разрабатываешь пайплайн обработки данных, который состоит из трёх этапов:
Скачивание данных с удалённого источника,
Обработка скачанных данных,
Сохранение результатов в базу данных.
Каждый этап должен выполняться в отдельном потоке, но строго последовательно: второй этап начинается только после завершения первого, а третий — только после второго. Как реализовать это, чтобы гарантировать порядок выполнения?
Подсказка:
Метод Thread.join() позволяет одному потоку дождаться завершения другого. Когда поток вызывает t.join(), он приостанавливает своё выполнение и ждёт, пока поток t не завершится.
👉 Java Portal
Как заставить три потока — T1, T2 и T3 — выполняться строго по очереди, один за другим?
Сценарий:
Ты разрабатываешь пайплайн обработки данных, который состоит из трёх этапов:
Скачивание данных с удалённого источника,
Обработка скачанных данных,
Сохранение результатов в базу данных.
Каждый этап должен выполняться в отдельном потоке, но строго последовательно: второй этап начинается только после завершения первого, а третий — только после второго. Как реализовать это, чтобы гарантировать порядок выполнения?
Подсказка:
Метод Thread.join() позволяет одному потоку дождаться завершения другого. Когда поток вызывает t.join(), он приостанавливает своё выполнение и ждёт, пока поток t не завершится.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3
Как
В статье объясняется, что аннотация
Подробности: http://www.java67.com/2023/04/what-is-component-annotation-in-spring.html
👉 Java Portal
@Component в Spring управляет зависимостямиВ статье объясняется, что аннотация
@Component помечает класс как bean, Spring сканирует такие классы и создаёт экземпляры для автосвязывания. @Component — основа для @Service, @Repository и @Controller, важная деталь DI в Spring. Подробности: http://www.java67.com/2023/04/what-is-component-annotation-in-spring.html
Please open Telegram to view this post
VIEW IN TELEGRAM
Spring Boot: используй spring-boot-starter-mail для отправки писем.
Этот стартер включает все необходимые зависимости и настройки, делая процесс отправки писем простым и понятным.
👉 Java Portal
Этот стартер включает все необходимые зависимости и настройки, делая процесс отправки писем простым и понятным.
// Добавь зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
// Настрой параметры почты в application.properties (или application.yml):
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=my_email@gmail.com
spring.mail.password=my_password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
// Используй JavaMailSender в коде:
...
@Autowired
private JavaMailSender mailSender;
public void sendEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
message.setFrom("your_email@gmail.com");
mailSender.send(message);
}
...
Please open Telegram to view this post
VIEW IN TELEGRAM
2❤13👍3🔥2
PocketBase — лёгкий open-source бэкенд в одном файле для быстрого создания приложений с базой данных, аутентификацией, хранением файлов и панелью администратора. Идеален для прототипов и небольших проектов.
👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥2
Совет по продвинутому использованию Spring
Используйте Spring SSEEvent для плавных реальных обновлений в ваших приложениях.
👉 Java Portal
Используйте Spring SSEEvent для плавных реальных обновлений в ваших приложениях.
@GetMapping("/events")
public Flux<ServerSentEvent<String>> events() {
return Flux.interval(Duration.ofSeconds(1)) // каждую секунду создаётся новое событие
.map(sequence -> ServerSentEvent.<String>builder()
.id(String.valueOf(sequence)) // задаём ID события
.event("message") // тип события (можно использовать для фильтрации на клиенте)
.data("Event #" + sequence + " @ " + LocalTime.now()) // данные события
.build());
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Вся линейка JDK уже доступна! Теперь можно использовать все основные сборки Java 25, включая IBM Semeru на движке OpenJ9 🙌
Читай в их блоге, чтобы узнать, как установить свежий JDK в свою IDE.
👉 Java Portal
Читай в их блоге, чтобы узнать, как установить свежий JDK в свою IDE.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8
Spring Boot tip:
Используй CommandLineRunner, если нужно выполнить код сразу после того, как приложение полностью поднялось и контекст инициализирован.
CommandLineRunner — это интерфейс Spring Boot, который позволяет запускать любую логику при старте приложения.
Удобно для:
заполнения базы начальными данными,
проверки состояния сервисов,
инициализации внешних ресурсов.
Пример:
Такой класс автоматически выполнится один раз при запуске Spring Boot.
👉 Java Portal
Используй CommandLineRunner, если нужно выполнить код сразу после того, как приложение полностью поднялось и контекст инициализирован.
CommandLineRunner — это интерфейс Spring Boot, который позволяет запускать любую логику при старте приложения.
Удобно для:
заполнения базы начальными данными,
проверки состояния сервисов,
инициализации внешних ресурсов.
Пример:
@Component
public class StartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("App started! Further setup");
}
}
Такой класс автоматически выполнится один раз при запуске Spring Boot.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Тебе не нужно дробить приложение на 20 репозиториев и 15 сервисов, чтобы получить модульность.
Это можно спокойно реализовать внутри грамотно спроектированного модульного монолита.
1. Разделяй модули по функциональным доменам.
Пример: пользователи, платежи, уведомления, отчёты.
Каждый модуль — это свой пакет со своими сущностями, сервисами и бизнес-логикой.
2. Определи чёткие интерфейсы между модулями.
Один модуль не должен знать внутренние классы другого.
Общай их через интерфейсы или внутренние события (например, Spring Events).
Так сохраняется слабое связывание и высокая связность.
3. Избегай циклических зависимостей.
Если модуль A зависит от B, убедись, что B никогда не зависит от A.
Разрывай такие циклы с помощью интерфейсов, dependency injection или событий.
4. Придерживайся принципа внутренних слоёв.
В каждом модуле разделяй внутренние части (entities, repositories, services) и то, что наружу (controllers, DTO, API).
5. Рассмотри использование Spring Modulith (для Java/Kotlin).
Он не заставляет переходить на микросервисы, но даёт инструменты для организации модулей, проверки зависимостей и документирования архитектуры.
6. Опционально: подумай о доменных событиях.
Они помогают масштабировать модульность, не ломая монолит.
И если потом решишь вынести модуль отдельно — половина работы уже сделана.
Модульность зависит не от размера системы, а от чёткости её границ.
Хорошо спроектированный модульный монолит может быть гораздо проще в поддержке, чем хаотичная сеть микросервисов.
👉 Java Portal
Это можно спокойно реализовать внутри грамотно спроектированного модульного монолита.
1. Разделяй модули по функциональным доменам.
Пример: пользователи, платежи, уведомления, отчёты.
Каждый модуль — это свой пакет со своими сущностями, сервисами и бизнес-логикой.
2. Определи чёткие интерфейсы между модулями.
Один модуль не должен знать внутренние классы другого.
Общай их через интерфейсы или внутренние события (например, Spring Events).
Так сохраняется слабое связывание и высокая связность.
3. Избегай циклических зависимостей.
Если модуль A зависит от B, убедись, что B никогда не зависит от A.
Разрывай такие циклы с помощью интерфейсов, dependency injection или событий.
4. Придерживайся принципа внутренних слоёв.
В каждом модуле разделяй внутренние части (entities, repositories, services) и то, что наружу (controllers, DTO, API).
5. Рассмотри использование Spring Modulith (для Java/Kotlin).
Он не заставляет переходить на микросервисы, но даёт инструменты для организации модулей, проверки зависимостей и документирования архитектуры.
6. Опционально: подумай о доменных событиях.
Они помогают масштабировать модульность, не ломая монолит.
И если потом решишь вынести модуль отдельно — половина работы уже сделана.
Модульность зависит не от размера системы, а от чёткости её границ.
Хорошо спроектированный модульный монолит может быть гораздо проще в поддержке, чем хаотичная сеть микросервисов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3
Совет по Spring Boot:
используй spring-boot-starter-logging (на Logback) для логирования — он уже подключён по умолчанию.
spring-boot-starter-logging уже включён во большинство стартеров, например spring-boot-starter-web, spring-boot-starter-data-jpa и т.д.
Можно настраивать уровни логирования, отредактировав application.yml:
Чтобы изменить формат логов и политику ротации, создай файл logback-spring.xml в каталоге src/main/resources.
👉 Java Portal
используй spring-boot-starter-logging (на Logback) для логирования — он уже подключён по умолчанию.
spring-boot-starter-logging уже включён во большинство стартеров, например spring-boot-starter-web, spring-boot-starter-data-jpa и т.д.
Можно настраивать уровни логирования, отредактировав application.yml:
logging:
level:
root: INFO
com.myapp: DEBUG
Чтобы изменить формат логов и политику ротации, создай файл logback-spring.xml в каталоге src/main/resources.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
This media is not supported in your browser
VIEW IN TELEGRAM
ChartDB это опенсорс-инструмент для работы с SQL-базами данных через визуальный интерфейс.
Что умеет:
✓ интерактивная диаграмма со всеми таблицами и связями
✓ можно скачать схему как PNG-картинку
✓ поддерживает MySQL, PostgreSQL, SQLite и другие
→ app.chartdb.io
👉 Java Portal
Что умеет:
✓ интерактивная диаграмма со всеми таблицами и связями
✓ можно скачать схему как PNG-картинку
✓ поддерживает MySQL, PostgreSQL, SQLite и другие
→ app.chartdb.io
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
Spring Boot: можно выполнять задачи через фиксированные интервалы без настройки Quartz или внешних планировщиков.
✅ Добавь
✅ Используй
👉 Java Portal
@EnableScheduling в любой конфигурационный или основной класс приложения:@SpringBootApplication
@EnableScheduling
public class MainApp { }
@Scheduled для метода:@Component
public class Scheduler {
@Scheduled(fixedRate = 5000)
public void executeTask() {
...
}
}
@EnableScheduling активирует механизм планирования, а @Scheduled задаёт частоту выполнения метода (fixedRate = 5000 — каждые 5 секунд).Please open Telegram to view this post
VIEW IN TELEGRAM
Держи сотни гигабайт свежих уроков, и каждую неделю мы подкидываем ещё!
• 1612 ГБ — DevOps
• 1402 ГБ — Python
• 1300 ГБ — C, C++
• 1815 ГБ — Frontend
• 1515 ГБ — Backend
• 898 ГБ — ИБ, Хакинг
• 996 ГБ — Kotlin, Swift
• 212 ГБ — JavaScript
• 315 ГБ — Flutter
• 820 ГБ — Go, PHP
• 419 ГБ — Java, Rust
• 648 ГБ — GameDev
• 517 ГБ — Windows, Linux
• 998 ГБ — Дизайн (UX/UI)
• 617 ГБ — Нейросети (ML/RL)
• 546 ГБ — БД (SQL & NoSQL)
• 687 ГБ — Аналитика данных
• 115 ГБ — QA-тестирование
Подписывайся и не плати за то, что можно получить бесплатно
Please open Telegram to view this post
VIEW IN TELEGRAM
У тебя есть 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
👍5