Тестовое собеседование №29 (Разбор)

Ссылка на видео:

Ответы на вопросы

Вопрос про OpenShift (что такое ingress, egress, sidecar)

    1. Что такое OpenShift?

    OpenShift — это Kubernetes-платформа от Red Hat с дополнительными функциями для управления жизненным циклом приложений. Она предоставляет разработчикам и DevOps-инженерам удобную среду для развертывания, масштабирования и управления контейнеризированными приложениями.

    Ключевые особенности:

    • Построен поверх Kubernetes
    • Встроенные CI/CD пайплайны (через Jenkins или Tekton)
    • Управление правами доступа (RBAC)
    • Поддержка шаблонов приложений (OpenShift Templates, Helm Charts)
    • Web UI и CLI (oc)

    Что такое Ingress?

    Ответ:
    Ingress — это объект Kubernetes (и OpenShift), который управляет входящим HTTP(S)-трафиком в кластер. Он определяет правила маршрутизации запросов к различным сервисам внутри кластера.

    Пример использования:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress
    spec:
      rules:
        - host: example.com
          http:
            paths:
              - path: /app
                pathType: Prefix
                backend:
                  service:
                    name: my-service
                    port:
                      number: 80

    Что такое Egress?

    Ответ:
    Egress — это термин, обозначающий исходящий трафик из подов наружу (в Интернет или другие внешние ресурсы). В OpenShift можно управлять Egress-трафиком, например, с помощью Egress firewall rules, Egress IPs, или NetworkPolicy, чтобы ограничить или разрешить доступ к внешним адресам.

    Что такое Sidecar?

    Ответ:
    Sidecar — это контейнер, запускаемый в одном поде вместе с основным приложением, дополняющий его функциональность. Это шаблон проектирования в Kubernetes, широко используемый для:

    • Логирования
    • Проксирования (например, Envoy в Istio)
    • Мониторинга (например, Prometheus exporters)
    • Кеширования

    Пример:
    В поде запускается ваше Java-приложение и рядом — sidecar-контейнер с Fluentd для логирования или Istio proxy для трассировки.

    Как обеспечить безопасность межсервисных обращений через Keycloak?

    Общий подход

    Чтобы сервисы безопасно вызывали друг друга, необходимо:

    • Аутентифицировать вызывающий сервис
    • Проверять токен на принимающей стороне
    • Гарантировать, что только авторизованные сервисы могут обращаться к нужным эндпоинтам

    Подход с Keycloak

    Шаги:

    Настройка Realm и Clients:

      • Создайте отдельный client для каждого сервиса (например, “service-a”, “service-b”) в режиме confidential.
      • Установите grant type: client credentials (для machine-to-machine общения).

      Выдача токена:

      • Сервис A получает токен от Keycloak через “POST /token” с client_id и client_secret.
      • Keycloak возвращает access token (чаще всего в формате JWT).

      Валидация токена:

        • Сервис B (принимающая сторона) проверяет:
          • подпись токена (если JWT)
          • срок действия (“exp”)
          • “aud” / “azp” (кому выдан токен)
          • роли/scopes (если есть)

        Передача токена:

          • В заголовке “Authorization: Bearer ” при каждом вызове между сервисами.

          Что такое JWT и Opaque токены?

          JWT (JSON Web Token)

          • Самодостаточный токен в формате JSON, закодированный и подписанный.
          • Содержит полезную нагрузку (claims), такую как “sub”, “exp”, “scope”, “roles”, “azp”.
          • Проверяется локально (нет запроса к Keycloak).
          • Пример:
          {
            "sub": "service-a",
            "azp": "service-a",
            "exp": 1716409999,
            "realm_access": {
              "roles": ["service-caller"]
            }
          }

          Плюсы:

          • Нет обращения к Keycloak при каждом запросе
          • Быстрая валидация

          Минусы:

          • Нельзя отозвать или немедленно отследить отключение (если нет отдельного механизма)

          Opaque token

          • Непрозрачный токен (обычно просто UUID), не содержит читаемой информации.
          • Требует обратного запроса к Keycloak для валидации через “/introspect” endpoint.

          Плюсы:

          • Лучше контроль — можно отозвать токен
          • Меньший риск утечки данных (в токене нет содержимого)

          Минусы:

          • Требует сетевого запроса к Keycloak при каждом вызове
          • Медленнее
          СценарийРекомендация
          Внутренние микросервисы, быстрые вызовыJWT (access token)
          Требуется высокая управляемость (отзыв)Opaque token + introspection
          Нужна трассировка и аудитJWT с scopes/roles

          Вопросы по Kafka, offset и offset lag

          Что такое Kafka?

          Kafka — это распределённая платформа потоковой передачи событий (event streaming platform), разработанная в LinkedIn и переданная Apache Foundation. Она используется для:

          • асинхронной коммуникации между микросервисами,
          • реалтайм-аналитики,
          • журнального хранения событий.

          Основные понятия

          Topic

          • Логическая категория/канал, куда публикуются события.
          • Подразумевается, что производители (producers) отправляют события в топик, а потребители (consumers) их читают.

          Partition

          • Топик разбивается на партиции — физические сегменты данных.
          • Каждая партиция — упорядоченный, неизменяемый лог событий.
          • Сообщения внутри партиции имеют offset — уникальный номер, по которому происходит чтение.

          Зачем нужны партиции?

          • Масштабируемость (горизонтальный шардинг)
          • Параллельное потребление (каждая партиция читается одним consumer’ом внутри consumer group)

          Consumer group

          • Группа потребителей, обрабатывающих события вместе.
          • Каждая партиция назначается ровно одному потребителю в группе.
          • Это означает: N consumers на максимум N партиций — не более.
          ПартицийConsumer’овЧто будет?
          33Идеально: 1 consumer на 1 партицию
          32Один consumer читает 2 партиции
          352 consumer’а будут “бездельничать”, т.к. лишние

          Как связаны партиции и количество consumer’ов?

          Число активных consumer’ов в группе не может быть больше числа партиций.

          Что такое Offset и Offset Lag?

          • Offset — позиция, до которой consumer прочитал сообщения.
          • Offset lag — количество непрочитанных сообщений (разница между последним offset’ом в партиции и тем, что прочитал consumer).

          Как бороться с Offset Lag?

          1. Увеличить число партиций
            Чтобы больше consumer’ов могли читать параллельно.
          2. Добавить consumer’ов
            Но не больше числа партиций!
          3. Убедиться, что обработка сообщений быстрая
            Узким местом может быть БД, внешние API и т.д.
          4. Масштабировать горизонтально
            — Распределить нагрузку по нескольким нодам.
          5. Использовать batch processing
            Вместо обработки по одному сообщению — пакетно (“max.poll.records”).
          6. Увеличить “fetch.min.bytes”, “max.poll.interval.ms”, “session.timeout.ms”
            Для оптимизации чтения и избежания ребалансинга.

          Сколько должно быть consumer’ов?

          • Максимум: = числу партиций
          • Обычно: = числу партиций или чуть меньше
          • Избыточное количество consumer’ов бесполезно — Kafka назначит одному consumer’у ноль партиций
          ВопросОтвет
          Kafka хранит сообщения?Да, по времени (retention.ms) или по объёму (retention.bytes)
          Kafka — очередь?Нет, это лог событий (event log), поддерживает pub/sub и replay
          Kafka масштабируется?Да, за счёт партиций и кластеров брокеров
          Нужно ACK от consumer’а?Да, Kafka фиксирует offset только после commit (авто или вручную)

          Нагрузочное тестирование

          Что такое нагрузочное тестирование (load testing)?

          Нагрузочное тестирование — это вид нефункционального тестирования, при котором проверяется, как система ведёт себя при ожидаемой и повышенной нагрузке. Цель — определить пределы производительности, задержки, стабильность и масштабируемость системы.

          Зачем нужно?

          • Проверить, выдержит ли система пик нагрузки
          • Найти узкие места (база данных, API, кэш)
          • Предотвратить сбои в проде
          • Определить, сколько пользователей или запросов система может обрабатывать

          Виды нагрузочного тестирования

          Вид тестаЦель
          Load TestingПроверка работы системы под нормальной и повышенной нагрузкой
          Stress TestingПроверка системы на пределе, чтобы увидеть, как она ломается
          Spike TestingПроверка резкого скачка нагрузки (внезапный наплыв трафика)
          Soak Testing (Endurance)Проверка системы под нагрузкой в течение долгого времени
          Scalability TestingОценка, насколько хорошо система масштабируется с ростом нагрузки

          Как проводится нагрузочное тестирование?

          Определение целей

            • Что мы хотим протестировать? (API, БД, UI, Kafka, Redis)
            • Какие метрики важны? (RPS, latency, CPU, memory)

            Настройка сценариев

              • Эмуляция пользовательского поведения (например, логин ? просмотр ? заказ)
              • Задание количества виртуальных пользователей, RPS

              Выбор инструментов

                • JMeter (графический интерфейс, скрипты)
                • Gatling (Scala/Java, кодогенерация)
                • k6 (JavaScript-подход, CI-friendly)
                • Locust (Python-скрипты)
                • Artillery, Tsung, Vegeta, wrk — для CLI/микросервисов

                Запуск теста

                  • Локально, в CI или через Kubernetes
                  • Снятие метрик (Prometheus, Grafana, Zipkin, OpenTelemetry)

                  Анализ результатов

                    • Важные метрики:
                    • Response Time (P50, P95, P99)
                    • Throughput (RPS)
                    • Error rate
                    • CPU, Memory, Disk I/O
                    • Kafka lag, Redis latency

                    Оптимизация

                      • Балансировка нагрузки
                      • Кэширование
                      • Оптимизация SQL-запросов
                      • Увеличение партиций в Kafka
                      • Горизонтальное масштабирование

                      Пример из практики

                      API обрабатывает 300 RPS, при 500 RPS растёт latency до 3 сек, CPU 100% ? узкое место — синхронные DB-запросы ? решение: кэширование + асинхронная очередь (Kafka).

                      Общие вопросы о JDK 11, 17, 21

                      Какие релизы JDK являются LTS?

                        Ответ:

                        • Java 11 — LTS (вышел в 2018)
                        • Java 17 — LTS (вышел в 2021)
                        • Java 21 — LTS (вышел в 2023)

                        JDK 11 — ключевые нововведения

                        Что нового в JDK 11?

                        • “var” разрешён в лямбда-параметрах
                        • Новый HTTP Client (стабилен, из incubator в JDK 9)
                        • “String” API: “isBlank()”, “lines()”, “strip()”, “repeat()”
                        • “Files.readString()” / “Files.writeString()”
                        • Удаление модулей (JavaFX, CORBA, WebStart)

                        Что такое ZGC и появился ли он в JDK 11?

                        Ответ: Да. ZGC — экспериментальный низколатентный сборщик мусора для больших heap (до терабайтов), с паузами <10 мс.

                        JDK 17 — основные изменения

                        Какие новые возможности добавлены в Java 17?

                        • Sealed classes (final для наследования):
                          public sealed class Shape permits Circle, Square {}
                        • Pattern matching for switch (preview) — упрощение “switch” по типам
                        • New “record” enhancements
                        • Новый GC: G1 улучшен, ZGC стабилизирован
                        • Удаление RMI Activation, Applet API, Security Manager (deprecate)
                        • JEP 356: Enhanced Pseudo-Random Number Generators

                        JDK 21 — нововведения и стабилизации

                        Что было стабилизировано в JDK 21?

                        • Virtual Threads (JEP 444) — масштабируемые lightweight-потоки
                        • Pattern Matching for “switch” (JEP 441) — полная поддержка
                        • Record Patterns (JEP 440) — распаковка вложенных структур
                        • Sequenced Collections (JEP 431) — “SequencedSet”, “SequencedMap” — предсказуемый порядок элементов

                        Что такое virtual threads?

                        • Это user-mode потоки (на “java.lang.Thread”), исполняемые в ForkJoinPool
                        • Облегчают реализацию конкурентных REST-сервисов без использования Reactive stack

                        Чем отличаются платформенные потоки от виртуальных?

                        Платформенный потокВиртуальный поток
                        УправляетсяОС (kernel thread)JVM (user thread)
                        ВесТяжёлыйЛёгкий (~few KB stack)
                        Кол-во одновременноОграниченоСотни тысяч возможно

                        Как использовать виртуальные потоки с “ExecutorService”?

                        var executor = Executors.newVirtualThreadPerTaskExecutor();
                        executor.submit(() -> System.out.println("Hello from virtual thread"));

                        Какие GC появились или стабилизированы?

                        • ZGC: Java 11 — experimental, Java 15+ — стабильный
                        • Shenandoah: С JDK 17 — включён по умолчанию в некоторых билдах
                        • G1: Постоянно оптимизируется, остаётся дефолтным

                        Виртуальные потоки в Java

                        Что такое виртуальные потоки?

                        Virtual threads (JEP 444, Java 21) — это легковесные потоки, управляемые JVM, а не операционной системой. Они позволяют запускать миллионы конкурентных задач без перегрузки системы.

                        • Создаются быстро
                        • Имеют низкие накладные расходы
                        • Идеальны для I/O-bound задач (например, HTTP-запросов, JDBC)

                        Почему это важно для HTTP?

                        Обычные (платформенные) потоки ограничивают масштабируемость сервера:

                        • У Tomcat, Jetty и других серверов есть thread pool — обычно ограниченный (~200 потоков)
                        • Если каждый HTTP-запрос блокирует поток (ожидая БД, стороннего API), то масштаб ограничен

                        Виртуальные потоки снимают это ограничение: можно обрабатывать десятки тысяч запросов, даже если каждый из них блокирующий.

                        Можно ли использовать виртуальные потоки с Tomcat?

                        По умолчанию — нет.

                        Apache Tomcat (даже 10.1+) работает на платформенных потоках. Он использует “ExecutorService”, в котором работают обычные “java.lang.Thread”.

                        Можно — через кастомный “Executor”

                        Начиная с Java 21, можно внедрить виртуальные потоки вручную:

                        Executor executor = Executors.newVirtualThreadPerTaskExecutor();
                        Connector connector = new Connector();
                        connector.getProtocolHandler().setExecutor(executor);

                        Но:

                        • Tomcat неофициально поддерживает virtual threads
                        • Не всё совместимо (некоторые filters/servlets могут быть не thread-safe)
                        • Поддержка может появиться официально позднее (обсуждается в Apache Tomcat mailing list)

                        Где лучше применять Virtual Threads уже сейчас?

                        1. Spring Boot 3 + Undertow/Jetty: легче внедрить виртуальные потоки
                        2. Micronaut / Helidon Nima / Quarkus Loom: экспериментальная или полноценная поддержка
                        3. Самописные HTTP-серверы с “HttpServer” из JDK:
                        HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
                        server.createContext("/", exchange -> {
                            Thread.startVirtualThread(() -> {
                                // Обработка запроса
                                exchange.sendResponseHeaders(200, 0);
                                exchange.getResponseBody().write("Hello".getBytes());
                            });
                        });

                        Пример: Spring Boot + Virtual Threads (на Undertow)

                        @Bean
                        public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> virtualThreadCustomizer() {
                            return factory -> {
                                if (factory instanceof UndertowServletWebServerFactory undertow) {
                                    undertow.addBuilderCustomizers(builder ->
                                        builder.setWorkerThreads(100_000) // Нереально много, т.к. это виртуальные потоки
                                    );
                                }
                            };
                        }

                        И включить в “application.yml”:

                        server:
                          undertow:
                            threads:
                              worker: 100000

                        Вывод

                        Платформенные потокиВиртуальные потоки
                        Уровень управленияОС (kernel threads)JVM (user-mode threads)
                        Задержки на I/OБлокируют потокНе блокируют ресурсы
                        Масштабируемость~1000 потоков~1 000 000+
                        Поддержка в TomcatНет (только вручную)Экспериментально
                        Поддержка в NettyНет (лучше использовать reactive)

                        Вопросы по многопоточности и executorservice ам

                        Базовые вопросы

                        Что такое поток в Java?

                        Ответ:
                        Поток (thread) — это наименьшая единица исполнения в программе. В Java каждый поток реализуется через “java.lang.Thread” и выполняется независимо от других потоков.

                        Как создать и запустить поток?

                        Ответ:

                        Thread thread = new Thread(() -> System.out.println("Hello"));
                        thread.start();

                        Что такое race condition?

                        Ответ:
                        Ситуация, когда два потока обращаются к одной переменной и порядок их выполнения влияет на результат. Решается через синхронизацию (“synchronized”, “Lock”, атомарные переменные).

                        Какие проблемы решает “ExecutorService”?

                        Ответ:

                        • Повторное использование потоков (thread pooling)
                        • Управление количеством потоков
                        • Планирование и контроль задач
                        • Асинхронное выполнение с получением результата (“Future”, “CompletableFuture”)

                        Что такое “ExecutorService”?

                        Ответ:
                        Интерфейс из “java.util.concurrent”, представляющий пул потоков и методы для отправки задач (“submit”, “execute”, “invokeAll”, “shutdown” и др.).

                        Чем отличаются “execute()” и “submit()”?

                        МетодВозвращаетОбработка ошибок
                        execute(Runnable)voidИсключения могут потеряться
                        submit(Runnable)Future<?>Можно обработать результат и исключения

                        Что делает “shutdown()” и “shutdownNow()”?

                        • “shutdown()” — инициирует корректное завершение, не принимает новые задачи, завершает текущие.
                        • “shutdownNow()” — прерывает текущие потоки, возвращает список задач, которые не начали выполнение.

                        Как реализовать пул из 10 потоков?

                        ExecutorService executor = Executors.newFixedThreadPool(10);

                        Как получить результат выполнения задачи?

                        Future<Integer> future = executor.submit(() -> 1 + 1);
                        Integer result = future.get(); // блокирующий вызов

                        Что такое “Callable”?

                        Интерфейс, аналогичный “Runnable”, но:

                        • Возвращает значение
                        • Может выбрасывать checked-исключения

                        Чем отличается “Future” от “CompletableFuture”?

                        “Future”“CompletableFuture”
                        Асинхронный APIНетДа (“thenApply”, “thenCompose”)
                        Блокирующий “get()”ДаМожно избежать
                        Комбинирование задачНетДа

                        Как работают виртуальные потоки с “ExecutorService”?

                        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
                        executor.submit(() -> {
                            // lightweight thread
                        });

                        Как избежать “ThreadPoolExecutor” saturation?

                        • Ограничить очередь (например, “ArrayBlockingQueue”)
                        • Добавить RejectedExecutionHandler
                        • Мониторить метрики (“activeCount”, “queueSize”)

                        Какие есть типы пулов в “Executors”?

                        МетодОписание
                        newFixedThreadPool(n)Постоянное число потоков
                        newCachedThreadPool()Динамический пул, без ограничений
                        newSingleThreadExecutor()Один поток — все задачи последовательно
                        newScheduledThreadPool(n)Запуск по таймеру
                        Executors.newVirtualThreadPerTaskExecutor()Virtual threads (Java 21+)

                        Практические вопросы распределенным системам

                        Как приложение на Spring Boot валидирует Access Token, выданный Keycloak?

                          JWT Access Token (по умолчанию в Keycloak)

                          Spring Boot валидирует JWT локально, без запроса в Keycloak.

                          Механизм:

                          1. Токен приходит в заголовке “Authorization: Bearer “
                          2. Spring Security (через “OAuth2ResourceServer”) извлекает токен
                          3. Проводится проверка подписи с использованием публичного ключа из Keycloak (“/realms/{realm-name}/protocol/openid-connect/certs”)
                          4. Проверяются:
                          • “exp” — срок действия
                          • “aud”, “iss” — валидность источника
                          • “scope”, “roles”, “permissions”

                          Конфигурация:

                          spring:
                            security:
                              oauth2:
                                resourceserver:
                                  jwt:
                                    issuer-uri: https://keycloak.example.com/realms/myrealm

                          Альтернатива — opaque token:

                          • Валидация через introspection endpoint
                          • Нужно “POST”-запрос к Keycloak: “/protocol/openid-connect/token/introspect”
                          • Медленнее, но управляемее

                          Почему чтение из RAM быстрее, чем из SSD?

                            Причина: уровни иерархии памяти

                            УровеньПримерСкорость доступа
                            Регистры CPU~1 наносекунда
                            Кэш L1/L2/L3CPU-кэш1–10 наносекунд
                            Оперативная память (RAM)DDR4/DDR5~100 наносекунд
                            SSD (NVMe)Samsung 980 Pro~100 микросекунд
                            HDD~5–10 миллисекунд

                            Почему так:

                            • RAM — энергозависимая и адресуется напрямую
                            • SSD — работает через контроллер, поддерживает I/O очереди, требует больше операций (чтение страниц, wear leveling, garbage collection)

                            Пример:
                            Чтение из RAM — прямой доступ по адресу
                            Чтение с SSD — обращение к файловой системе, драйверу, контроллеру

                            Что такое партиционирование в БД?

                              Определение:

                              Партиционирование — это разбиение таблицы на несколько частей (partition) по заданному критерию (например, по дате, ID, региону).

                              Цель:

                              • Ускорить поиск и агрегацию
                              • Ограничить область данных для запросов
                              • Улучшить масштабируемость и управляемость

                              Виды партиционирования:

                              ТипПримерПодходит для
                              RangeWHERE date >= '2023-01-01'Временные данные
                              Listregion IN ('RU', 'US')Разные регионы
                              Hashid % NРавномерное распределение
                              Compositedate + regionКомбинация стратегий

                              Пример в PostgreSQL:

                              CREATE TABLE orders (
                                id SERIAL,
                                region TEXT,
                                created_at DATE
                              ) PARTITION BY RANGE (created_at);
                              
                              CREATE TABLE orders_2023 PARTITION OF orders
                                FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');

                              Преимущества:

                              • Query pruning — оптимизатор сам выбирает нужную партицию
                              • Меньше индексов на каждую часть
                              • Упрощённое удаление старых данных (удаляется партиция)

                              Документирование API

                              Документирование API — важная часть разработки, особенно в микросервисной архитектуре. Ниже — краткий и структурированный гайд по способам документирования REST API, подходящий для собеседования Java-разработчика:

                              Цели документации API

                                • Упростить использование API другими командами и клиентами
                                • Обеспечить прозрачность контрактов
                                • Облегчить тестирование и интеграцию
                                • Поддерживать единый формат и описание версий

                                Основные подходы

                                  a. OpenAPI / Swagger (де-факто стандарт)

                                  • YAML/JSON спецификация, описывающая эндпоинты, методы, параметры, модели
                                  • Используется для генерации:
                                  • Документации (Swagger UI)
                                  • Клиентов (OpenAPI Generator)
                                  • Серверных заглушек

                                  Инструменты:

                                  • Springdoc OpenAPI (“springdoc-openapi-ui”)
                                  • Swagger-Core (ручная аннотация)
                                  • Stoplight, Redocly (для ручной редакции и визуализации)

                                  Пример аннотаций с Spring Boot:

                                  @Operation(summary = "Получить заказ по ID")
                                  @GetMapping("/orders/{id}")
                                  public OrderDto getOrder(@PathVariable Long id) { ... }

                                  b. Javadoc для внутренних API

                                  • Подходит для SDK, client-libraries
                                  • Используется “/ … */” над методами и классами
                                  • Генерируется через “javadoc” CLI или IDE

                                  c. Asciidoc / Markdown + REST Docs

                                  • Позволяет писать документацию вручную или полуавтоматически
                                  • Spring REST Docs генерирует snippets из интеграционных тестов

                                  Инструменты и стек

                                    НазваниеНазначение
                                    Swagger UIИнтерфейс для просмотра и тестирования API
                                    springdoc-openapiГенерация OpenAPI из кода Spring Boot
                                    Postman / InsomniaПросмотр и экспорт коллекций API
                                    Spring REST DocsГенерация документации на основе тестов
                                    RedocСовременная визуализация OpenAPI-доков
                                    Stoplight StudioРедактор OpenAPI

                                    Хорошая документация включает:

                                      • Описание каждого эндпоинта (метод, URL, описание)
                                      • Параметры запроса, заголовки, тело
                                      • Формат ответа (с примерами)
                                      • Ошибки и коды статусов
                                      • Безопасность (auth, scopes)
                                      • Примеры cURL / HTTP-запросов

                                      Советы

                                      • Храните “openapi.yaml” в репозитории рядом с кодом
                                      • Включайте документацию в CI
                                      • Для публичных API — публикуйте с Redoc или SwaggerHub
                                      • Поддерживайте версионирование API (“/v1/”, “/v2/”)

                                      Различия между системами сборки Maven и Gradle

                                      Maven vs Gradle: ключевые различия

                                      КритерийMavenGradle
                                      Язык конфигурацииXML (pom.xml)Groovy или Kotlin DSL (build.gradle, build.gradle.kts)
                                      Скорость сборкиМедленнее (особенно при больших проектах)Быстрее благодаря incremental build и daemon
                                      ГибкостьОграниченная, строгое дерево фазОчень гибкий, можно писать произвольную логику сборки
                                      Структура сборкиСтандартная и предсказуемаяБолее гибкая, но требует дисциплины
                                      Инструменты и плагиныОгромное количество плагиновБогатый набор, легко пишутся кастомные плагины
                                      ДекларативностьПолностью декларативныйПоддерживает декларативный и императивный подход
                                      КэшированиеНетЕсть (в том числе remote build cache)
                                      ЗависимостиОпределяются через <dependency>Определяются как implementation 'group:artifact:version'
                                      Интеграция с IDEОтличная (особенно с IntelliJ)Также отличная, но иногда нужна ручная настройка
                                      Test lifecycleЖёстко заданная модель фаз (compile, test, package и т.д.)Можно задавать произвольные таски и зависимости
                                      МногомодульностьПоддерживается, но может быть громоздкойЛегче реализуется, особенно для больших проектов

                                      Maven — когда использовать?

                                      Выбираем Maven, если:

                                      • Требуется стабильность и читаемость конфигурации
                                      • Проект простой или стандартный
                                      • Команда уже привыкла к Maven
                                      • Не нужно кастомных шагов сборки

                                      Gradle — когда использовать?

                                      Выбираем Gradle, если:

                                      • Большой монорепозиторий или сложные зависимости
                                      • Нужна высокая производительность сборки
                                      • Много кастомных шагов и скриптов
                                      • Используется Kotlin DSL (например, в Android проектах)

                                      Рекомендованная литература и статьи:

                                      Java и многопоточность

                                      1. “Java Concurrency in Practice” — Brian Goetz

                                      Фундаментальная книга по потокам, ExecutorService, synchronized, volatile, и многопоточному проектированию.

                                      1. “Modern Java in Action” — Raoul-Gabriel Urma

                                      Покрывает лямбды, стримы, CompletableFuture, virtual threads (в последних изданиях).

                                      1. “Effective Java” (3rd edition) — Joshua Bloch

                                      Паттерны и лучшие практики, включая работу с потоками, коллекциями и API-дизайном.

                                      Spring Boot и безопасность

                                      1. “Spring Security in Action” — Laurentiu Spilca

                                      Полное руководство по настройке OAuth2, JWT, ресурсных серверов, интеграции с Keycloak.

                                      1. “Spring Boot: Up and Running” — Mark Heckler

                                      Введение и практика, включая REST, WebFlux, Actuator, Docker.

                                      Kafka и распределённые системы

                                      1. “Kafka: The Definitive Guide” — Neha Narkhede

                                      Практика Kafka, топики, партиции, offset lag, продюсеры и консьюмер-группы.

                                      1. “Designing Data-Intensive Applications” — Martin Kleppmann

                                      MUST READ: транзакции, репликация, шардирование, потоковые системы.

                                      Документирование и архитектура API

                                      1. “RESTful Web APIs” — Leonard Richardson

                                      Архитектурные подходы, HATEOAS, версионирование, контракты и статус-коды.

                                      1. “API Design Patterns” — JJ Geewax (Google)

                                      Подробности по REST, GraphQL, OpenAPI, и практикам построения устойчивых API.

                                      Системные знания и DevOps

                                      1. “The Linux Command Line” — William E. Shotts Основы работы с Linux, процессы, память, системные вызовы.
                                      2. “Kubernetes in Action” / “OpenShift in Action” Для понимания кластеров, ingress/egress, sidecar, CI/CD, и сервисов.

                                      Статьи и официальные источники

                                      OpenAPI и документация:

                                      Keycloak:

                                      Virtual Threads:

                                      Java 11–21:

                                      Kafka:

                                      Нагрузочное тестирование:

                                      Loading