Ответ
Последний значимый проект – разработка высоконагруженного REST API для финтех-сервиса.
Стек: Java 11, Spring Boot, Hibernate, PostgreSQL, Redis, Docker.
Основные задачи и оптимизации:
- Оптимизация работы с БД: Решил проблему N+1 в JPA, использовал
@EntityGraphи проекции DTO. - Внедрение кэширования: Добавил двухуровневое кэширование ответов API для часто запрашиваемых данных.
- Асинхронная обработка: Вынес фоновые задачи (логирование, нотификации) с помощью
@AsyncиThreadPoolTaskExecutor.
Пример реализации кэширования с Spring Cache:
@Service
public class UserServiceImpl implements UserService {
@Override
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public UserDto getById(Long id) {
// Запрос выполняется только при промахе кэша
return userRepository.findProjectedById(id);
}
}
Архитектурные изменения: Участвовал в миграции с монолита на микросервисную архитектуру. Мы выделили три независимых сервиса (пользователи, платежи, отчеты), которые обменивались событиями через Apache Kafka, что повысило отказоустойчивость и масштабируемость системы.
Ответ 18+ 🔞
Да что ж такое-то, блядь! Ну вот сидишь, значит, пишешь свой код, думаешь — всё, красава, всё летает. А потом приходит этот, бизнес, и такой: «А давайте сделаем финтех, но чтобы выдерживало, блядь, овердохуища запросов в секунду!». Ну, пиздец, началось.
Короче, последняя моя эпопея — это высоконагруженное REST API для этих, финтеховских ребят. С деньгами, сука, шутки плохи, там всё должно работать, как часы, а иначе — волнение ебать, терпения ноль ебать у клиентов.
Чем ковырялся: Java 11, Spring Boot, Hibernate, PostgreSQL, Redis, Docker. Стандартный такой, блядь, набор для того, чтобы с ума сойти.
И что я там наворотил, спросишь? А вот что:
-
С БД пришлось повоевать. Hibernate, он же, сука, такой умный — начнёт тебе по одному юзеру вытаскивать, а у него там связи, ленивые коллекции... Классический N+1, ёпта! Я сначала офигел — откуда такие тормоза? Потом врубил
@EntityGraph, проекции DTO начал использовать — чтобы тащил из базы только то, что надо, а не всю ебучую объектную модель. Сразу полегчало, блядь. -
Кэширование — наше всё. Без этого нихуя. Сделал двухуровневое: часто запрашиваемые данные, типа курсов валют или справочников, — сразу в Redis летят. Чтоб базу лишний раз не ебашить. Spring Cache, блядь, рулит.
-
Всё, что можно — в фон. Пользователь платёж сделал — и хуй с ним, пусть идёт. А вот логировать операцию, письмо отправить, смс — это всё в отдельные потоки через
@Async.ThreadPoolTaskExecutorнастроил, чтобы эти фоновые задачи не забили всё нахуй. Главное — успеть впердолить ответ клиенту, а остальное — как-нибудь потом.
Вот, смотри, как кэш впилил, красиво же:
@Service
public class UserServiceImpl implements UserService {
@Override
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public UserDto getById(Long id) {
// Запрос выполняется только при промахе кэша
return userRepository.findProjectedById(id);
}
}
Красота, да? Запрос в базу — только если в кэше пусто. А так — чирик, и данные на руках.
А самое, блядь, интересное — это архитектура. Мы же начинали с монолита, здоровенного такого. А потом поняли — пидарас шерстяной, так жить нельзя! Один сервис упадёт — и всё, накрылся медным тазом весь наш финтех.
Начали пилить на микросервисы. Выделили три штуки: пользователи, платежи, отчеты. И чтобы они между собой общались не напрямую, а через события в Apache Kafka. Получилось, блядь, элегантно: один сервис сделал своё дело — бросил событие в кафку и забыл. А кто надо — тот подхватит. Масштабируемость выросла, отказоустойчивость — просто удивление пиздец. Теперь если сервис отчётов сдохнет, то платежи-то всё равно работают! Во какие распиздяйства, блядь, но правильные.