Тайм-аут закончился. Что осталось работать?
Ошибка уже вернулась клиенту, а SQL ещё может занимать базу и соединение. На карте — четыре разных уровня: дедлайн операции, выполнение SQL, ожидание блокировки и аварийное закрытие сети.
Начните с полного разбора: https://t.me/management_Java/35
Здесь разбираю Java в production: где заканчиваются гарантии и что проверить в своём сервисе. JVM, базы, надёжность и инженерные решения — с первичными источниками и схемами.
Следующий шаг: выберите один медленный запрос и проверьте, что после отмены прекратилась работа в базе и освободился ресурс пула.
Автор — Андрей Овчаренко.
Ошибка уже вернулась клиенту, а SQL ещё может занимать базу и соединение. На карте — четыре разных уровня: дедлайн операции, выполнение SQL, ожидание блокировки и аварийное закрытие сети.
Начните с полного разбора: https://t.me/management_Java/35
Здесь разбираю Java в production: где заканчиваются гарантии и что проверить в своём сервисе. JVM, базы, надёжность и инженерные решения — с первичными источниками и схемами.
Следующий шаг: выберите один медленный запрос и проверьте, что после отмены прекратилась работа в базе и освободился ресурс пула.
Автор — Андрей Овчаренко.
Решение важнее новостного пересказа
Информационного шума и так до хрена. Ценность технического контента не в том, сколько релизов я пересказал, а в том, помог ли разбор принять инженерное решение.
DORA сейчас использует 5 delivery metrics: 3 про throughput и 2 про instability. Сильные команды обычно хороши по всем пяти, но сама DORA предупреждает: чужие target без контекста — отличный способ красиво врать самим себе.
Google SRE показывает цену SLO за 30 дней:
— 99,9% оставляет 43 мин 12 с error budget;
— 99,99% — всего 4 мин 19 с.
Поэтому здесь схема простая: сигнал → доказательства → механизм → границы → решение. Иногда вывод будет скучным: пока ничего не менять. Это не трусость, а нормальная архитектура, если названы критерий и цена ожидания.
#Java #архитектура #исследования
Информационного шума и так до хрена. Ценность технического контента не в том, сколько релизов я пересказал, а в том, помог ли разбор принять инженерное решение.
DORA сейчас использует 5 delivery metrics: 3 про throughput и 2 про instability. Сильные команды обычно хороши по всем пяти, но сама DORA предупреждает: чужие target без контекста — отличный способ красиво врать самим себе.
Google SRE показывает цену SLO за 30 дней:
— 99,9% оставляет 43 мин 12 с error budget;
— 99,99% — всего 4 мин 19 с.
Поэтому здесь схема простая: сигнал → доказательства → механизм → границы → решение. Иногда вывод будет скучным: пока ничего не менять. Это не трусость, а нормальная архитектура, если названы критерий и цена ожидания.
#Java #архитектура #исследования
Микросервисы: дорогой способ слишком рано почувствовать независимость
Микросервисы обещают независимые релизы, масштабирование и изоляцию отказов. А приносят сетевые вызовы, распределённое состояние и эксплуатационную координацию — сюрприз, бесплатной архитектуры не завезли.
Дэвид Парнас: модуль отделяют там, где он скрывает независимо меняющееся решение. Отдельный процесс нужен позже — когда независимость должна дойти до релиза, scaling или failure domain.
DeathStarBench 2019 собрал 6 end-to-end приложений: benchmark одного процесса не видит service graph и tail latency всей системы. В кейсе Prime Video workflow упёрся примерно в 5% ожидаемой нагрузки; после локальной консолидации команда сообщила о снижении инфраструктурной стоимости на 90%.
Это не «монолит всех победил». Архитектурная религия — херовый заменитель измерений. Стартовая позиция — модульный монолит; сервис выделяется при самостоятельной бизнес-границе и измеримом эксплуатационном давлении.
#Java #архитектура #микросервисы
Микросервисы обещают независимые релизы, масштабирование и изоляцию отказов. А приносят сетевые вызовы, распределённое состояние и эксплуатационную координацию — сюрприз, бесплатной архитектуры не завезли.
Дэвид Парнас: модуль отделяют там, где он скрывает независимо меняющееся решение. Отдельный процесс нужен позже — когда независимость должна дойти до релиза, scaling или failure domain.
DeathStarBench 2019 собрал 6 end-to-end приложений: benchmark одного процесса не видит service graph и tail latency всей системы. В кейсе Prime Video workflow упёрся примерно в 5% ожидаемой нагрузки; после локальной консолидации команда сообщила о снижении инфраструктурной стоимости на 90%.
Это не «монолит всех победил». Архитектурная религия — херовый заменитель измерений. Стартовая позиция — модульный монолит; сервис выделяется при самостоятельной бизнес-границе и измеримом эксплуатационном давлении.
#Java #архитектура #микросервисы
@Transactional не накрывает сеть священным куполом
Транзакция сохраняет инвариант: изменение фиксируется целиком либо не фиксируется. Но её власть заканчивается на границе базы. HTTP и broker на аннотацию смотрят без благоговения.
По Spring Framework, @Transactional действует только в границе TransactionManager:
— self-invocation в proxy mode не перехватывается;
— checked exception по умолчанию не вызывает rollback;
— PostgreSQL принимает 4 названия isolation level, но реализует 3 режима: READ UNCOMMITTED работает как READ COMMITTED.
В READ COMMITTED каждый SELECT получает новый snapshot. SQLSTATE 40001 и deadlock 40P01 требуют повтора всей транзакции.
Для DB + broker данные и outbox фиксируются вместе. Debezium читает изменения через CDC, Event Router преобразует запись. Дубликаты возможны, consumer остаётся идемпотентным. Иначе получаем распределённый бардак с очень уверенной аннотацией.
#Java #Spring #транзакции
Транзакция сохраняет инвариант: изменение фиксируется целиком либо не фиксируется. Но её власть заканчивается на границе базы. HTTP и broker на аннотацию смотрят без благоговения.
По Spring Framework, @Transactional действует только в границе TransactionManager:
— self-invocation в proxy mode не перехватывается;
— checked exception по умолчанию не вызывает rollback;
— PostgreSQL принимает 4 названия isolation level, но реализует 3 режима: READ UNCOMMITTED работает как READ COMMITTED.
В READ COMMITTED каждый SELECT получает новый snapshot. SQLSTATE 40001 и deadlock 40P01 требуют повтора всей транзакции.
Для DB + broker данные и outbox фиксируются вместе. Debezium читает изменения через CDC, Event Router преобразует запись. Дубликаты возможны, consumer остаётся идемпотентным. Иначе получаем распределённый бардак с очень уверенной аннотацией.
#Java #Spring #транзакции
Exactly-once заканчивается там, где начинается бизнес
Идемпотентность нужна, чтобы retry не стал повторным платежом или заказом. Транспорт может сказать «ровно один раз», но внешней системе на его самооценку плевать.
В Apache Kafka 4.3 producer idempotence включена по умолчанию без конфликтующих настроек и требует acks=all, retries>0, max.in.flight≤5. KIP-98 связывает records и offsets через sendOffsetsToTransaction; consumer читает read_committed. Платёжный API в гарантию не входит.
AWS Builders’ Library рекомендует caller-provided request ID для повторов одного намерения. Я добавляю unique constraint, состояния IN_PROGRESS/SUCCEEDED и reconciliation неизвестного исхода.
Stripe ограничивает idempotency key 255 символами и может удалить его после 24 часов. После pruning старый retry станет новым запросом. Это контракт Stripe, не закон природы.
Если деньги списались дважды, пользователю до лампочки, насколько красиво exactly-once выглядело внутри Kafka.
#Java #Kafka #идемпотентность
Идемпотентность нужна, чтобы retry не стал повторным платежом или заказом. Транспорт может сказать «ровно один раз», но внешней системе на его самооценку плевать.
В Apache Kafka 4.3 producer idempotence включена по умолчанию без конфликтующих настроек и требует acks=all, retries>0, max.in.flight≤5. KIP-98 связывает records и offsets через sendOffsetsToTransaction; consumer читает read_committed. Платёжный API в гарантию не входит.
AWS Builders’ Library рекомендует caller-provided request ID для повторов одного намерения. Я добавляю unique constraint, состояния IN_PROGRESS/SUCCEEDED и reconciliation неизвестного исхода.
Stripe ограничивает idempotency key 255 символами и может удалить его после 24 часов. После pruning старый retry станет новым запросом. Это контракт Stripe, не закон природы.
Если деньги списались дважды, пользователю до лампочки, насколько красиво exactly-once выглядело внутри Kafka.
#Java #Kafka #идемпотентность
Timeout завершает Future, но не работу
В CompletableFuture легко перепутать завершение обещания и остановку работы. Первое API делает за строку; второе за вас никто, зараза, не спроектирует.
Oracle API:
Поэтому я развожу четыре слоя:
— deadline операции;
— timeout реального ресурса;
— cooperative cancellation;
— completion для caller и dependents.
Fallback допустим только как явный бизнес-контракт. TimeoutException у caller и живой JDBC-запрос — не cancellation, а перенос проблемы в мониторинг.
#Java #concurrency #CompletableFuture #reliability
В CompletableFuture легко перепутать завершение обещания и остановку работы. Первое API делает за строку; второе за вас никто, зараза, не спроектирует.
Oracle API:
cancel(...) завершает stage через CancellationException, но mayInterruptIfRunning здесь не имеет эффекта — interrupts не управляют обработкой. orTimeout завершает тот же Future через TimeoutException, а completeOnTimeout подставляет значение. Supplier, JDBC-запрос или HTTP-вызов могут продолжать занимать ресурс.Поэтому я развожу четыре слоя:
— deadline операции;
— timeout реального ресурса;
— cooperative cancellation;
— completion для caller и dependents.
Fallback допустим только как явный бизнес-контракт. TimeoutException у caller и живой JDBC-запрос — не cancellation, а перенос проблемы в мониторинг.
#Java #concurrency #CompletableFuture #reliability
Hibernate экономит код. Базе данных на это плевать
ORM отлично убирает повторяющийся persistence-код и связывает данные с объектной моделью. Но SQL, сеть и materialization никуда не деваются — просто становятся менее заметны в Java-коде. Магия закончилась на аннотациях.
100 orders + lazy collection в цикле: 1 root query + до 100 secondary selects = до 101 SQL.
Две to-many коллекции по 10 и 20 элементов: JOIN способен вернуть до 200 rows на parent. Hibernate ORM User Guide также фиксирует: EAGER не гарантирует один JOIN, несколько bags могут вызвать MultipleBagFetchException, а IDENTITY отключает JDBC insert batching.
Поэтому я смотрю SQL statements, rows, план через PostgreSQL EXPLAIN и размер persistence context/flush, а не гадаю по красивым entities. Только потом выбираю JOIN FETCH, entity graph, batch fetch, DTO или native SQL.
Hibernate — инструмент. Делать вид, что он отменил SQL, — дорогая иллюзия.
#Java #Hibernate #JPA #SQL
ORM отлично убирает повторяющийся persistence-код и связывает данные с объектной моделью. Но SQL, сеть и materialization никуда не деваются — просто становятся менее заметны в Java-коде. Магия закончилась на аннотациях.
100 orders + lazy collection в цикле: 1 root query + до 100 secondary selects = до 101 SQL.
Две to-many коллекции по 10 и 20 элементов: JOIN способен вернуть до 200 rows на parent. Hibernate ORM User Guide также фиксирует: EAGER не гарантирует один JOIN, несколько bags могут вызвать MultipleBagFetchException, а IDENTITY отключает JDBC insert batching.
Поэтому я смотрю SQL statements, rows, план через PostgreSQL EXPLAIN и размер persistence context/flush, а не гадаю по красивым entities. Только потом выбираю JOIN FETCH, entity graph, batch fetch, DTO или native SQL.
Hibernate — инструмент. Делать вид, что он отменил SQL, — дорогая иллюзия.
#Java #Hibernate #JPA #SQL
TTL может синхронизировать отказ
Кэш снижает нагрузку, пока origin не начинает зависеть от него как от несущей стены. Общий expiry hot key превращает cache miss в thundering herd — календарь отказа теперь просто известен заранее.
AWS рекомендует request coalescing: один refresh на ключ, остальные ждут тот же результат. Cloudflare показывает probabilistic early revalidation — refresh распределяется до expiry без отдельного lock-сервиса. RFC 5861 задаёт ещё два договора: stale-while-revalidate и stale-if-error.
Мой набор для hot keys:
— TTL jitter;
— single-flight с timeout;
— bounded early refresh;
— stale только для безопасных данных;
— load test холодного cache и метрика origin amplification.
Если потеря cache может положить dependency, это часть модели надёжности. Поставить TTL и надеяться — не стратегия; это будильник для аварии.
#architecture #cache #reliability #systemdesign
Кэш снижает нагрузку, пока origin не начинает зависеть от него как от несущей стены. Общий expiry hot key превращает cache miss в thundering herd — календарь отказа теперь просто известен заранее.
AWS рекомендует request coalescing: один refresh на ключ, остальные ждут тот же результат. Cloudflare показывает probabilistic early revalidation — refresh распределяется до expiry без отдельного lock-сервиса. RFC 5861 задаёт ещё два договора: stale-while-revalidate и stale-if-error.
Мой набор для hot keys:
— TTL jitter;
— single-flight с timeout;
— bounded early refresh;
— stale только для безопасных данных;
— load test холодного cache и метрика origin amplification.
Если потеря cache может положить dependency, это часть модели надёжности. Поставить TTL и надеяться — не стратегия; это будильник для аварии.
#architecture #cache #reliability #systemdesign