fa
Feedback
Backend VK Hub

Backend VK Hub

رفتن به کانال در Telegram

Комьюнити VK для бэкендеров. Cамые хардовые кейсы, дискуссии в кругу своих и прямой доступ к нашим экспертам 😎

نمایش بیشتر
1 155
مشترکین
اطلاعاتی وجود ندارد24 ساعت
-17 روز
-1230 روز

در حال بارگیری داده...

کانال‌های مشابه
هیچ داده‌ای
مشکلی وجود دارد؟ لطفاً صفحه را تازه کنید یا با مدیر پشتیبانی ما تماس بگیرید.
اشارات ورودی و خروجی
---
---
---
---
---
---
جذب مشترکین
ژوئن '26
ژوئن '26
+2
در 0 کانال‌ها
مه '26
+17
در 1 کانال‌ها
Get PRO
آوریل '26
+21
در 1 کانال‌ها
Get PRO
مارس '26
+8
در 0 کانال‌ها
Get PRO
فوریه '26
+25
در 1 کانال‌ها
Get PRO
ژانویه '26
+40
در 1 کانال‌ها
Get PRO
دسامبر '25
+427
در 21 کانال‌ها
Get PRO
نوامبر '25
+154
در 0 کانال‌ها
Get PRO
اکتبر '25
+770
در 20 کانال‌ها
تاریخ
رشد مشترکین
اشارات
کانال‌ها
10 ژوئن0
09 ژوئن+1
08 ژوئن0
07 ژوئن0
06 ژوئن0
05 ژوئن0
04 ژوئن+1
03 ژوئن0
02 ژوئن0
01 ژوئن0
پست‌های کانال
🔵 Incus 7.0 LTS — контейнеры и VM до 2031 года Вышел новый LTS-релиз платформы управления контейнерами и виртуальными машина
🔵 Incus 7.0 LTS — контейнеры и VM до 2031 года Вышел новый LTS-релиз платформы управления контейнерами и виртуальными машинами. Среди ключевых изменений — поддержка OCI-контейнеров, встроенное S3-хранилище, новые драйверы хранения и отказ от устаревших cgroupv1 и iptables. 🔵 Bumblebee — защита AI-разработки от supply-chain атак Perplexity открыла исходный код сканера, который анализирует зависимости npm, PyPI и Go Modules без выполнения кода. Инструмент помогает выявлять риски в AI- и developer-инфраструктуре ещё до попадания вредоносных пакетов в пайплайны. 🔵 JavaOne 2026 — курс на HTTP/3 и современную многопоточность На конференции показали ключевые изменения JDK 26: поддержку HTTP/3, развитие Structured Concurrency и новые возможности языка. Основной фокус — производительность, сетевые приложения и упрощение конкурентного программирования. 🔵 JEP 533 — Structured Concurrency становится всё ближе к релизу API для управления группами связанных задач вышло на очередной этап превью. Подход упрощает отмену операций, обработку ошибок и делает многопоточный код заметно предсказуемее. 🔵 JEP 534 — компактные заголовки объектов в HotSpot OpenJDK планирует включить Compact Object Headers по умолчанию. Изменение уменьшает потребление памяти и может дать дополнительный выигрыш в производительности за счёт лучшей работы процессорного кэша. 🔵 Go SIM DB — база данных для AI-агентов вместо LSP В сообществе обсуждают новый подход к анализу кодовых баз: SQLite-совместимое хранилище, оптимизированное для работы AI-инструментов. Тренд показывает, как экосистема разработки начинает адаптироваться под агентные сценарии. #backendvkhub #дайджест

