Ниже представлен детальный анализ кода с точки зрения промышленной разработки, архитектуры и эксплуатации в production.
1. Потокобезопасность и утечка памяти кеша (HashMap)
Почему это ошибка:HashMap не является потокобезопасным. В продакшене один экземпляр приложения обрабатывает десятки/сотни параллельных запросов. Статический кеш разделяется между всеми потоками. Что произойдёт в проде: При конкурентном доступе возникнут ConcurrentModificationException, потеря или дублирование записей. Кеш не имеет TTL/eviction, что приведёт к утечке памяти и eventual OutOfMemoryError. Кеш бесполезен при горизонтальном масштабировании (каждый инстанс хранит свои данные). Исправление: Удалить кеш из контроллера. Для кэширования использовать Redis или Caffeine/Guava Cache с политикой вытеснения и TTL. В платежной системе кеш часто избыточен.
2. Использование double для денежных сумм
Почему это ошибка:double работает с плавающей запятой и имеет ошибки округления. Деньги требуют точности до последнего цента/копейки. Что произойдёт в проде: Несоответствие сумм в логах и БД, финансовые расхождения при агрегации, ClassCastException при получении целого числа из JSON (например, "amount": 1000 будет десериализовано в Integer). Исправление: Заменить на BigDecimal на уровне DTO, сущности и репозитория.
3. Отсутствие валидации входных данных (Map<String, Object>)
Почему это ошибка:Map не имеет схемы. Нет аннотаций @NotNull, @DecimalMin, @Pattern. Контроллер принимает любые поля без проверки. Что произойдёт в проде:NullPointerException при отсутствии полей, ClassCastException при некорректных типах, возможность инъекций через поля, отсутствие контроля лимитов и формата счетов. Исправление: Ввести строго типизированный DTO с @Valid, валидаторами и проверкой обязательных полей.
4. Слишком широкая транзакция (@Transactional на create)
Почему это ошибка: Транзакция охватывает не только работу с БД, но и внешние синхронные вызовы (antifraud, kafka, notifications). Это классическое антипаттерн. Что произойдёт в проде: Долгое удержание соединений БД, исчерпание connection pool, блокировки строк, таймауты на уровне DBA, деградация всей системы при зависании внешних сервисов. Исправление: Вынести repo.save() в отдельный метод с короткой транзакцией. Внешние вызовы выполнять асинхронно или через Outbox-паттерн.
5. Self-invocation и игнорирование @Transactional
Почему это ошибка:this.sendNotification(p) вызывается внутри того же класса. Spring AOP работает через прокси, и прямой вызов this. минует прокси. Аннотация @Transactional(propagation = REQUIRES_NEW) не применится. Что произойдёт в проде: Уведомление выполнится в той же транзакции, что и create. При откате основной транзакции уведомление не дойдёт. При успешном коммите, но падении notifications.send(), транзакция откатится, хотя логика могла предполагать отдельную обработку. Исправление: Вынести sendNotification в отдельный Spring-бин или использовать @Lazy self-injection.
6. Отправка p.toString() в Kafka
Почему это ошибка:toString() не гарантирует сериализацию, зависит от реализации, не является схемой и не поддерживает эволюцию формата. Что произойдёт в проде: Потребители получат невалидные данные, рассинхронизация downstream-систем, невозможность откатить изменения формата, ошибки парсинга в продакшене. Исправление: Использовать JSON-сериализацию (Jackson) с описанной схемой (JSON Schema / Avro / Protobuf). Формат должен быть версионирован.
7. Игнорирование ошибок отправки в Kafka
Почему это ошибка:KafkaTemplate.send() по умолчанию асинхронный. Возвращаемый ListenableFuture не обрабатывается. Ошибки сетевых сбоев или недоступности брокера просто логируются и игнорируются. Что произойдёт в проде: Платёж сохраняется в БД, но событие не доходит до Kafka. Потеря данных для аудит-систем, аналитики и downstream-сервисов. “Тихий” отказ. Исправление: Обрабатывать Callback с логированием ошибок и повторной отправкой, либо настраивать retries/acks=all на уровне KafkaTemplate. В критичных системах использовать Outbox.
8. Синхронный вызов antifraud без resilience-механизмов
Почему это ошибка: Нет таймаутов, circuit breaker, retry policy. Вызов блокирует поток в рамках транзакции. Что произойдёт в проде: При зависании антифрода — утечка потоков, исчерпание thread pool, cascading failure, таймауты на уровне Nginx/Gateway, недоступность всего API. Исправление: Добавить Resilience4j (@CircuitBreaker, @Timeout), настроить feign/webClient с таймаутами. Рассмотреть асинхронную проверку с последующим обновлением статуса.
9. Логирование через System.out.println
Почему это ошибка:System.out не интегрируется с ELK/Grafana/Sentry, не имеет уровней логирования, не структурирован. Что произойдёт в проде: Невозможность мониторинга и алертинга, засорение stdout контейнера, потеря информации при ротации логов, невозможность фильтрации по уровням. Исправление: Использовать SLF4J Logger с уровнями INFO/WARN/ERROR. Выносить в отдельный сервис логирования или использовать MDC для трассировки.
10. Перехват Exception и возврат e.getMessage() клиенту
Почему это ошибка:e.printStackTrace() не подходит для прода. e.getMessage() может содержать стектрейс, внутренние пути, названия таблиц, SQL-запросы. Что произойдёт в проде: Утечка внутренней информации (OWASP Top 10), плохой UX, невозможность корректной обработки ошибок на клиенте, засорение логов. Исправление: Использовать @ControllerAdvice + @ExceptionHandler. Возвращать стандартизированные ответы (ErrorDTO). Логировать детали на сервере.
11. Отсутствие обработки частичных отказов (Payment saved, Kafka failed)
Почему это ошибка: Если repo.save() прошёл, а kafka.send() упал — состояние рассинхронизировано. Транзакция коммитится, но событие не опубликовано. Что произойдёт в проде: Платёж в БД есть, но downstream-системы о нём не знают. Потеря данных для аудит-логов, аналитики, уведомлений. Восстановление требует ручного вмешательства. Исправление: Паттерн Outbox: сохранять событие в таблицу outbox в той же транзакции. Отдельный процесс (CDC или периодический опрос) доставляет события в Kafka с гарантией at-least-once.
12. Жёстко заданный статус "PENDING" (String)
Почему это ошибка: Использование строковых констант вместо enum prone to typos, не обеспечивает валидацию состояний, усложняет поддержку. Что произойдёт в проде: Ошибки при сравнении статусов, невозможность добавить новые статусы без рефакторинга всех сравнений, рассинхронизация состояний. Исправление: Использовать enum PaymentStatus с методами валидации переходов.
13. Генерация ID в контроллере
Почему это ошибка: Нарушение SRP. Контроллер знает о внутреннем устройстве сущности и механизмах генерации идентификаторов. Что произойдёт в проде: Сложности с миграцией на другие ID-генераторы, дублирование логики, невозможность переиспользовать сущность вне контекста REST. Исправление: Перенести генерацию ID в сервис или настроить @Id генерацию в JPA/Hibernate (GenerationType.UUID).
14. Возврат сущности Payment напрямую в ответе
Почему это ошибка: Сущность может содержать чувствительные данные, внутренние поля, циклические ссылки, которые не должны попадать в ответ. Что произойдёт в проде: Утечка данных, нарушение инкапсуляции, проблемы сериализации (StackOverflowError при циклических ссылках), привязка API к структуре БД. Исправление: Использовать DTO/VO для ответа. Маппинг через MapStruct или вручную.
15. Отсутствие идемпотентности и проверки на дубликаты
Почему это ошибка: Нет idempotency-key, нет проверки уникальности запроса. Клиент может повторить запрос при таймауте. Что произойдёт в проде: Двойное списание/зачисление, рассинхронизация балансов, финансовые потери, невозможность восстановить состояние после сбоя. Исправление: Добавить заголовок Idempotency-Key, проверять его в БД/Redis, возвращать предыдущий результат при дубликате.
ИТОГО: найдено 15 проблем.
Краткая сводка по категориям:
🔴 Транзакции: 4, 5
🔴 Интеграция: 6, 7, 8, 11
🔴 Безопасность/Данные: 2, 3, 10, 14, 15
🔴 Эксплуатация в проде: 1, 9, 12, 13
🟡 Скрытые под нагрузкой: 1, 4, 8, 15
Код требует рефакторинга с переходом на событийную архитектуру (Outbox), внедрением DTO, валидацией, resilience-механизмами и proper error handling.
Если у кого-то тоже есть опыт локальных серверов для ИИ — делитесь, интересно сравнить подходы..
Начинал с простейшего выделенного сервера инференса на одной RTX-3060/12GB + i5-4520/32GB DDR3 для llama-server под MX Linux 25.2 XFCE на обычных GGUF моделях. Это самый бюджетный однопользовательский вариант ( --parallel 1 - не забываем!). Сейчас в том же корпусе с более мощным БП 2х RTX-3060/12GB, MB ASUS P9X79 LE, i7-4820k, 4x 8GB DDR3 + "самописное" приложение для удалённого управления сервером.
NGL=“auto” И финал лога по задаче: авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.827.998 I slot print_timing: id 0 | task 0 | prompt eval time = 3136.40 ms / 5265 tokens ( 0.60 ms per token, 1678.68 tokens per second)
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.003 I slot print_timing: id 0 | task 0 | eval time = 102895.95 ms / 5964 tokens ( 17.25 ms per token, 57.96 tokens per second)
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.004 I slot print_timing: id 0 | task 0 | total time = 106032.35 ms / 11229 tokens
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.020 I slot print_timing: id 0 | task 0 | graphs reused = 5940
КатегорияРекомендацияПричинаПример реализацииВалидацияДобавить @Valid и DTO для запросаУстранить неопределенность типов и отсутствие проверок@Valid @RequestBody PaymentRequest bodyЛогированиеЗаменить System.out на SLF4JУлучшить контроль уровней и централизацию логовlogger.info("Large payment: {}", amount);ТранзакцииСделать sendNotificationчастью одной транзакции или очистить кэш при ошибкеИзбежать несогласованного состояния@Transactional на sendNotificationКэшИспользовать Spring Cache или ConcurrentHashMapс TTLУстранить гонки и утечки памяти@Cacheable("payments")ИдемпотентностьТребовать Idempotency-KeyПредотвратить дубликаты платежей@RequestHeader("Idempotency-Key")Обработка исключенийРазделить перехваты на конкретные типыПредоставить точные ошибки клиентамcatch (AntifraudException e) { … }Сообщения KafkaОтправлять структурированный JSON без PIIСоответствовать требованиям безопасностиkafka.send("payments", new PaymentEvent(...))Повторы/Обратный отсчетДобавить Retry и Backoff для асинхронных вызововУстойчивость к временным сетевым сбоям@Retryable(...)МониторингЭкспортировать метрики (создание платежей, успех антифрауда, задержки Kafka)Повысить отказоустойчивость и быстрое реагированиеSpring Actuator, Prometheus
Применение этих исправлений сделает контроллер PaymentController более надежным, масштабируемым, соблюдающим требования безопасности и легко тестируемым в производственной среде.
Почему это баг: Код пытается одновременно обновить базу данных (repo.save), отправить сообщение в Kafka (kafka.send) и отправить уведомление (notifications.send). Эти системы не связаны в единую распределенную транзакцию.
Что произойдет в проде: Если repo.save(p) пройдет успешно, но Kafka упадет или произойдет сетевой сбой при отправке сообщения, платеж будет создан в БД, но система обработки заказов/логистики его не увидит. И наоборот: сообщение уйдет, а транзакция в БД откатится. Это приведет к "фантомным" платежам или потере заказов.
Как исправить: Использовать паттерн Transactional Outbox. Сохраняйте событие (сообщение для Kafka) в ту же БД в рамках одной транзакции с платежом. Отдельный сервис (Relay) будет читать эти события и отправлять их в Kafka.
Б. Самовызов транзакционного метода (Self-invocation)
Почему это баг: Метод sendNotification помечен @Transactional(propagation = Propagation.REQUIRES_NEW), но он вызывается внутри метода create через this.sendNotification(p).
Что произойдет в проде: Spring использует AOP-прокси для управления транзакциями. При вызове через this прокси-объект обходится, и аннотация @Transactional игнорируется. Уведомление будет выполняться в той же транзакции, что и основной метод create. Если уведомление упадет, откатится весь платеж (и наоборот).
Как исправить: Вынести sendNotification в отдельный сервис (например, NotificationServiceили новый NotificationManager) и внедрить его в контроллер.
В. Утечка соединений БД (Connection Pool Exhaustion)
Почему это баг: Аннотация @Transactional стоит на всем методе create. Внутри этого метода вызывается antifraud.check(p). Если внешний сервис антифрода работает медленно (например, 2-5 секунд), соединение с базой данных будет удерживаться всё это время.
Что произойдет в проде: При росте нагрузки количество свободных соединений в пуле (HikariCP) быстро закончится. Система начнет выдавать ошибки ConnectionTimeout, и приложение перестанет принимать новые платежи.
Как исправить: Вынести вызов antifraud.check(p) за пределы транзакции. Сначала проверяем антифрод, и только если он "OK", открываем транзакцию для сохранения в БД.
2. Проблемы многопоточности и памяти (Medium/High Severity)
А. Непотокобезопасный кэш и утечка памяти
Почему это баг: private static Map<UUID, Payment> cache = new HashMap<>();
Что произойдет в проде:
Race Condition: HashMap не потокобезопасна. Одновременная запись из разных потоков может привести к бесконечному циклу (зависание CPU) или повреждению структуры данных.
Memory Leak: Карта никогда не очищается. С каждым новым платежом память будет забиваться, пока приложение не упадет с OutOfMemoryError.
Как исправить: Использовать распределенный кэш (Redis) или локальный кэш с политикой вытеснения и TTL (например, Caffeine или Guava Cache).
3. Проблемы кода и данных (Medium Severity)
А. Использование double для финансовых операций
Почему это баг: Тип double использует двоичную плавающую запятую, которая не может точно точно выразить десятичные дроби (например, 0.1 + 0.2 != 0.3).
Что произойдет в проде: Накопление микроскопических ошибок при расчетах. В финансовой системе это недопустимо и приведет к расхождениям в балансах.
Как исправить: Использовать BigDecimal с указанием RoundingMode.
Б. Слабая типизация входных данных
Почему это баг: Использование Map<String, Object> body и ручное приведение типов (double) body.get("amount").
Что произойдет в проде: Если клиент пришлет число как целое (Integer) в JSON, body.get("amount")вернет Integer, и попытка привести его к double вызовет ClassCastException (500 ошибка). Также нет валидации (например, отрицательный amount).
Как исправить: Создать DTO класс (например, PaymentRequest) с использованием @Valid и аннотаций @Positive, @NotNull.
В. Некорректное логирование и обработка ошибок
Почему это баг: e.printStackTrace() и return ... body(e.getMessage()).
Что произойдет в проде:
printStackTrace() не пишет в стандартные системы сбора логов (ELK, Graylog) и не позволяет фильтровать ошибки.
e.getMessage() может содержать конфиденциальные данные (SQL ошибки, пути к файлам, данные БД), что является дырой в безопасности.
Как исправить: Использовать SLF4J (log.error("...", e)), создать @ControllerAdvice для обработки исключений и возвращать клиенту понятный, безопасный код ошибки.
Г. Использование System.out.println
Почему это баг: Это синхронная операция, которая может замедлять работу приложения под нагрузкой.
Что произойдет в проде: Засорение стандартного вывода и потеря возможности управлять уровнем логирования.
Без GPU с 12GB VRAM - это только посмотреть. Что-то толковое от 7/8b моделей можно ожидать начиная с Q5_K_M. Очень хороши оказались gemma-4-12B-it-Q5_K_M и ibm-granite_granite-4.1-8b-Q6_K_L при контексте 32768. На RTX-3060/12GB они выдают около 30 t/s.
Новая модель на более мощном оборудовании нашла 15 проблем:
source_note: “[[код_собеседования_T-Bank.txt]]” processed_at: 2026-08-10 10:16:39 type: analysis
Ниже представлен детальный анализ кода с точки зрения промышленной разработки, архитектуры и эксплуатации в production.
1. Потокобезопасность и утечка памяти кеша (
HashMap)Почему это ошибка:
HashMapне является потокобезопасным. В продакшене один экземпляр приложения обрабатывает десятки/сотни параллельных запросов. Статический кеш разделяется между всеми потоками. Что произойдёт в проде: При конкурентном доступе возникнутConcurrentModificationException, потеря или дублирование записей. Кеш не имеет TTL/eviction, что приведёт к утечке памяти и eventualOutOfMemoryError. Кеш бесполезен при горизонтальном масштабировании (каждый инстанс хранит свои данные). Исправление: Удалить кеш из контроллера. Для кэширования использовать Redis илиCaffeine/Guava Cacheс политикой вытеснения и TTL. В платежной системе кеш часто избыточен.2. Использование
doubleдля денежных суммПочему это ошибка:
doubleработает с плавающей запятой и имеет ошибки округления. Деньги требуют точности до последнего цента/копейки. Что произойдёт в проде: Несоответствие сумм в логах и БД, финансовые расхождения при агрегации,ClassCastExceptionпри получении целого числа из JSON (например,"amount": 1000будет десериализовано вInteger). Исправление: Заменить наBigDecimalна уровне DTO, сущности и репозитория.3. Отсутствие валидации входных данных (
Map<String, Object>)Почему это ошибка:
Mapне имеет схемы. Нет аннотаций@NotNull,@DecimalMin,@Pattern. Контроллер принимает любые поля без проверки. Что произойдёт в проде:NullPointerExceptionпри отсутствии полей,ClassCastExceptionпри некорректных типах, возможность инъекций через поля, отсутствие контроля лимитов и формата счетов. Исправление: Ввести строго типизированный DTO с@Valid, валидаторами и проверкой обязательных полей.4. Слишком широкая транзакция (
@Transactionalнаcreate)Почему это ошибка: Транзакция охватывает не только работу с БД, но и внешние синхронные вызовы (
antifraud,kafka,notifications). Это классическое антипаттерн. Что произойдёт в проде: Долгое удержание соединений БД, исчерпание connection pool, блокировки строк, таймауты на уровне DBA, деградация всей системы при зависании внешних сервисов. Исправление: Вынестиrepo.save()в отдельный метод с короткой транзакцией. Внешние вызовы выполнять асинхронно или через Outbox-паттерн.5. Self-invocation и игнорирование
@TransactionalПочему это ошибка:
this.sendNotification(p)вызывается внутри того же класса. Spring AOP работает через прокси, и прямой вызовthis.минует прокси. Аннотация@Transactional(propagation = REQUIRES_NEW)не применится. Что произойдёт в проде: Уведомление выполнится в той же транзакции, что иcreate. При откате основной транзакции уведомление не дойдёт. При успешном коммите, но паденииnotifications.send(), транзакция откатится, хотя логика могла предполагать отдельную обработку. Исправление: ВынестиsendNotificationв отдельный Spring-бин или использовать@Lazyself-injection.6. Отправка
p.toString()в KafkaПочему это ошибка:
toString()не гарантирует сериализацию, зависит от реализации, не является схемой и не поддерживает эволюцию формата. Что произойдёт в проде: Потребители получат невалидные данные, рассинхронизация downstream-систем, невозможность откатить изменения формата, ошибки парсинга в продакшене. Исправление: Использовать JSON-сериализацию (Jackson) с описанной схемой (JSON Schema / Avro / Protobuf). Формат должен быть версионирован.7. Игнорирование ошибок отправки в Kafka
Почему это ошибка:
KafkaTemplate.send()по умолчанию асинхронный. ВозвращаемыйListenableFutureне обрабатывается. Ошибки сетевых сбоев или недоступности брокера просто логируются и игнорируются. Что произойдёт в проде: Платёж сохраняется в БД, но событие не доходит до Kafka. Потеря данных для аудит-систем, аналитики и downstream-сервисов. “Тихий” отказ. Исправление: ОбрабатыватьCallbackс логированием ошибок и повторной отправкой, либо настраиватьretries/acks=allна уровнеKafkaTemplate. В критичных системах использовать Outbox.8. Синхронный вызов
antifraudбез resilience-механизмовПочему это ошибка: Нет таймаутов, circuit breaker, retry policy. Вызов блокирует поток в рамках транзакции. Что произойдёт в проде: При зависании антифрода — утечка потоков, исчерпание thread pool, cascading failure, таймауты на уровне Nginx/Gateway, недоступность всего API. Исправление: Добавить Resilience4j (
@CircuitBreaker,@Timeout), настроитьfeign/webClientс таймаутами. Рассмотреть асинхронную проверку с последующим обновлением статуса.9. Логирование через
System.out.printlnПочему это ошибка:
System.outне интегрируется с ELK/Grafana/Sentry, не имеет уровней логирования, не структурирован. Что произойдёт в проде: Невозможность мониторинга и алертинга, засорение stdout контейнера, потеря информации при ротации логов, невозможность фильтрации по уровням. Исправление: Использовать SLF4JLoggerс уровнямиINFO/WARN/ERROR. Выносить в отдельный сервис логирования или использовать MDC для трассировки.10. Перехват
Exceptionи возвратe.getMessage()клиентуПочему это ошибка:
e.printStackTrace()не подходит для прода.e.getMessage()может содержать стектрейс, внутренние пути, названия таблиц, SQL-запросы. Что произойдёт в проде: Утечка внутренней информации (OWASP Top 10), плохой UX, невозможность корректной обработки ошибок на клиенте, засорение логов. Исправление: Использовать@ControllerAdvice+@ExceptionHandler. Возвращать стандартизированные ответы (ErrorDTO). Логировать детали на сервере.11. Отсутствие обработки частичных отказов (Payment saved, Kafka failed)
Почему это ошибка: Если
repo.save()прошёл, аkafka.send()упал — состояние рассинхронизировано. Транзакция коммитится, но событие не опубликовано. Что произойдёт в проде: Платёж в БД есть, но downstream-системы о нём не знают. Потеря данных для аудит-логов, аналитики, уведомлений. Восстановление требует ручного вмешательства. Исправление: Паттерн Outbox: сохранять событие в таблицуoutboxв той же транзакции. Отдельный процесс (CDC или периодический опрос) доставляет события в Kafka с гарантией at-least-once.12. Жёстко заданный статус
"PENDING"(String)Почему это ошибка: Использование строковых констант вместо enum prone to typos, не обеспечивает валидацию состояний, усложняет поддержку. Что произойдёт в проде: Ошибки при сравнении статусов, невозможность добавить новые статусы без рефакторинга всех сравнений, рассинхронизация состояний. Исправление: Использовать
enum PaymentStatusс методами валидации переходов.13. Генерация ID в контроллере
Почему это ошибка: Нарушение SRP. Контроллер знает о внутреннем устройстве сущности и механизмах генерации идентификаторов. Что произойдёт в проде: Сложности с миграцией на другие ID-генераторы, дублирование логики, невозможность переиспользовать сущность вне контекста REST. Исправление: Перенести генерацию ID в сервис или настроить
@Idгенерацию в JPA/Hibernate (GenerationType.UUID).14. Возврат сущности
Paymentнапрямую в ответеПочему это ошибка: Сущность может содержать чувствительные данные, внутренние поля, циклические ссылки, которые не должны попадать в ответ. Что произойдёт в проде: Утечка данных, нарушение инкапсуляции, проблемы сериализации (StackOverflowError при циклических ссылках), привязка API к структуре БД. Исправление: Использовать DTO/VO для ответа. Маппинг через MapStruct или вручную.
15. Отсутствие идемпотентности и проверки на дубликаты
Почему это ошибка: Нет
idempotency-key, нет проверки уникальности запроса. Клиент может повторить запрос при таймауте. Что произойдёт в проде: Двойное списание/зачисление, рассинхронизация балансов, финансовые потери, невозможность восстановить состояние после сбоя. Исправление: Добавить заголовокIdempotency-Key, проверять его в БД/Redis, возвращать предыдущий результат при дубликате.ИТОГО: найдено 15 проблем.
Краткая сводка по категориям:
🔴 Транзакции: 4, 5
🔴 Интеграция: 6, 7, 8, 11
🔴 Безопасность/Данные: 2, 3, 10, 14, 15
🔴 Эксплуатация в проде: 1, 9, 12, 13
🟡 Скрытые под нагрузкой: 1, 4, 8, 15
Код требует рефакторинга с переходом на событийную архитектуру (Outbox), внедрением DTO, валидацией, resilience-механизмами и proper error handling.
===
● llama-server.service - Local LLM Server Loaded: loaded (/etc/systemd/system/llama-server.service; enabled; preset: enabled) Active: active (running) since Mon 2026-08-10 10:12:07 +03; 14min ago Invocation: e39cac952b104038baa54931c517f066 Main PID: 13278 (llama-server) Tasks: 16 (limit: 38021) Memory: 1G (peak: 1G) CPU: 1min 33.003s CGroup: /system.slice/llama-server.service └─13278 /usr/bin/llama-server -m /srv/models/Salience-1.5-Pro.Q4_K_S/Salience-1.5-Pro.Q4_K_S.gguf -t 8 -c 32768 -b 768 -ngl 99 --host 0.0.0.0 --port 8080 --parallel 1 --tensor-split 12,12 --temp 0.15 --top-p 0.92 --top-k 50 --min-p 0.05 --repeat-penalty 1.0 -ctk q8_0 -ctv q8_0 -fa on
авг 10 10:16:39 rtx run-llama.sh[13278]: 4.31.299.106 I slot print_timing: id 0 | task 2 | prompt eval time = 1700.81 ms / 607 tokens ( 2.80 ms per token, 356.89 tokens per second) авг 10 10:16:39 rtx run-llama.sh[13278]: 4.31.299.112 I slot print_timing: id 0 | task 2 | eval time = 85718.53 ms / 7575 tokens ( 11.32 ms per token, 88.37 tokens per second) авг 10 10:16:39 rtx run-llama.sh[13278]: 4.31.299.113 I slot print_timing: id 0 | task 2 | total time = 87419.34 ms / 8182 tokens авг 10 10:16:39 rtx run-llama.sh[13278]: 4.31.299.114 I slot print_timing: id 0 | task 2 | graphs reused = 7545 авг 10 10:16:39 rtx run-llama.sh[13278]: 4.31.299.178 I slot release: id 0 | task 2 | stop processing: n_tokens = 8181, truncated = 0
Начинал с простейшего выделенного сервера инференса на одной RTX-3060/12GB + i5-4520/32GB DDR3 для llama-server под MX Linux 25.2 XFCE на обычных GGUF моделях. Это самый бюджетный однопользовательский вариант ( --parallel 1 - не забываем!).
Сейчас в том же корпусе с более мощным БП 2х RTX-3060/12GB, MB ASUS P9X79 LE, i7-4820k, 4x 8GB DDR3 + "самописное" приложение для удалённого управления сервером.
MODEL=“/srv/models/gemma-4-26B‑A4B‑it‑qat‑q4_0-unquantized‑uncensored‑heretic.i1-Q4_K_M/gemma-4-26B‑A4B‑it‑qat‑q4_0-unquantized‑uncensored‑heretic.i1-Q4_K_M.gguf”HOST=“0.0.0.0”PORT=“8080”THREADS=“8”CTX=“36864”BATCH=“768”NGL=“auto”И финал лога по задаче:
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.827.998 I slot print_timing: id 0 | task 0 | prompt eval time = 3136.40 ms / 5265 tokens ( 0.60 ms per token, 1678.68 tokens per second)
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.003 I slot print_timing: id 0 | task 0 | eval time = 102895.95 ms / 5964 tokens ( 17.25 ms per token, 57.96 tokens per second)
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.004 I slot print_timing: id 0 | task 0 | total time = 106032.35 ms / 11229 tokens
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.020 I slot print_timing: id 0 | task 0 | graphs reused = 5940
авг 01 19:35:02 rtx run-llama.sh[197016]: 2.33.828.366 I slot release: id 0 | task 0 | stop processing: n_tokens = 11228, truncated = 0
Спасибо! Хорошая беседа.
Установил из deb-пакета. А вы тестировали его работу?
Мой опыт, характеристики сервера (Hardware Specifications):
GPU:
• Модель: NVIDIA RTX 3060 • VRAM: 12 GB • Тип: GDDR6
CPU:
• Модель: Intel Core i5-4570 • Ядра: 4 • Поток: 4 (без Hyper-Threading) • Архитектура: Haswell (2013)
RAM:
• Объём: 32 GB • Тип: DDR3
Software:
• MX Linux 25.2 XFCE, systemd
• llama-server: используется для инференса
Примечания:
• модель Qwen3.5-9B-UD-Q6_K_XL.gguf 8.16GB
• VRAM 10.57 GB, 36 tokens/sec
• CTX=“98304”, BATCH=“128”, NGL=“48”, EXTRA=“–parallel 1 --no-mmap”
• клиенты - Jan (jan.ai), Thonny, Doka, самописные агенты
• в работе с 02.06.2026
ibm-granite_granite-4.1-8b-Q6_K_L/ibm-granite_granite-4.1-8b-Q6_K_L нашла 10!
Общие рекомендации для продукта
Export
КатегорияРекомендацияПричинаПример реализацииВалидацияДобавить
@Validи DTO для запросаУстранить неопределенность типов и отсутствие проверок@Valid @RequestBody PaymentRequest bodyЛогированиеЗаменитьSystem.outна SLF4JУлучшить контроль уровней и централизацию логовlogger.info("Large payment: {}", amount);ТранзакцииСделатьsendNotificationчастью одной транзакции или очистить кэш при ошибкеИзбежать несогласованного состояния@TransactionalнаsendNotificationКэшИспользовать Spring Cache илиConcurrentHashMapс TTLУстранить гонки и утечки памяти@Cacheable("payments")ИдемпотентностьТребоватьIdempotency-KeyПредотвратить дубликаты платежей@RequestHeader("Idempotency-Key")Обработка исключенийРазделить перехваты на конкретные типыПредоставить точные ошибки клиентамcatch (AntifraudException e) { … }Сообщения KafkaОтправлять структурированный JSON без PIIСоответствовать требованиям безопасностиkafka.send("payments", new PaymentEvent(...))Повторы/Обратный отсчетДобавить Retry и Backoff для асинхронных вызововУстойчивость к временным сетевым сбоям@Retryable(...)МониторингЭкспортировать метрики (создание платежей, успех антифрауда, задержки Kafka)Повысить отказоустойчивость и быстрое реагированиеSpring Actuator, PrometheusПрименение этих исправлений сделает контроллер PaymentController более надежным, масштабируемым, соблюдающим требования безопасности и легко тестируемым в производственной среде.
Jun 9, 2026, 10:42 AM
29 tokens/sec
(3457 tokens)
Вот так ответила локальная gemma-4-12B-it-Q5_K_M:
1. Архитектурные проблемы (High Severity)
А. Проблема "Dual Write" (Консистентность данных)
Почему это баг: Код пытается одновременно обновить базу данных (
repo.save), отправить сообщение в Kafka (kafka.send) и отправить уведомление (notifications.send). Эти системы не связаны в единую распределенную транзакцию.Что произойдет в проде: Если
repo.save(p)пройдет успешно, но Kafka упадет или произойдет сетевой сбой при отправке сообщения, платеж будет создан в БД, но система обработки заказов/логистики его не увидит. И наоборот: сообщение уйдет, а транзакция в БД откатится. Это приведет к "фантомным" платежам или потере заказов.Как исправить: Использовать паттерн Transactional Outbox. Сохраняйте событие (сообщение для Kafka) в ту же БД в рамках одной транзакции с платежом. Отдельный сервис (Relay) будет читать эти события и отправлять их в Kafka.
Б. Самовызов транзакционного метода (Self-invocation)
Почему это баг: Метод
sendNotificationпомечен@Transactional(propagation = Propagation.REQUIRES_NEW), но он вызывается внутри методаcreateчерезthis.sendNotification(p).Что произойдет в проде: Spring использует AOP-прокси для управления транзакциями. При вызове через
thisпрокси-объект обходится, и аннотация@Transactionalигнорируется. Уведомление будет выполняться в той же транзакции, что и основной методcreate. Если уведомление упадет, откатится весь платеж (и наоборот).Как исправить: Вынести
sendNotificationв отдельный сервис (например,NotificationServiceили новыйNotificationManager) и внедрить его в контроллер.В. Утечка соединений БД (Connection Pool Exhaustion)
Почему это баг: Аннотация
@Transactionalстоит на всем методеcreate. Внутри этого метода вызываетсяantifraud.check(p). Если внешний сервис антифрода работает медленно (например, 2-5 секунд), соединение с базой данных будет удерживаться всё это время.Что произойдет в проде: При росте нагрузки количество свободных соединений в пуле (HikariCP) быстро закончится. Система начнет выдавать ошибки
ConnectionTimeout, и приложение перестанет принимать новые платежи.Как исправить: Вынести вызов
antifraud.check(p)за пределы транзакции. Сначала проверяем антифрод, и только если он "OK", открываем транзакцию для сохранения в БД.2. Проблемы многопоточности и памяти (Medium/High Severity)
А. Непотокобезопасный кэш и утечка памяти
Почему это баг:
private static Map<UUID, Payment> cache = new HashMap<>();Что произойдет в проде:
Race Condition:
HashMapне потокобезопасна. Одновременная запись из разных потоков может привести к бесконечному циклу (зависание CPU) или повреждению структуры данных.Memory Leak: Карта никогда не очищается. С каждым новым платежом память будет забиваться, пока приложение не упадет с
OutOfMemoryError.Как исправить: Использовать распределенный кэш (Redis) или локальный кэш с политикой вытеснения и TTL (например, Caffeine или Guava Cache).
3. Проблемы кода и данных (Medium Severity)
А. Использование
doubleдля финансовых операцийПочему это баг: Тип
doubleиспользует двоичную плавающую запятую, которая не может точно точно выразить десятичные дроби (например,0.1 + 0.2 != 0.3).Что произойдет в проде: Накопление микроскопических ошибок при расчетах. В финансовой системе это недопустимо и приведет к расхождениям в балансах.
Как исправить: Использовать
BigDecimalс указаниемRoundingMode.Б. Слабая типизация входных данных
Почему это баг: Использование
Map<String, Object> bodyи ручное приведение типов(double) body.get("amount").Что произойдет в проде: Если клиент пришлет число как целое (Integer) в JSON,
body.get("amount")вернетInteger, и попытка привести его кdoubleвызоветClassCastException(500 ошибка). Также нет валидации (например, отрицательныйamount).Как исправить: Создать DTO класс (например,
PaymentRequest) с использованием@Validи аннотаций@Positive,@NotNull.В. Некорректное логирование и обработка ошибок
Почему это баг:
e.printStackTrace()иreturn ... body(e.getMessage()).Что произойдет в проде:
printStackTrace()не пишет в стандартные системы сбора логов (ELK, Graylog) и не позволяет фильтровать ошибки.e.getMessage()может содержать конфиденциальные данные (SQL ошибки, пути к файлам, данные БД), что является дырой в безопасности.Как исправить: Использовать SLF4J (
log.error("...", e)), создать@ControllerAdviceдля обработки исключений и возвращать клиенту понятный, безопасный код ошибки.Г. Использование
System.out.printlnПочему это баг: Это синхронная операция, которая может замедлять работу приложения под нагрузкой.
Что произойдет в проде: Засорение стандартного вывода и потеря возможности управлять уровнем логирования.
Как исправить: Заменить на
log.info().Резюме (Checklist для рефакторинга):
Заменить
doubleнаBigDecimal.Заменить
Map<String, Object>наPaymentRequestDTO.Вынести
antifraud.checkза пределы@Transactional.Перенести
sendNotificationв отдельный сервис.Удалить
static HashMapи заменить на Redis/Caffeine.Реализовать Transactional Outbox для Kafka.
Заменить
System.outиprintStackTraceна нормальный логгер.Добавить валидацию входных данных.
Jun 9, 2026, 10:30 AM
31 tokens/sec
(3208 tokens)
дополнение: и "дружат" c MCP Filesystem
Без GPU с 12GB VRAM - это только посмотреть. Что-то толковое от 7/8b моделей можно ожидать начиная с Q5_K_M. Очень хороши оказались gemma-4-12B-it-Q5_K_M и ibm-granite_granite-4.1-8b-Q6_K_L при контексте 32768. На RTX-3060/12GB они выдают около 30 t/s.