12073
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика Связь: @devmangx РКН: https://clck.ru/3H4WUg
Кэшировать или не кэшировать?
Это вопрос, с которым бэкендер сталкивается каждый день.
Большинство инженеров кэшируют слишком много.
Это ленивая инженерия.
Вот небольшой фреймворк, чтобы принимать решение правильно:
I. Данные часто запрашиваются?
II. Их дорого получать?
III. Они изменчивые?
IV. Объём данных большой?
V. Влияет ли это на воспринимаемую пользователем задержку?
VI. Безопасно ли кэшировать?
VII. Есть ли механизм протухания или инвалидации кэша?
👉 Java Portal
Автор pgrust — PostgreSQL, переписанного на Rust, — рассказал о четырёх распространённых причинах сбоев PostgreSQL:
1. VACUUM и переполнение счётчика идентификаторов транзакций
2. Лимиты подключений и модель «один процесс на подключение»
3. Неудачные планы выполнения запросов — интересно, насколько здесь помогут новые хинты для запросов в PostgreSQL 19
4. Статистика для JSON
Раздел о JSON оказался интересным. Любопытно, устраняют ли расширения PostgreSQL вроде DocumentDB некоторые из этих ограничений.
Стоит прочитать, если вы работаете с PostgreSQL.
https://malisper.me/the-four-horsemen-behind-thousands-of-postgres-outages/
👉 Java Portal
Сохрани этот ресурс, если работаешь с SQL.
Это playground без установки, где можно:
- создавать таблицы, выполнять запросы и делиться результатами;
- работать с MySQL, PostgreSQL и SQL Server.
Бесплатно и без установки:
→ http://runsql.com/r
👉 Java Portal
В Spring Boot 4 больше нет @MockBean — вместо него теперь используется @MockitoBean.
Для моков в полях всё привычно:
— @MockitoBean
— @MockitoSpyBean
Но в классах @Configuration они больше не используются. Для общих моков теперь рекомендуется подключать тестовые конфигурации через @Import.
#SpringBoot4 #Testing
👉 Java Portal
Используйте Stream.peek() только для отладки, а не для реальной логики.
✅ peek() выполняется как побочный эффект, поэтому его вызов легко не заметить или вообще потерять при выполнении Stream pipeline.
✅ Для намеренной обработки данных лучше использовать map() или forEach().
#Java #Streams
👉 Java Portal
💡 Используй Instant.truncatedTo(...), когда нужно сравнивать время с точностью до дня, часа или минуты.
✅ Instant.equals() сравнивает значение целиком, поэтому разница даже в наносекундах даст false
✅ truncateTo(ChronoUnit.DAYS) отбрасывает более мелкие единицы времени
✅ Удобно для проверок вроде «тот же день» или «тот же час»
#Java #Time
👉 Java Portal
Вы создали составной индекс:
(first_name, last_name, city)
SELECT *
FROM users
WHERE last_name = 'Smith';
last_name является его частью?WHERE first_name = ?
WHERE first_name = ? AND last_name = ?
WHERE first_name = ? AND city = ?
В JVM уже есть вполне хороший встроенный профайлер.
Он доступен ещё с Java 11, но многие до сих пор им не пользуются.
Называется JDK Flight Recorder (JFR). В JEP 328 для него даже был задан ориентир: не более 1% overhead в конфигурации по умолчанию на SPECjbb2015.
JFR можно включить прямо для уже запущенного процесса:
jcmd <pid> JFR.start
A Compiler Writing Journey — практическое руководство по созданию компиляторов.
https://github.com/DoctorWkt/acwj
👉 Java Portal
PostgreSQL 19 теперь умеет показывать активность асинхронного ввода-вывода прямо в EXPLAIN.
Это упрощает понимание:
→ где именно используется асинхронный I/O;
→ какие части плана обращаются к хранилищу;
→ получает ли запрос преимущество от асинхронного чтения.
Меньше догадок и больше прозрачности в том, что PostgreSQL делает под капотом плана выполнения запроса.
В PostgreSQL 18 появился асинхронный I/O.
А в PostgreSQL 19 стало проще увидеть, как он работает.
👉 Java Portal
Не позволяйте одному контейнеру съесть всю память сервера.
Устанавливайте лимиты памяти в Docker с помощью флага --memory или через настройки в файле Compose
👉 Java Portal
Как один баг в Google Cloud уронил весь Интернет
12 июня Google Cloud упал, и вместе с ним перестали работать Spotify, Fitbit, Gmail, Google Drive, Vertex AI и десятки других сервисов. Причиной оказался всего один null pointer баг в Service Control — сервисе, через который проходит почти каждый запрос к Google Cloud API.
Все запросы проходят через Service Control, он как вышибала, решающий, есть ли у тебя доступ. Если он падает, то рушится всё.
В конце мая Google добавил туда новый код для проверки квот, где не было обработки ошибок на пустые поля. На тестах этот код не активировался, потому что требовалась специфичная политика. Не было ни feature flag, ни постепенного раската — просто мёртвый код, ждавший своего часа.
12 июня утром в базы попала политика с пустыми полями. Service Control попытался её обработать, наткнулся на null pointer и упал.
Spanner почти мгновенно разнёс некорректные данные по всему миру, и каждая инстанция, которая к ним обратилась, падала следом. Двух минут хватило, чтобы Google Cloud лег глобально.
Начались таймауты, 503 от перегруженных систем и 401, когда пустые политики интерпретировались как отсутствие прав.
Пользователи Spotify массово получали 401, Fitbit выдавал разные ошибки в зависимости от региона, сервисы не могли пройти аутентификацию к своим бэкендам.
У Google был kill switch — красная кнопка, чтобы отключить проблемный код. Её нажали через сорок минут, и большая часть регионов восстановилась. Но us-central1 оставался недоступен ещё три часа. Когда тысячи инстансов Service Control перезапустились одновременно, они одновременно пошли в базу и устроили эффект стада, который уронил даже сам фикс.
Хуже всего то, что статус-дэшборд Google тоже крутился на Google Cloud. Когда облако упало, он умер вместе с ним, и мониторинг ослеп. Команды поддержки почти час работали вслепую.
Инцидент случился потому, что не было feature flag на новом коде, не было проверки на null в критическом пути, данные с багом мгновенно разлетелись по всему миру, восстановление не имело задержек и мониторинг был привязан к той же инфраструктуре, которую он должен был отслеживать.
После этого Google заморозил изменения в Service Control, начал переделывать систему так, чтобы компоненты могли падать независимо, добавляет задержки в репликацию, чтобы отлавливать некорректные данные, и строит отдельный мониторинг, который будет жить вне основной системы.
В итоге вся история показала, что один пропущенный if может уронить одну из самых сложных платформ в мире. Не атака и не катастрофа, а просто null pointer.
В распределённых системах локальный сбой превращается в глобальную аварию быстрее, чем человек успевает отреагировать. Инфраструктура, которая даёт масштаб, так же усиливает и ошибки.
Любой запрос к API всегда на расстоянии одного непроверенного значения от фатала. Это и есть реальность современной облачной архитектуры.
Полный отчет о происшествии: ссылка
👉 Java Portal
Иногда я удивляюсь тому, насколько Java и C# похожи.
Оба языка работают в управляемой среде выполнения с JIT-компиляцией и сборкой мусора: JVM для Java и CLR для C#.
Оба имеют строгую статическую типизацию. Я также нашёл статью, в которой говорится, что к 2026 году даже разрыв в возможностях языков практически исчез: records, pattern matching, primary constructors и так далее.
Java Code Geeks, «The Feature Gap Has Closed», 2026.
Какой язык вы предпочитаете и почему?
👉 Java Portal
Хотите стать backend-инженером, которого в 2026 году захотят нанять компании уровня Google, Uber, Netflix и Stripe?
Тогда изучите:
## Сети
- DNS
- TCP/IP
- HTTP/2
- HTTP/3
- TLS
## Внутреннее устройство баз данных
- B+-деревья
- MVCC
- WAL
- оптимизаторы запросов
- индексы
## Проектирование API
- REST
- gRPC
- GraphQL
- идемпотентность
- пагинация
## Распределённые системы
- теорема CAP
- консенсус
- репликация
- CQRS
- Saga
## Событийно-ориентированная архитектура
- Kafka
- Outbox Pattern
- CDC
- потоковая обработка событий
## Инженерия производительности
- пулы соединений
- кэширование
- асинхронный ввод-вывод
- профилирование
## Cloud Native
- Docker
- Kubernetes
- Service Mesh
- автомасштабирование
## Наблюдаемость
- OpenTelemetry
- Prometheus
- Grafana
- ELK
## Безопасность
- OAuth 2.0
- JWT
- mTLS
- Zero Trust
- OWASP Top 10
## Production Engineering
- Blue-Green Deployments
- Canary Releases
- Chaos Engineering
- Disaster Recovery
👉 Java Portal
Spring Boot: HTTP-клиенты через интерфейсы с @HttpExchange.
✅ Аннотируйте интерфейс — Spring Boot создаст клиентскую реализацию
✅ Настройте тайм-ауты/SSL с помощью свойств spring.http.clients.*
#SpringBoot4 #HttpExchange
👉 Java Portal
Используйте Files.isSameFile(path1, path2), чтобы проверить, указывают ли два пути на один и тот же файл. Метод также учитывает симлинки.
✅ Он проверяет, ссылаются ли два объекта Path на один и тот же реальный файл в файловой системе.
#Java #JavaDev
👉 Java Portal
В Spring Boot 4 библиотекой для работы с JSON по умолчанию стала Jackson 3.
✅ Изменились пакеты: com.fasterxml → tools.jackson
✅ Вместо обычного изменяемого бина ObjectMapper используется неизменяемый JsonMapper, создаваемый через Builder
✅ Крайний вариант (устаревший): добавить spring-boot-jackson2
#SpringBoot4 #Jackson3
👉 Java Portal
Тяжело нынче быть Java-разработчиком...
👉 Java Portal
Флаг Java, который снижает потребление памяти без единого изменения в коде.
Compact Object Headers уменьшают размер заголовка каждого объекта с 16 до 8 байт на 64-битных архитектурах.
В одном из сценариев бенчмарка SPECjbb2015 в JEP указывается снижение использования heap на 22% и CPU на 8% — OpenJDK, JEP 519.
Более того, согласно JEP 534, Amazon уже использует эту возможность в продакшене в сотнях сервисов, причём большинство из них работает на бэкпортах для Java 17 и 21.
В JDK 25 эту опцию нужно включать вручную:-XX:+UseCompactObjectHeaders
Но есть важный момент: JEP 534 предлагает сделать Compact Object Headers поведением по умолчанию в JDK 27.
👉 Java Portal
В Java есть несколько сборщиков мусора, и некоторые из них действительно могут вызывать паузы, которые останавливают приложение на секунды.
Но ZGC работает иначе.
В JEP 439 прямо указано: паузы ZGC стабильно измеряются в микросекундах, тогда как у G1 — сборщика по умолчанию — они могут составлять от миллисекунд до секунд.
При этом длительность пауз ZGC не растёт вместе с размером heap: согласно официальной документации, он рассчитан на heap от нескольких сотен мегабайт до 16 ТБ.
Важно: ZGC не является сборщиком по умолчанию. По умолчанию используется G1.
ZGC нужно включать вручную:
-XX:+UseZGC
Собираем бэкенд-комьюнити на JVM Day
Бэкендеры, 29 августа в Москве пройдет хардкорная конференция. Ждут своих: Java-, Scala- и Kotlin-разработчиков, архитекторов и тимлидов.
Здесь выступят и расскажут:
— Андрей Кулешов — что нового в мире JVM за год.
— Сергей Петрелевич — разработка по Mechanical Sympathy.
— Александр Ланцов — Java после Loom: другие модели concurrency.
— Антон Курако — как бенчмарки вводят в заблуждение.
А вечером во дворе T-Space — посиделки, интерактивы и открытый микрофон с историями ошибок.
Мест мало, а цена билета будет расти.
Успевай зарегистрироваться
Spring Boot 4: для подключения поддерживаемых технологий теперь лучше использовать более узкие, специализированные starter-зависимости.
✅ В Boot 4 появились более компактные модули под конкретные технологии
✅ spring-boot-starter-* подключает соответствующую автоконфигурацию
✅ Для Flyway, Liquibase и Mongo теперь нужны отдельные starter’ы
#SpringBoot4 #Modular
👉 Java Portal
Анимированное введение в преобразование Фурье от 3Blue1Brown.
https://youtu.be/spUNpyF58BY
👉 Java Portal
Используйте Comparator.nullsFirst() или Comparator.nullsLast(), если ключи сортировки могут быть null.
✅ comparing(User::getName) выбросит NullPointerException, если getName() вернёт null.
✅ Оберните компаратор в nullsFirst() или nullsLast(), чтобы явно задать порядок для null.
✅ Для сортировки по нескольким полям добавляйте thenComparing().
#Java #Comparator
👉 Java Portal
В PostgreSQL 19 autovacuum станет умнее и сможет работать параллельно.
Теперь PostgreSQL сможет запускать сразу несколько autovacuum-воркеров, оценивать риск для каждой таблицы и в первую очередь обслуживать те, где очистка нужнее всего.
Раньше autovacuum мог превращаться в длинную очередь: один воркер обрабатывал таблицы по одной, из-за чего проблемные таблицы могли ждать, пока завершится менее срочная работа.
В PostgreSQL 19 несколько таблиц можно будет очищать одновременно, а приоритет получат таблицы с наибольшим риском.
👉 Java Portal
Если говорить про «прикольные штуки с конференций по программированию», Java Ring, пожалуй, самая крутая.
Ты получал своё кольцо, записывал свои предпочтения по кофе, а затем использовал его для аутентификации и получения бесплатного «Java» на JavaOne 1998.
Конечно, внутри него был небольшой микропроцессор, который запускал JVM, с целыми 6 КБ NVRAM. В то время они заявляли(?), что «конференция — это компьютер», потому что эти кольца носили 14 000 участников.
Насколько я могу понять, никто не использовал какое-либо… настоящее P2P-вычисление. Тем не менее, в маркетинговых материалах это называли параллельным компьютером.
Забавно, но спустя почти 30 лет эта идея может продолжать жить. Некто по имени yamad проделал отличную работу по реверс-инжинирингу Java Ring и ведёт подробный блог об этом. Замена севшей герметичной батареи оказалась сложной задачей, но, судя по всему, ему удалось запускать и записывать новые программы на устройство, которое работает на оригинальной JVM!
Мне очень, очень хочется теперь раздобыть несколько Java Ring просто ради того, чтобы проверить, можно ли сделать с ними хоть что-нибудь в стиле P2P…
Вот оригинальная серия постов в блоге yamad. Оказалось, что найти IDE было отдельным приключением!
https://yamad.jp/en/
👉 Java Portal
Для null-safe проверки равенства лучше использовать Objects.equals(a, b).
✅ a.equals(b) выбросит NullPointerException, если a равен null
✅ Objects.equals корректно обрабатывает null с обеих сторон
✅ Оба значения null → true; одно значение null → false; иначе вызывается a.equals(b)
#Java #Objects
👉 Java Portal
Ты на интервью по системному дизайну. Спрашивают: «Как бы ты спроектировал слой кэширования для высоконагруженного веб-приложения?»
Вот подробный подход:
I. Что кэшировать → Кэшируй дорогие запросы к БД, горячие данные с большим количеством чтений и статические ресурсы; избегай очень динамичных, гигантских объектов или чувствительной PII, если только она не зашифрована и не защищена доступом.
II. Хранилище кэша → Используй Redis или Memcached для распределённого in-memory кэша, CDN для статики на краю сети, локальные in-process кэши (например, Caffeine) для сверхнизкой задержки L1.
III. Паттерн и запись → По умолчанию Cache-Aside: читаем из кэша, при промахе читаем из БД и заполняем кэш. Для сильной консистентности чтения — Write-Through (пишем одновременно в кэш и БД). Всегда сначала коммитим БД, потом обновляем/инвалидируем кэш, чтобы не дать устаревшим данным просочиться.
IV. Истечение и вытеснение → TTL для каждого типа данных, чтобы держать кэш свежим, политики вытеснения (LRU/LFU) для управления памятью, negative caching для промахов, чтобы не перегружать БД. Ограничивай размер объектов, чтобы не создавать проблемы с памятью и сборкой мусора.
V. Масштабирование и «горячие ключи» → Масштабируй через consistent hashing и реплики для пропускной способности чтения. Многоуровневый кэш (edge→regional→local). Горячие ключи — локальные L1 кэши, отдельные кэши для горячих ключей, либо rate-limiting запросов.
VI. Надёжность и наблюдаемость → Предотвращай «каскады» промахов через request coalescing, короткие блокировки (SETNX + expiry) или serve-stale-while-revalidate с jittered TTL. Мониторь hit rate, latency, eviction, память и replication lag с алертами.
👉 Java Portal
Утверждение «Go потребляет в 4 раза меньше памяти, чем Java» в целом верно, но применимо далеко не во всех сценариях.
При нагрузке в 500 запросов в секунду сервис на Go использует около 68 МБ памяти, а JVM — около 412 МБ (BackendBytes).
Но при 1 миллионе конкурентных задач ситуация меняется на противоположную: Java использует около 800 МБ, а Go — примерно 2,5 ГБ (WebDev|today).
«Победитель» по потреблению памяти зависит от конкретной нагрузки.
Именно поэтому нельзя просто разбрасываться случайными цифрами без учёта контекста.
👉 Java Portal
Концепции моделирования данных, которые должен знать каждый разработчик
1. Сущность — Объект реального мира или концепт, о котором вы хотите хранить данные (например, пользователь, заказ).
2. Атрибут — Свойство или поле сущности (например, имя, email, цена).
3. Первичный ключ — Уникальный идентификатор для каждой строки в таблице (например, user_id).
4. Внешний ключ — Ссылка на первичный ключ в другой таблице; используется для связывания сущностей.
5. Связь "один к одному" — Каждая строка в одной таблице связана с одной строкой в другой.
6. Связь "один ко многим" — Одна строка в таблице связана с несколькими строками в другой (например, пользователь → посты).
7. Связь "многие ко многим" — Несколько строк в одной таблице связаны с несколькими строками в другой (требуется таблица-связка).
8. Нормализация — Организация данных с целью уменьшения дублирования и повышения целостности.
9. Денормализация — Добавление избыточных (дублированных) данных для повышения скорости чтения.
10. Первая нормальная форма (1NF) — Устранение повторяющихся групп; каждая ячейка содержит атомарное значение.
11. Вторая нормальная форма (2NF) — Устранение частичных зависимостей от составного ключа.
12. Третья нормальная форма (3NF) — Устранение транзитивных зависимостей (неключевые столбцы не зависят от других неключевых столбцов).
13. Суррогатный ключ — Системно-сгенерированный идентификатор (например, UUID или auto-increment ID).
14. Естественный ключ — Уникальный идентификатор из реального мира (например, email или номер паспорта).
15. Составной ключ — Первичный ключ, состоящий из нескольких столбцов.
16. Уникальное ограничение — Обеспечивает уникальность значений в столбце (или группе столбцов).
17. Допустимость NULL — Возможность хранить в столбце NULL (т.е. отсутствие значения).
18. Ограничение по значению — Проверяет значения в столбце на соответствие условиям (например, age > 0).
19. Индекс — Повышает производительность поиска за счёт ускоренного доступа к данным.
20. Схема — Структура/определение таблиц, полей, типов и связей в базе данных.
21. ERD (диаграмма "сущность-связь") — Визуальное представление сущностей и их связей.
22. Кардинальность — Количество строк, которое может быть связано в рамках связи.
23. Тип данных — Определяет, какие значения может хранить столбец (например, INT, VARCHAR, DATE).
24. Перечисление — Поле, значение которого ограничено предопределённым набором (например, status = [pending, complete]).
25. Мягкое удаление — Пометка записи как удалённой без фактического удаления (например, deleted_at).
👉 Java Portal