Software Engineering - Евгений Сулейманов
3.14K subscribers
178 photos
3 videos
4 files
132 links
По вопросам писать в ЛС:
@proselyte
Download Telegram
Друзья, 26-й еженедельный квиз по распределенным системам.

❗️❗️❗️Задача❗️❗️❗️
Transactional Outbox и его виды: как обеспечить порядок, идемпотентность и масштабирование на шардированной БД

Сценарий:
Сервис Billing принимает REST-запросы на списания/возвраты. Данные хранятся в PostgreSQL, шардированной по tenant_id (Shard-A, Shard-B). После успешной записи транзакции в БД нужно публиковать доменные события ChargeCreated/RefundCreated в Kafka для downstream-сервисов (anti-fraud, уведомления, аналитика).

Требования:
- Порядок по агрегату ("accountId"): события одного аккаунта должны приходить строго последовательно.
- Идемпотентность: возможны рестарты релея/коннектора; дубликаты недопустимы на уровне эффекта у консьюмера.
- Минимальная нагрузка на OLTP: поток до 30k msg/s суммарно по шардам.
- Zero-downtime при добавлении 3-го шарда в будущем (расширение без пересборки пайплайна).

Проблема:
- Dual-write окно: запись в БД закоммитилась, а публикация в Kafka могла не произойти.
- Реордеринг: poller, читающий created_at/id, не гарантирует commit-order под длинными транзакциями, особенно между шардами.
- Горячие партиции Kafka при неправильном ключе и высокая вероятность дублей при ретраях.
- Операционная сложность: нужно масштабировать релей, удерживая порядок по accountId и не перегружая основной кластер БД.

Вопрос:
Какой вариант Transactional Outbox выбрать и как его спроектировать, чтобы выполнить требования (порядок по "accountId", идемпотентность, низкая нагрузка на OLTP, расширение до 3-го шарда без даунтайма)?

Варианты решения:
A) Глобальный poller поверх единой outbox-таблицы (через FDW объединяем Shard-A/B во “view”): SELECT … FOR UPDATE SKIP LOCKED ORDER BY created_at, публикуем в Kafka; при добавлении 3-го шарда подключаем его к тому же view.
B) Per-shard Transactional Outbox + Debezium Outbox SMT (CDC) + EOS в Kafka Connect.
C) Inline publish: в том же @Transactional методе после INSERT в доменную таблицу сразу отправляем в Kafka (idempotent producer), на случай сбоя - ретраи/алерт.
D) XA/2PC между PostgreSQL и Kafka: записываем доменные данные и отправляем в Kafka в одной распределенной транзакции; координатор - сторонний TM.

#proselyte_sysdesign_quiz
👍94👀2🔥1🤯1🤩1
Друзья, всем добрый день!
Сегодня в 16:00 буду проводить мок интервью с кандидатом Максимом (@Maxim_S4).
Максим - опытный backend инженер c более чем 6 годами опыта, который специализируется на энтерпрайз разработке.

Пожелаем ему удачи 🚀

P.S.: запись планирую опубликовать в начале следующей недели.
🔥122👍2515🤝2🥴1
Software Engineering - Евгений Сулейманов
Друзья, 26-й еженедельный квиз по распределенным системам. ❗️❗️❗️Задача❗️❗️❗️ Transactional Outbox и его виды: как обеспечить порядок, идемпотентность и масштабирование на шардированной БД Сценарий: Сервис Billing принимает REST-запросы на списания/возвраты.…
Правильный ответ: B - Per-shard Transactional Outbox + Debezium Outbox SMT (CDC) + EOS в Kafka Connect.

Почему:
- Атомарность на write-path каждого шарда. Доменная запись и outbox-строка фиксируются одной локальной транзакцией на соответствующем шарде -> нет dual-write окна.
- Порядок по агрегату (`accountId`). Debezium читает commit-order из WAL каждого шарда; ключ Kafka = tenantId:accountId -> все события аккаунта попадают в одну партицию, приходят последовательно.
- Идемпотентность сквозь ретраи. eventId`/`aggregate_version в outbox + идемпотентный продюсер/Exactly-Once в Kafka Connect (EOS) + дедуп у потребителей -> нет двойных эффектов.
- Низкая нагрузка на OLTP. CDC читает журнал транзакций, а не делает SELECT-сканирование; outbox секционируется (по времени/tenant) + TTL/cleanup -> дешевое сопровождение.
- Масштабирование и добавление шарда без даунтайма. Добавили Shard-C -> деплой нового Debezium-коннектора, указываем только его outbox-таблицу; остальной конвейер не трогаем.

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