2
Классический сценарий в проде: запрос не меняли, данные те же, а время выросло в разы — и не сразу, а после некоторого числа+5
Классический сценарий в проде: запрос не меняли, данные те же, а время выросло в разы — и не сразу, а после некоторого числа выполнений. Причина почти всегда в том, как PostgreSQL кэширует планы за параметризованными запросами. #backendvkhub #postgresql
321
3
Проблема двойной записи и transactional outbox Типичная задача: сервис создаёт заказ и должен и сохранить его в базу, и сообщ
Проблема двойной записи и transactional outbox Типичная задача: сервис создаёт заказ и должен и сохранить его в базу, и сообщить о нём другим сервисам — через Kafka, RabbitMQ или вызов API. Очевидное решение выглядит так: db.insert(order) # запись в БД kafka.publish("order.created", order) # публикация события Этот код содержит баг, который не виден на тесте и проявляется под нагрузкой или при сбоях. Две операции идут в две разные системы, и общей транзакции между ними нет. Разберём поведение при сбое. Если процесс упадёт после db.insert, но до kafka.publish — заказ в базе есть, события нет, другие сервисы о заказе не узнают. Если поменять порядок и публиковать первым — при падении после publish событие ушло, а заказа в базе нет: подписчики обработают заказ, которого не существует. Любой порядок двух записей в две системы оставляет окно, в котором состояние рассинхронизировано. Это и есть dual-write problem. Сетевой ретрай не спасает. Брокер может принять сообщение, но ответ потеряется по таймауту — сервис не знает, опубликовалось ли событие, и повторная отправка либо продублирует его, либо снова упрётся в ту же неопределённость. Корень проблемы — попытка получить атомарность поверх двух систем без распределённой транзакции. Решение — свести задачу к одной системе, где атомарность уже есть. У базы есть транзакции; значит, факт «событие нужно отправить» должен записываться в ту же базу и в той же транзакции, что и сам заказ. Это паттерн transactional outbox. К таблицам данных добавляется таблица исходящих сообщений: id bigserial PRIMARY KEY, topic text NOT NULL, payload jsonb NOT NULL, created_at timestamptz DEFAULT now(), published_at timestamptz ); Сервис записывает заказ и сообщение одной транзакцией: with db.transaction(): db.insert(order) db.insert_outbox("order.created", order) Сбой между двумя записями теперь невозможен: либо транзакция коммитится целиком — и заказ, и строка в outbox, либо откатывается целиком. Состояние БД всегда согласовано. Остаётся доставить то, что лежит в outbox, в брокер. Этим занимается отдельный процесс — релей. Он читает неопубликованные строки и отправляет их: rows = db.query( "SELECT * FROM outbox WHERE published_at IS NULL " "ORDER BY id LIMIT 100" ) for row in rows: kafka.publish(row.topic, row.payload) db.execute( "UPDATE outbox SET published_at = now() WHERE id = %s", row.id, ) Здесь важно то, что релей может опубликовать сообщение в Kafka и упасть до того, как проставит published_at. На следующем проходе он отправит то же сообщение снова. Outbox гарантирует доставку at-least-once — каждое событие дойдёт хотя бы раз, но возможны повторы. Поэтому потребители событий обязаны быть идемпотентными: повторная обработка того же события не должна давать повторный эффект. Это связывает outbox с идемпотентностью на стороне потребителя — первый паттерн гарантирует, что событие не потеряется, второй, что повтор не навредит. У polling-релея есть цена, он постоянно опрашивает таблицу. Альтернатива — change data capture: релей читает не таблицу, а WAL базы (через Debezium и подобные инструменты) и реагирует на коммиты в outbox без опроса. Механика доставки другая, контракт тот же: запись данных и события атомарна, доставка — at-least-once. Практический вывод очень простой. Как только в коде рядом стоят запись в базу и обращение к внешней системе — брокеру, платёжному шлюзу, другому сервису, — это уже кандидат на dual-write баг. Если обе операции должны произойти вместе, одну из них нужно свести к записи в ту же базу, а фактическое действие вынести в отдельный надёжный процесс. #backendvkhub
483
4
До 18-й версии PostgreSQL читал страницы с диска синхронно: на каждый промах кеша вызывался блокирующий pread(), бэкенд остан
До 18-й версии PostgreSQL читал страницы с диска синхронно: на каждый промах кеша вызывался блокирующий pread(), бэкенд останавливался и ждал ответ ядра. На AWS EBS gp3 это около 1–2 мс на блок, и большое последовательное сканирование упиралось не в диск, а в накопленное ожидание. Спасались привычным набором: увеличенный shared_buffers, parallel workers, реплики на чтение. В 18 появилась подсистема AIO и параметр io_method с тремя значениями: sync, worker (по умолчанию), io_uring. Параметр требует рестарта. io_method = io_uring io_workers = 3 # учитывается только для worker effective_io_concurrency = 16 # дефолт в 18, было 1 io_combine_limit = 128kB sync повторяет поведение 17 — для отката, если новая подсистема даёт регрессию. worker поднимает фоновые процессы, принимающие read-запросы через shared memory; бэкенд кладёт пачку запросов и продолжает обрабатывать предыдущие страницы. Издержки — context switch и конкуренция за очередь. io_uring обращается к ядру напрямую через ring buffer Linux 5.1+, без syscall на каждый блок; требует сборки с --with-liburing и kernel.io_uring_disabled = 0. Бенчмарки pganalyze и CYBERTEC на c7i.8xlarge с EBS показывают прирост 2-3× по throughput на cold-cache sequential scan при переходе с sync на io_uring. На локальном NVMe эффект скромнее: BetterStack получили 24% (2913 → 2221 мс), PlanetScale на своих Metal-серверах разницы между worker и io_uring практически не увидели, диск перестал быть узким местом. Для наблюдения появилось два инструмента. Функция pg_get_aios() возвращает все запланированные операции с их состоянием: FROM pg_get_aios(); В pg_stat_io добавились разрезы по асинхронным чтениям — видно, сколько байт прошло мимо синхронного пути и сколько времени ушло на ожидание completion. Еще есть несколько мест, где легко ошибиться. Во-первых, AIO работает только на чтения: WAL и обычные writes остались синхронными. Во-вторых, EXPLAIN ANALYZE может занижать I/O time, потому что часть работы делается в воркерах и backend этого не видит, — для диагностики берите pg_stat_io. В-третьих, effective_io_concurrency теперь напрямую управляет числом параллельных read-ahead запросов: на network storage его имеет смысл повышать до 32–64, на локальном NVMe оптимум обычно меньше. Neon и Supabase пока держат io_method = sync — их prefetch-механика интегрирована с собственным storage layer и переписывается под новый интерфейс отдельно. Если обновляетесь на 18 на своих серверах, начните с worker, снимите профиль через pgbench и pg_stat_io, и только потом переключайтесь на io_uring, если у storage остался запас. #backendvkhub #asyncio #postgresql
455
5
Ранее мы кратко писали о том, что в марте вышла Java 26 с 10 JEP. Structured Concurrency, Scoped Values, Flexible Main Method+6
Ранее мы кратко писали о том, что в марте вышла Java 26 с 10 JEP. Structured Concurrency, Scoped Values, Flexible Main Methods, Derived Record Creation, HTTP/3, улучшения G1 GC. Релиз платформенный, ускоряет JVM и упрощает конкурентность. ➡️ Разобрали подробности в карточках. #backendvk #java26
609
6
Джависты, помогите по-братски примите участие в большом исследовании! 💙 Вместе с JUG Ru Group составляем полную картину совр
Джависты, помогите по-братски примите участие в большом исследовании! 💙 Вместе с JUG Ru Group составляем полную картину современной Java-разработки. Пожалуйста, пройдите опрос, он займёт не больше 20 минут. По итогам мы сделаем большой отчёт и поделимся результатами с вами! P. S. Среди участников опроса JUG Ru Group разыграет 5 офлайн- и 10 онлайн-билетов на свои конференции. Ваш шанс 😏
547
7
python tooling на Rust uv, ruff, ty — три инструмента, которые заменяют солянку из pyenv, pip, venv, conda, Poetry, Black, Fl
python tooling на Rust uv, ruff, ty — три инструмента, которые заменяют солянку из pyenv, pip, venv, conda, Poetry, Black, Flake8, isort и mypy. Все три написаны на Rust, потому что сам python медленно делает то, что должно быть быстрым — разрешение зависимостей, парсинг AST и статический анализ. Когда pip install занимает минуту, а полный линтинг работает полминуты, то разработчик либо отключает проверки, либо привыкают к медленному CI. Использование Rust устраняет этот компромисс. На типичном проекте pip install -r requirements.txt занимает 60-120 секунд, uv sync на том же наборе 5-10 секунд. ruff check сканирует сотни тысяч строк за секунду, заменяя Flake8, Black и isort одним бинарником. ty check проверяет 50к строк за 150 мс, в то время как mypy на том же коде будет работать больше секунды. ➡️ Единый стек # было pip install -r requirements.txt black . && flake8 . && isort . mypy . # стало uv sync uvx ruff check --fix . uvx ty check . Инструменты Astral объединены конфигурацией через pyproject.toml и лаунчером uvx. Workspaces для монорепозиториев заимствованы из Cargo: несколько пакетов, один uv.lock, консистентные зависимости между сервисами. К началу 2026 года uv стал дефолтным инсталлером во многих CI-пайплайнах и сократил шаг установки с двух минут до десяти секунд. Ruff включает 800+ линт-правил с автофиксом и встроенный LSP-сервер на Rust (стабилизирован в 0.5.3). Ty работает как language server с навигацией, подсказками типов и автоимпортами. Одна команда для установки окружения, одна для линтера, одна для проверки типов. Lockfile один на весь монорепозиторий. ➡️ Ограничения Ty в бете и пока не поддерживает плагины для Pydantic, Django, SQLAlchemy. Глобальный кэш uv разрастается до 20 ГБ за год. Кроме того, uv строго разрешает зависимости, поэтому проекты с грязной историей pip freeze могут не собраться и требуют чистки freeze-файлов. Результат работы Ruff практически идентичен связке black + flake8 + isort, но при миграции на него диффы в гите всё же появятся. Astral куплена OpenAI в марте 2026. Инструменты open source, но зависимость от одного вендора необходимо учитывать при выборе инфраструктуры. Если заводите новый проект, то смело берите uv + ruff + ty с первого дня. Миграцию же старого проект лучше начинать с uv и ruff, а ty подключать параллельно с mypy с флагом --add-ignore и переводить ошибки по мере роста уверенности. 👇 А вы уже перешли на связку uv + ruff + ty? #backendvk #python #pythontooling
662
8
Row-Level Security в PostgreSQL Мультитенантные приложения обычно изолируют данные через WHERE tenant_id = ? в каждом запросе+5
Row-Level Security в PostgreSQL Мультитенантные приложения обычно изолируют данные через WHERE tenant_id = ? в каждом запросе. Это работает ровно до тех пор, пока кто-то не забывает написать этот фильтр. Один новый endpoint без WHERE — и данные одного клиента уйдут другому. С Row-Level Security фильтр живёт в базе, а не в коде, и применяется автоматически к каждому запросу — что бы приложение ни написало. #backendvk #postgresql #rowlevelsecurity
712
9
Kronk — Go SDK, который встраивает LLM прямо в приложение Ardan Labs выпустили Kronk — Go SDK для локального запуска LLM прям
Kronk — Go SDK, который встраивает LLM прямо в приложение Ardan Labs выпустили Kronk — Go SDK для локального запуска LLM прямо внутри приложения. Стандартная схема работы Go с моделями — отправить HTTP-запрос в Ollama или OpenAI и получить ответ. То есть рядом с приложением всегда висит отдельный процесс, к которому ты ходишь по сети. Kronk делает иначе: llama.cpp встраивается прямо в Go-бинарь через модуль yzma — никакого отдельного сервера, модель крутится в том же процессе. krn, err := kronk.New(model.Config{ ModelPath: "/models/llama-3.2.gguf", }) resp, err := krn.Chat(ctx, model.D{ Messages: []model.Message{ {Role: "user", Content: "Объясни structured concurrency"}, }, }) API похож на OpenAI — Chat, ChatStreaming, Embeddings, Rerank, Tokenize. Если работали с OpenAI SDK, синтаксис знакомый, только всё локально. ➡️ Полный RAG в одном бинаре Главная идея в том, чтобы убрать модельный сервер как отдельную архитектурную единицу. Весь RAG пайплайн: чтение документов, создание эмбеддингов, поиск, ответ — можно упаковать в один бинарь. Без Ollama рядом, без HTTP между компонентами, без зависимости от провайдера. ➡️ Поддержка моделей и ускорения Работает с GGUF-моделями — тот же формат что у Ollama, больше 147k моделей на Hugging Face. Hardware acceleration есть: CUDA, Metal, Vulkan, ROCm, OpenCL. Поддерживаются текстовые модели, vision и аудио. Через GBNF-грамматики можно жёстко ограничить формат вывода, применимо, когда нужен структурированный JSON без галлюцинаций в схеме. ➡️ Сервер — опционально Сервер в проекте тоже есть и совместим с OpenWebUI, Cline и Claude Code,если нужен привычный endpoint для разработки. Но авторы честно говорят: долгосрочная цель — убрать сервер как отдельную сущность, твоё приложение и должно быть сервером. Проект не v1, молодой. Но за ним Ardan Labs — авторы Ultimate Go, не студенческий эксперимент. По заявлению авторов, через yzma покрыто уже 94% функциональности llama.cpp. Как тебе такое, Сергей? «Как и следовало ожидать, ИИ добрался и до бэкенда. Конечно, приложения для ИИ на Go писали и раньше, но, так как львиная доля кода для машинного обучения реализована на Python, для написания ИИ-шного приложения надо было как-то взаимодействовать с Python — через удаленный API или напрямую с Python'овскими модулями через application binary interface. Это было довольно муторно. С появлением Kronk встраивание AI в Go-шные программы упростилось донельзя, теперь для этого не надо ваять никаких переходников для ML-ных библиотек на Python, теперь локальная LLM и все средства для работы с ней есть прямо в вашей любимой Goшке. Это как Lua, но для AI — можно встроить куда угодно. Как заявляют авторы, Kronk поддерживает свыше 94% фич llama.cpp — популярного инструмента для поднятия локальной LLM. В комплекте идут примеры для реализации разных кейсов работы с AI, от простого чата с моделью, до работы с аудио и изображениями, так что теперь начать писать на Go программы, работающие с ИИ, стало гораздо проще», — отметил Сергей Лебедев, старший backend-разработчик VK. А как вам такой подход? Хотели бы отказаться от отдельного LLM-сервера и держать модель прямо внутри приложения — или текущая архитектура с API вам кажется надёжнее? Обсудим в комментариях 👇 #backendvk #go
697
10
🔵nginx 1.30 — MPTCP, sticky sessions и HTTP/2 к бэкендам Multipath TCP, шифрование TLS-параметров через ECH, привязка клиент
🔵nginx 1.30 — MPTCP, sticky sessions и HTTP/2 к бэкендам Multipath TCP, шифрование TLS-параметров через ECH, привязка клиентов к серверам и HTTP/2 при проксировании к бэкендам. Криптоключи загружаются из аппаратных токенов. 🔵CVE-2025-24859 в Apache Roller — CVSS 10.0 Злоумышленники сохраняют доступ через активные сессии после смены пароля. Исправлено в 6.1.5: при изменении учётных данных все сессии инвалидируются централизованно. 🔵Solod — подмножество Go с ручным управлением памятью Транскомпилируется в C11, отказывается от GC в пользу ручного управления памятью. Дает прирост производительности в ряде сценариев, но требует аккуратной работы с указателями. 🔵OpenJDK: фокус сместился на тестирование JDK 27 После релиза Java 26 команда переключилась на JDK 27. Обсуждаются удаление устаревших локализаций и переход JavaFX на Metal-рендеринг на macOS. 🔵Gitea 1.26 — параллельные Actions и переход на Vite Три исправленных уязвимости, параллельное выполнение Actions с кастомными токенами и ускорение работы с большими репозиториями. Фронтенд переехал на Vite. 📌 Новые статьи от инженеров VK на Хабр: 🔵Проектирование микросервисов на Go: типичные сложности и лучшие практики 🔵Реализация автоудаления блокирующих сессий в MS SQL #дайджест #backendvk
530
11
🍃 Бэкенд без воды, пиво — без открывашек, так прошел большой весенний Java meetup Провели митап для джавистов, сфокусировали
🍃 Бэкенд без воды, пиво — без открывашек, так прошел большой весенний Java meetup Провели митап для джавистов, сфокусировались на практике: обсудили архитектурные подходы, масштабирование сервисов, оптимизацию и observability— без лишней теории, только реальные кейсы и рабочие инструменты из продакшена от спикеров VK и сообщества Spring АйО. Без неформальной части тоже не обошлось. Позвали choco_nik — сначала он кратко рассказал про подходы, а потом началась практика: открывали пиво всем, что попадалось под руку (да, даже роутером). Зафиналили баттлом на скорость, где главный приз — ящик пива. Итог простой: сильный технический контент + живое общение + немного фанового безумия = митап, на который хочется возвращаться. #backendvk #javameetup #java #пивобезалкогольное
0
12
🍿 Команда VK Видео поделилась опытом перехода с монолита на микросервисы на Go под высокую нагрузку. Ниже — конкретные техни+5
🍿 Команда VK Видео поделилась опытом перехода с монолита на микросервисы на Go под высокую нагрузку. Ниже — конкретные техники из статьи, которые реально влияют на производительность. #backendvk #VKВидео
0
13
Context в Go — это не просто способ передать данные context.Context в Go используют для двух вещей: передать данные через сте
Context в Go — это не просто способ передать данные context.Context в Go используют для двух вещей: передать данные через стек вызовов и управлять временем жизни операций. Вторая часть важнее, и именно она чаще всего игнорируется. Когда HTTP-запрос отменяется — клиент закрыл соединение, таймаут истёк — контекст этого запроса отменяется. Это сигнал: всё, что работало в рамках этого запроса, должно остановиться. Запросы в БД, вызовы внешних API, фоновые горутины. Если контекст не прокидывается — ничего не останавливается. // ❌ Запрос к БД продолжается даже если клиент ушёл func handleRequest(w http.ResponseWriter, r *http.Request) { result, err := db.QueryRow("SELECT ...", id).Scan(&data) // ... } // ✅ Запрос к БД отменяется вместе с HTTP-запросом func handleRequest(w http.ResponseWriter, r *http.Request) { result, err := db.QueryRowContext(r.Context(), "SELECT ...", id).Scan(&data) // ... } Разница между QueryRow и QueryRowContext — один параметр. Но без него при пике нагрузки, когда клиенты начинают закрывать соединения по таймауту, база продолжает обрабатывать уже ненужные запросы. Отдельная ловушка — создать новый контекст там, где надо пробросить существующий: // ❌ Создали новый контекст -- потеряли отмену, потеряли трейсинг func (s *Service) GetUser(ctx context.Context, id string) (*User, error) { return s.repo.Find(context.Background(), id) // ctx проигнорирован } // ✅ func (s *Service) GetUser(ctx context.Context, id string) (*User, error) { return s.repo.Find(ctx, id) } Такой баг не видно в тестах — context.Background() работает нормально. Виден в продакшне, когда трейс обрывается на границе сервиса или горутины не завершаются при shutdown. Правило для горутин: если запускаешь горутину внутри handler — либо передай контекст, либо отвяжи её явно через context.WithoutCancel. Без этого горутина либо не реагирует на отмену, либо падает, когда родительский контекст отменяется раньше, чем она завершилась: // Фоновая задача которая должна пережить запрос go func() { ctx := context.WithoutCancel(r.Context()) // сохраняет данные, убирает отмену s.asyncJob(ctx, data) }() context.WithoutCancel появился в Go 1.21 — создаёт контекст, который наследует данные из родителя, но не наследует отмену. До 1.21 для этого использовали context.Background() с ручным копированием нужных значений, что было плохой практикой. Ещё один момент: context не для хранения бизнес-данных. ctx.Value — для инфраструктурных вещей: trace ID, user ID для логов, deadline. Бизнес-параметры передаются явными аргументами. Если в context хранятся данные, которые влияют на бизнес-логику — это признак плохой архитектуры. #backendvk #go #context
0
14
readOnly = true на @Transactional выглядит как подсказка-документация — мол, этот метод не меняет данные. На самом деле, он м+5
readOnly = true на @Transactional выглядит как подсказка-документация — мол, этот метод не меняет данные. На самом деле, он меняет поведение Hibernate и драйвера на уровне, который реально влияет на производительность. #backendvk #spring #transactional
0
15
Kafka доставляет сообщения at-least-once. Это значит, что каждое сообщение будет доставлено минимум один раз, но, возможно, б
Kafka доставляет сообщения at-least-once. Это значит, что каждое сообщение будет доставлено минимум один раз, но, возможно, больше. Большинство это знают, но продолжают писать consumer, которые обрабатывают дубликаты как ошибку. Дубликаты — это нормальный режим работы. Consumer получил сообщение, обработал его, записал результат в БД, а потом упал до того как закоммитил offset. При перезапуске или перебалансировке он получит это же сообщение снова. Если consumer при повторной доставке создаст вторую запись в таблице заказов или спишет деньги дважды — это не проблема Kafka, это отсутствие idempotency на стороне приложения. Самый простой способ — сделать таблицу обработанных сообщений: CREATE TABLE processed_messages ( message_id TEXT PRIMARY KEY, topic TEXT NOT NULL, partition INT NOT NULL, offset BIGINT NOT NULL, processed_at TIMESTAMPTZ DEFAULT now() ); В consumer перед обработкой проверяем, видели ли это сообщение: @KafkaListener(topics = "orders") @Transactional public void handle(OrderEvent event) { String msgId = event.getEventId(); if (processedMessages.existsById(msgId)) { return; // дубликат пропускаем } // бизнес-логика orderService.createOrder(event); // записываем факт обработки в той же транзакции processedMessages.save(new ProcessedMessage(msgId, ...)); } Очень важен порядок операций. Бизнес-логика и запись в processed_messages должны быть в одной транзакции БД. Если сначала записать processed_messages, а потом выполнить бизнес-логику, и бизнес-логика упадёт — сообщение будет помечено как обработанное, хотя на самом деле нет. Если сначала бизнес-логика, потом processed_messages, и consumer упадёт между ними — при следующей доставке сообщение будет обработано повторно, но проверка это поймает. Kafka transactions с enable.idempotence=true и transactional.id решают дубликаты только на уровне Kafka. То есть если consumer читает из одного топика и пишет в другой — транзакции помогут. Если consumer пишет в реляционную БД — Kafka транзакции здесь ничего не гарантируют, потому что между Kafka и PostgreSQL нет единой транзакции. И еще: message_id должен быть частью самого события, а не генерироваться consumer. Offset + partition формально уникален, но при смене схемы топика или миграции может повести себя непредсказуемо. Лучше чтобы producer явно клал UUID в тело события: { "eventId": "550e8400-e29b-41d4-a716-446655440000", "orderId": 42, "amount": 1500 } Таблица processed_messages растёт. Строки старше разумного retention можно удалять — события, которые были в топике N дней назад, уже не будут доставлены повторно. Это не бесплатно, но дешевле чем разбираться с задвоенными платежами в продакшне.
0
16
В Go 1.26 полностью переписана подкоманда go fix. Одна из ключевых новаций — это директива //go:fix inline для автоматической+5
В Go 1.26 полностью переписана подкоманда go fix. Одна из ключевых новаций — это директива //go:fix inline для автоматической миграции API на уровне исходного кода. Разработчик добавляет директиву //go:fix inline к функции, после чего go fix заменяет вызовы. #backendvk #go #gofixinline
0
17
🍃 Весна в бэкенде: собираем Java-комьюнити на митап! Солнце светит ярче, а значит — самое время выйти из зимней спячки и пос
🍃 Весна в бэкенде: собираем Java-комьюнити на митап! Солнце светит ярче, а значит — самое время выйти из зимней спячки и послушать доклады. 22 апреля приглашаем Java-разработчиков на большой весенний митап: встречаемся гибридно — в нашем московском офисе и онлайн. Что в программе? 🔵Экспертный блок: три доклада от инженеров VK и Spring АйO. 🔵Мастер-класс: прокачаем самый летний навык, который оценят на любой вечеринке. 🔵Нетворкинг-зона: фуршет, неформальное общение и возможность обсудить доклады. Формат встречи создан для живого диалога: задавайте вопросы спикерам, делитесь опытом и заряжайтесь идеями. Регистрация уже открыта. Ждём вас и офлайн, и онлайн!
0
18
Сегодня знакомимся с Сергеем Зелёным, бэкенд-техлидом ВКонтакте. Когда-то Сергей был инженером по видеосвязи и фотографом, а
Сегодня знакомимся с Сергеем Зелёным, бэкенд-техлидом ВКонтакте. Когда-то Сергей был инженером по видеосвязи и фотографом, а сейчас руководит сразу двумя командами ВКонтакте. Обо всём этом он расскажет сам. ➡️ С чего ты начинал свой путь в IT? Свой путь я начал с совмещения двух полярных сфер. Днём в строгом костюме я организовывал совещания президента и премьера с губернаторами — прошёл путь от специалиста техподдержки до инженера по видеосвязи и спутниковым сетям. А по ночам я работал фотографом: снимал в клубах и для журналов, участвовал в нескольких выставках, в том числе за рубежом. После переезда осознал, что профессия фотографа слишком зависит от локации: ты сразу теряешь наработанную базу клиентов и каждый раз вынужден начинать всё с нуля. Я решил сменить сферу и ушёл в разработку, когда это ещё не было мейнстримом. Обучался сам: пока ездил из Подмосковья в Москву, смотрел видеокурсы в автобусах и метро, читал книжки и программировал вечерами. ➡️ Когда и как ты пришёл в VK? Как программист я успел поработать на международный стартап и большой российский маркетплейс. Получил разный опыт: от загрузки файлов по FTP и их редактирования в Notepad++ до современной разработки с фокусом на продукт, опорой на данные и интервью с пользователями. В VK пришёл летом 2023 года в сервис объявлений Юла. Хотел попасть в бигтех, чтобы получить новый опыт. ➡️ Что помогло адаптироваться? Открытость. Чтобы быстрее выстроить связи, я специально выбрал офисный режим и постоянно знакомился с другими сотрудниками. Теперь мои коллеги считают, что я знаю весь офис. ➡️ Чем ты занимаешься внутри компании? Сейчас я — техлид продуктовой разработки ВКонтакте. Управляю командой, контролирую появление новых фич. Как тимлид я руковожу командой бэкенда, помогаю ребятам расти. В нашей зоне ответственности — Уведомления и Соцграф. Например, мы работаем над оптимизацией количества пуш-уведомлений, стараемся сделать их более ценными, чтобы пользователи заходили в приложение ради действительно важной информации. ➡️ Чем тебе нравится заниматься вне работы? Нравится посещать разные мероприятия: концерты, оперу, стендапы, экскурсии. Стараюсь наполнять жизнь спонтанностью — могу увидеть интересный мастер-класс (недавно проходил обучение приготовлению стейков) или поездку в Никола-Ленивец с незнакомыми ребятами и сразу записаться. Люблю горы. Как-то раз в Армении я за один день поднялся на три вершины высотой свыше 4000 метров (и встретил там медведя). Также учусь хип-хопу: ранее танцы помогли мне справиться со стеснительностью. Был максимально зажат в общении с незнакомыми людьми, но прошёл путь от простого качания головой под ритм до выхода первым на танцпол на вечеринках на 2000 человек. #backendvk #команда
0
19
Postgres часто используют как основную БД, и когда нужны фоновые задачи — возникает соблазн добавить Redis или RabbitMQ. Но д+5
Postgres часто используют как основную БД, и когда нужны фоновые задачи — возникает соблазн добавить Redis или RabbitMQ. Но для большинства задач этого не нужно: FOR UPDATE SKIP LOCKED превращает обычную таблицу в надёжную очередь с параллельными воркерами и без deadlock. #backendvk #postgresql #concurrency
0
20
🔵Go — source-level inliner и //go:fix inline Новый механизм позволяет автоинлайнить вызовы через go fix, помогая авторам биб
🔵Go — source-level inliner и //go:fix inline Новый механизм позволяет автоинлайнить вызовы через go fix, помогая авторам библиотек оптимизировать API без ломки обратной совместимости. Важный шаг к безопасным массовым миграциям зависимостей. 🔵Cozystack 1.0 — self-hosted PaaS поверх Kubernetes Платформа для развёртывания managed-сервисов (включая БД и Kafka) с мультикластерной архитектурой и собственным storage/network стеком. Полезна для платформенных команд и private-cloud инфраструктур. 🔵Java 26 — HTTP/3 и structured concurrency В стандартный HttpClient добавлен HTTP/3, ускорен G1 GC и расширен pattern matching. Релиз усиливает позиции Java в high-throughput сервисах. 🔵SnakeYAML — критическая RCE-уязвимость Уязвимость позволяет выполнять произвольный код при десериализации недоверенных YAML-данных. Зависимость рекомендуется срочно обновить или ограничить типы. 🔵Apache Kafka — десктоп-клиент без JVM: kafkalet Появился лёгкий GUI-клиент на Go с поддержкой Schema Registry, фильтрации потоков и профилей окружений. Удобный инструмент для локальной диагностики и работы с кластерами без тяжёлого стека. 🔵FFmpeg — удалённый GPU через TCP (ffmpeg-over-ip) Проект позволяет запускать транскодирование на удалённой машине с GPU без NFS/SMB, проксируя I/O через один TCP-порт. Полезно для media-пайплайнов и распределённых compute-сетапов. 📌 Новая статья от инженеров VK на Хабр: От события до дашборда в облаках: практика по созданию потоковой платформы на Kubernetes #дайджест #backendvk
0