- A (глобальный poller по объединенному view). Несохранение commit-order (по created_at легко "плывет" под длинными транзакциями), блокировки/IO (`SELECT … FOR UPDATE SKIP LOCKED`), единая точка отказа/бутылочное горлышко, лишняя нагрузка на OLTP, сложный failover.
- C (inline publish после коммита). Классическое dual-write окно: БД уже зафиксирована, Kafka может быть недоступна -> рассинхрон; ретраи плодят дубли; нарушаются latency/SLO критического пути.
- D (XA/2PC БД+Kafka). Kafka не XA-ресурс, 2PC резко усложняет систему и снижает доступность/пропускную способность; в проде не применяется для этой задачи.

Что важно учесть (реализация B):

- Схема outbox (на каждом шарде): event_id (UUID, PK, UNIQUE), tenant_id, account_id, aggregate_type, aggregate_version, event_type, payload, headers, created_at. Секционирование по времени/tenant.
- Debezium/Connect (на шард): включить Outbox Event Router SMT (unwrap payload, route by event_type`), ключ Kafka = `tenantId:accountId; включить Exactly-Once Support у Connect; настроить backpressure.
- Kafka: продюсер/коннектор с идемпотентностью; партиционирование по ключу (`tenantId:accountId`) для порядка; разумный ретеншн/compaction для событий с версиями.
- Потребители: идемпотентная обработка (дедуп по `eventId`/`aggregate_version`), мониторинг лагов, DLQ на неразбираемые события.
- Операции: TTL/cleanup outbox, метрики хвоста/лагов, алерты на рассинхрон (счетчики per-shard).

Что почитать:
- Transactional Outbox - надежная передача событий между сервисами.
- Debezium Outbox Event Router.
- Exactly-Once Semantics Are Possible: Here’s How Kafka Does It
- Designing Data-Intensive Applications (Kleppmann): журналы изменений, CDC, порядки и ключи.
🔥161
Друзья, всем привет!
Сегодня в 13:00 буду проводить мок интервью с кандидатом Азизом (@alibaba228999).
Азиз - начинающий разработчик, студент 3 курса с 2х летним опытом работы.
Пожелаем ему удачи 🚀

P.S.: запись прошлого собеседования на монтаже, на этой неделе планирую публикацю 🙂
🔥53❤‍🔥61
Недавно скинули вот такую историю из канала Kubernetes и кот Лихачева про 404, service mesh и фоновые джобы. Интересно, как большинство в обсуждениях сразу уходит в две темы:
- "кривой Kubernetes / mesh / балансировщики"
- "неправильные ретраи и таймауты"

Лично мне видится здесь несолько иное:
- Размытая семантика контрактов - 404 как "и не ошибка, и не норма" неизбежно приводит к экспоненциальным ретраям и хаосу.
- Слишком сложная внутренняя маршрутизация без нормальной observability: нет единой картины пути запроса - нет и быстрого дебага.
- Архитектурный долг инфраструктуры: когда mesh, прокси и правила маршрутизации живут в головах пары людей, любая мелкая правка превращается в производственный квест.

Пока команда обсуждает "а давайте ещё подкрутим ретраи", система мстит за годы накопленного архитектурного и инфраструктурного долга. Именно поэтому мне крайне импонирует идея прозрачных контрактов, трассировка end-to-end и документация маршрутизации - без этого любая такая история превращается не в инцидент, а в детектив на несколько дней.

Какие мысли у сообщества?
👍97🔥4💯2
Друзья, новая публикация о кэшировании для backend-разработчика.

В статье разбираем:
- как кэшировать API и HTML-документы,
- как настроить заголовки в контроллерах,
- как использовать Spring Cache с Redis или Caffeine,
- как не "убить" hit rate из-за "Vary: Cookie".

Ссылка на публикацию:
Основы кэширования для backend-разработчика

Дополнение - Основы Redis
🔥5526👍10❤‍🔥1🥴1
Новая публикация о том, как мы проверяем JWT, выданный Keycloak.

Многие имеют опыт работы с Keycloak, но иногда до конца не понимают, что именно происходит, когда бэкенд видит Authorization: Bearer <jwt> - и почему ему не нужны ни секретный ключ, ни поход в Keycloak на каждый запрос.

В данной статье, разбираем:
- как устроен JWT побайтно: header.payload.signature и RS256;
- как Spring Boot валидирует токен по публичному ключу из JWKS, не дергая Keycloak;
- что именно проверяется в claims: exp, iss, aud/azp, typ;
- access vs refresh token и зачем вообще нужен refresh flow;
- как роли из Keycloak превращаются в GrantedAuthority и почему из-за них вы получаете 403 на /admin;
- пример конфигурации Spring Security и куски кода без магии адаптеров.

Ссылка на статью:
Валидация JWT-токена в Spring Boot с Keycloak

Ссылка на видео по основам Keycloak
Основы Keycloak
🔥6716
Друзья, нас уже более 3000.
Большое спасибо за вашу поддержку
🙏
146🔥66🍾17🎉11👍4❤‍🔥2
Друзья, искренне рекомендую к просмотру, получилось крайне живое общение на подкасте с Spring АйО.
Forwarded from Spring АйО
Media is too big
VIEW IN TELEGRAM
🍃 Spring Boot 4, версионирование API и инженерная культура | Spring АйО подкаст №43

😉 СМОТРЕТЬ НА YOUTUBE
😄 СМОТРЕТЬ В VK ВИДЕО
🥰 СМОТРЕТЬ НА RUTUBE
🗯 СЛУШАТЬ НА ЯНДЕКС МУЗЫКЕ
🤩 СЛУШАТЬ НА SPOTIFY
🤩 СЛУШАТЬ НА APPLE PODCASTS

💬 Аудио версию подкаста можно найти в комментариях
Please open Telegram to view this post
VIEW IN TELEGRAM
👍29🔥259
Новая публикация по Hibernate/Spring Data и кэш: как он работает и какие сложности возникают.

В данной статье разбираем:

Зачем вообще кэш в Hibernate и чем отличаются:
- L1 (session / persistence context)
- L2 (shared между сессиями, Ehcache)
- Query cache (и почему он почти всегда неправильно используется)

Как работает L1/L2 под капотом: стратегии "READ_ONLY / READ_WRITE / NONSTRICT_READ_WRITE"

EHCache как L2:
- конфигурация (XML + через код), регионы, TTL, eviction
- где он действительно дает выигрыш, а где только усложняет жизнь

Работа в кластере:
- чем локальный L2 на каждом узле опасен
- почему "пусть каждый инстанс сам кэширует" - не стратегия

Redis как внешний кэш:
- когда он действительно нужен
- почему "всегда воткнуть Redis" - плохое архитектурное решение
- что теряем по латентности и сложности инфраструктуры

Практические рекомендации:
- когда L2 включать
- когда от него отказаться
- где лучше использовать Spring Cache/Redis.

Ссылка на статью:
Кэширование в Hibernate и Spring Data: уровни, EHCache, Redis и лучшие практики
🔥66🤓5❤‍🔥32🤔2
Мнение:

На рынке ИТ сейчас ситуация в пользу нанимателя.

Сокращения - это реальность: сотни тысяч уволенных по всему миру за 2024–2025 годы, и волна увольнений еще не завершена.

При этом интересный момент: по долгосрочным прогнозам спрос на разработчиков все равно будет расти. То есть индустрия не "умирает" - она перестраивается. И выживают в ней не "джуны с опытом 5 раз по году", а те, кто работают шире, чем просто писать код по ТЗ.

Кто остается после волн сокращений

По моим наблюдениям - по тому, что вижу в проектах и на собеседованиях, остаются в первую очередь люди, которые:
- умеют не только в Java/Go/TypeScript, но понимают архитектуру: где границы сервисов, какие компромиссы по консистентности, как систему потом эксплуатировать;
- не боятся DevOps-части: деплой, CI/CD, контейнеры, базовая работа с k8s/облаком;
- нормально относятся к тестированию - умеют строить хотя бы вменяемый набор авто-тестов и не воспринимают это как "чужую работу";
- мыслят системно: от бизнес-требований и NFR (надежность, производительность, безопасность) до конкретных решений в коде.

То есть ценятся люди с T-shaped профилем: глубокая экспертиза в своем стеке + достаточная ширина по смежным областям (архитектура, инфраструктура, тесты, observability). И чем дальше, тем жестче будет фильтр именно по такому профилю.

Самый опасный сценарий сейчас

Соблазн понятный:
работа есть, зарплата есть - "можно пару лет ничего особо серьезного не учить".

Проблема в том, что:
- рынок уже насытили людьми из волн сокращений 2022–2025;
- компании все чаще смотрят не на "количество лет опыта", а на набор актуальных навыков и способность закрывать несколько ролей.

В такой ситуации остановиться в точке "я просто пишу бэк на X и мне норм" - это тихий путь в тот самый слой "лишних", которых срезают первыми.

Что можно делать прямо сейчас

1. Углубить базу по своему стеку
Не "еще один фреймворк", а: многопоточность, работа с памятью, профилирование, паттерны, продвинутые возможности языка.

2. Добавить один соседний слой
Если вы чистый бэкендер - подтянуть CI/CD, контейнеризацию, базовый k8s/облако.

3. Сделать свой проект чуть более наблюдаемым
Научиться настраивать метрики, логи, алерты для своих сервисов и реально смотреть, как они живут в проде.

4. Научиться мыслить за рамками Jira задач
Не только "как запилить фичу", но:
- как это будет тестироваться;
- как это будет масштабироваться;
- как это будет падать и подниматься.

5. Регулярность > героизм

Не спринт "прочитать 5 книжек за месяц", а спокойный режим в котором обучение это часть рутины. Буквально 3-5 часов изучения в неделю на отрезке в 3 года дают существенный результат.

Мои ощущения
Конкуренция за линейные позиции будет только расти.

Что делать?
Примерный план обучения, который я рекомендую на основе личного опыта:

План развития backend разработчика

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

А вы как это видите текущую ситуацию? Есть ли ощущение, что рынок стал намного жестче?
🔥8830👍15😭4🤔3💯31
❗️❗️❗️Друзья, набор на Январь❗️❗️❗️

Детали 8-недельного интенсива "НашКод".
- Без громких обещаний.
- Просто - структурная, честная и тяжелая работа.

Кому подойдёт
- Тем, кто уже знаком с промышленным Java-стеком
- Тем, кто работает, но чувствует, что "упёрся в потолок"
- Тем, кто "вошёл в IT" - но не знает, куда теперь двигаться

Чего не будет
- "Серебряной пули"
- Конкурсов и геймификации
- Весёлых презентаций и розовых лимузинов
- Панибратства и «сеньора за 30 дней»
- Иллюзии, что можно "пересидеть" развитие

Что будет
- Моё видение - основанное на годах работы в реальной разработке
- Индивидуальный подход (я искренне верю, обучение инженеров нельзя просто "поставить на поток")
- Проект, в котором мы будем кодить (много кодить), править и обсуждать - как в команде
- Много кода, много ревью, много правок

Как всё устроено
- Только 6 человек в группе - никаких исключений (чтобы качественно уделить время каждому - вопросы, код ревью и т.д.)
- Старт: ~ 12 Января 2026
- Формат: раз в неделю мини-лекция + живая сессия + уходим на самостоятельную работу и общение в мини-чате, дз сдаем в фоновом режиме индивидуально
- Учебный проект: микросервисы, архитектура, тесты, документация, нагрузка - "вот это вот всё вот это"
- Платно

Как попасть
Более детально ознакомьтесь с условиями и заполните форму по ССЫЛКЕ.
Вопросы также можно задать в ЛС.
Ключевые выводы по предыдущим группам: СООБЩЕНИЕ
🔥265👌2
Новая публикация по версионированию REST API в Spring Boot.

В статье разбираем:
- зачем вообще версионировать API
- какие подходы бывают
- как реализовать разные контроллеры, DTO, сервисы
- маршрутизация в Spring Cloud Gateway
- группировка спецификаций Swagger/OpenAPI
- Поддержка на фронтенде:
- Версионирование в CI/CD:

Ссылка на статью:
Версионирование REST API в Spring Boot: практическое руководство
👍35🔥2910🏆4❤‍🔥2
Друзья, вышло техническое интервью с Евгением Савиновым (@SavinovEvgeny), опытным Java Tech Lead.

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

Ссылка на видео:
Тестовое собеседование Java разработчика #34 - Евгений Савинов

Приятного просмотра!
🔥4921👍15