Backend Portal | Программирование
17.4K subscribers
1.45K photos
136 videos
40 files
1.28K links
Присоединяйтесь к нашему каналу и погрузитесь в мир Backend-разработки

Связь: @devmangx

РКН: https://clck.ru/3FobxK
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
Этот инструмент экономит время на ручном прописывании API.
Вставляешь JSON — на выходе сразу получаешь TypeScript-код.

http://app.quicktype.io

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤯32
This media is not supported in your browser
VIEW IN TELEGRAM
Курс по git на русском прямо в браузере

Проходишь шаги от базовых команд до веток и коммитов, всё через практику.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍2
Акторная модель это, по сути, подход, где между процессами/потоками (или акторами) нет общей памяти.

Разные акторы общаются, передавая сообщения. Каждый актор владеет своим состоянием, обрабатывает по одному сообщению за раз и общается с другими только через асинхронные сообщения. Локов нет.

Rust красиво ложится на это через один только трейт Send в трейте актора.

Send означает, что актора можно безопасно перемещать в другой поток. Sync не нужен, потому что ссылка на актора никогда не шарится между потоками. К актору всегда имеет доступ только один поток, и это убирает гонки данных на этапе компиляции.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Media is too big
VIEW IN TELEGRAM
Разработчик выложил проект ShadowStream, систему отслеживания изменений в базе данных (CDC), построенную на PostgreSQL logical replication.

Цель проекта — ловить любые изменения в реальном времени и передавать их в потоковую инфраструктуру.

Как это работает:

- изменения в базе (INSERT, UPDATE, DELETE) сразу перехватываются через logical replication
- события сериализуются в Protobuf и отправляются в Redis Streams для быстрого доступа
- параллельно те же данные архивируются в Kafka для надежного хранения
- Kafka использует grouped consumer'ов: два обработчика работают параллельно, плюс резервная группа с отдельным offset
- поверх всего в Django Admin добавлена визуализация gRPC-вызовов

Исходники открыты на GitHub

Проект может пригодиться тем, кто работает с потоковой обработкой данных, аналитикой, репликацией или интеграцией микросервисов. 🙂

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍123🔥3
Представь, ты стримишь изменения из Postgres в Elasticsearch на Go. В деве всё работает стабильно. Потом растёт трафик, и внезапно сервис перестаёт вывозить…

Профилируешь и упираешься в JSON-сериализацию.

Каждый документ, который уходит в Elasticsearch, нужно закодировать. Когда событий тысячи в секунду, эти микросекунды начинают быстро накапливаться. Стандартная encoding/json удобная, но она сильно завязана на рефлексии.

Рефлексия удобна, потому что универсальна, но за неё платишь скоростью. Это почти всегда медленнее, чем когда структура известна на этапе компиляции.

И да, в любом языке почти никогда нет “одной библиотеки на задачу”. Люди постоянно переписывают одно и то же, и нередко делают быстрее, чем дефолт из коробки.

Так что вместо стандартной encoding/json можно взять пакет jsoniter. По бенчмаркам: декодирование среднего payload у стандартной либы занимает 35 510 ns/op и делает 99 аллокаций. У jsoniter это 5 623 ns/op и всего 3 аллокации. То есть больше чем в 6 раз быстрее и на 97% меньше аллокаций.

Дичь.

Это не значит, что надо срочно переписывать код. Но если у тебя JSON-сериализация в топе на пламеграфе :) переход на jsoniter (или на то, что в текущий момент самое эффективное) может дать ощутимый прирост

И такое есть вообще в каждом языке и почти под любую работу. Пусть этот пост будет напоминалкой: иногда стоит смотреть дальше дефолтов :)

Надеюсь, пригодится. 👍

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
14🔥4😁1
Если ты активно пользуешься JavaScript Intl API, можно выжать немного больше производительности.

Зацени intl-formatter: маленькая обертка, которая добавляет мемоизацию без настроек и при этом сохраняет тот же интерфейс Intl API. В AdonisJS мы такое используем уже много лет.

Бенчмарки: https://github.com/poppinss/intl-formatter?tab=readme-ov-file#benchmarks

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
Проверяет наличие электронной почты без отправки письма.

https://github.com/reacherhq/check-if-email-exists/

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2
Поздравляем, вы на 1 шаг ближе к работе мечты 🥳

Осталось только прочитать этот пост, подписаться на канал и откликнуться на вакансию 😉

Avito Career — место, где Авито делится актуальными вакансиями и стажировками для бэкенд-разработчиков.

Подписывайтесь, чтобы найти ту самую работу
3🤔2
Практический Docker Roadmap

Она включает более 50 практических заданий, дополненных десятками визуальных разборов и несколькими теоретическими глубокими погружениями. На данный момент вы можете изучить:

- Как запускать разные типы контейнеров (веб-приложения, CLI-утилиты, базы данных и т.д.)
- Как перечислять, инспектировать и управлять локальными контейнерами
- Как выполнять команды внутри контейнеров и отлаживать простые проблемы
- Как обновлять контейнерные образы для stateless и stateful приложений
- Как собирать контейнерные образы как профи
...и несколько других тем

https://labs.iximiuz.com/roadmaps/docker

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
SELECT FOR UPDATE в Postgres фактически делает запись

В heap-странице Postgres у каждого tuple есть заголовок header с метаданными.

Когда транзакция выполняет SELECT FOR UPDATE, у найденных tuple (по предикату) обновляется header: они помечаются как залоченные, а атрибут xmax фиксирует XID транзакции, которая поставила лок.

Конкретно выставляются два бита в infomask заголовка: HEAP_XMAX_EXCL_LOCK и HEAP_XMAX_LOCK_ONLY.

Из-за этого страница становится dirty и это также попадает в WAL, который потом может уехать на standby-реплику.

Позже dirty-страница может быть сброшена на диск background writer-ом.

На commit эти биты очищаются.

Забавно, что операция чтения может породить приличный объём write I/O.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Хорошие новости для пользователей Postgres под конец года. Команда TimescaleDB выпустила и открыла исходники расширения pg_textsearch.

В Postgres уже есть встроенный полнотекстовый поиск, а это расширение делает его более современным и продвинутым за счёт добавления ранжирования BM25.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Почему JSON жрёт ваш CPU

Ваш API тормозит. Вы грешите на базу. Потом на сеть. А реальным бутылочным горлышком может быть язык, на котором вы общаетесь.

JSON — это не формат данных. Это текстовая строка.

Каждый раз, когда вы отправляете {"id": 12345}, сервер платит скрытый налог на парсинг. Даже с современными SIMD-оптимизированными парсерами текст упирается в архитектурные ограничения, которых нет у бинарных форматов.

Разбор по инженерке:

1. Стоимость для CPU (машина состояний против арифметики)

JSON (текст):
Чтобы прочитать число 12345, CPU получает поток байт. Даже самые быстрые парсеры вроде simdjson вынуждены работать как машина состояний:

- искать структурные разделители (: и ,)
- проверять escape-последовательности ()
- конвертировать число: проход по ASCII-символам, вычитание '0', умножение на степени 10 и суммирование

Всё это — ветвления, промахи предсказателя и обращения к памяти.

-» Protobuf (бинарь):
Передаёт либо Varint (для маленьких чисел), либо фиксированную ширину (для больших).

Fixed-width (например, fixed32) — это просто memcpy. Парсинга нет вообще.

-» Varint — чтение байт по одному с проверкой старшего бита (MSB), продолжается ли число.

Итог: декодирование сводится к нескольким битовым сдвигам и маскам. Для числовых нагрузок это гарантированно быстрее любого текстового парсинга.

2. Стоимость по пропускной способности (энтропия против избыточности)

JSON:
[{"status": "active"}, {"status": "active"}]


Ключ "status" передаётся снова и снова.

Контраргумент: но gzip же всё сжимает.

Ответ: gzip уменьшает трафик, но увеличивает нагрузку на CPU. Сервер делает Serialize JSON → Compress → Send. Клиент — Decompress → Parse JSON. Вы тратите CPU на сжатие избыточного текста, которого вообще не должно было быть.

--» Protobuf:
Отделяет схему от данных.
В wire-формате строка "status" заменяется ID поля, например 1: [Tag: 1][Value: "active"]. Размер сообщения меньше ещё до компрессии, а значит экономятся CPU-циклы с обеих сторон.

3. Стоимость надёжности

JSON — это схема-при-чтении.
Получатель получает blob и надеется, что id — это число. В коде появляются проверки вида if typeof(id) !== 'number или подключаются валидаторы вроде Zod или Pydantic, которые добавляют ещё один слой runtime-нагрузки.

Protobuf — это схема при записи.
Контракт enforced на границе сериализации. Он не ловит логические ошибки, но гарантирует сохранность типов. Обычно не нужны тяжёлые runtime-валидаторы, чтобы проверить, что Integer — это Integer.

Можно сказать:

JSON отлично подходит для публичных API — его легко дебажить и читать. Но для высоконагруженных микросервисов JSON — это налог.

Переход на gRPC/Protobuf — не сверхчудо. Это просто перенос сложности из парсинг текста в генерацию кода

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
12
Postgres CTE

-» небольшие, читаемые блоки SQL
-» можно тестировать запрос по частям
-» переиспользовать фрагменты SQL в других запросах

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
2
В небольшом приложении один HTTP-запрос обычно делает всё.

Например, пользователь регистрируется.

Бэкенд сохраняет пользователя, отправляет welcome-письмо, пишет метрики и только потом отвечает. Работает, но пользователь ждёт дольше, а если что-то ломается посередине, может упасть вся операция.

Проблема в том, что в одном потоке смешиваются критичные и второстепенные задачи.

Создать пользователя -» критично. Отправить welcome-письмо -» нет. Когда всё идёт в одном флоу, у всего одинаковый вес, и приложение начинает тормозить.

В более крупных системах это решают через Message Queue.

Бэкенд выступает как producer -» сохраняет пользователя и кладёт сообщение в очередь с отложенной задачей, например «отправить welcome-email». На этом запрос заканчивается и быстро отдаёт ответ.

Позже один или несколько воркеров забирают сообщение из очереди и выполняют задачу. Если отправка письма упала, её можно ретраить, не затрагивая пользователя.

Так создание пользователя и отправка письма перестают зависеть друг от друга.

Обратная сторона -» в системе появляется больше компонентов и растёт сложность.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
5
Обобщённые инвертированные индексы (GIN) - мощный инструмент в Postgres.

Они хороши тем, что переворачивают привычную модель индексации.

Вместо логики вида: строка с ID 2 содержит значение "become a database expert", индекс хранит обратное соответствие: токен "database" указывает на строки с ID 1, 2 и 3, а "expert" — на строку с ID 2.

GIN-индексу на вход подаётся набор значений для каждой строки, которую нужно проиндексировать. Каждое уникальное значение становится ключом в индексе и сопоставляется с набором CTID (идентификаторов кортежей строк), в которых это значение встречается.

У такого подхода есть несколько сценариев применения, и один из самых популярных - полнотекстовый поиск. В MySQL для этого есть отдельный тип индекса FULLTEXT, а в Postgres похожая функциональность строится на более универсальных GIN-индексах.

Как это выглядит на практике:

(a) Добавляем колонку tsvector в таблицу:

CREATE TABLE post (
author TEXT,
publish_date DATE,
content TEXT NOT NULL,
search_vector tsvector
);


(b) Заполняем её лексемами (нормализованными словами):

UPDATE post
SET search_vector =
to_tsvector('english', content);


(c) Создаём GIN-индекс по лексемам:

CREATE INDEX post_search_idx
ON post USING GIN(search_vector);


(d) И выполняем запросы:

SELECT * FROM post
WHERE search_vector @@
to_tsquery('english', 'database & expert');


В итоге получаем быстрый и гибкий полнотекстовый поиск прямо внутри Postgres, без отдельных движков и костылей.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
2
В софте очень часто работают так: система хранит текущее состояние.

Например:
» у пользователя такой баланс
» заказ сейчас в таком статусе
» подписка активна

Event Sourcing предлагает другой подход.

Идея простая:
хранить не финальное состояние, а всю историю изменений.

То есть вместо того, чтобы сохранять

balance = 100


ты сохраняешь события:

deposit +200
purchase -50
adjustment -50


А текущий баланс считается путём воспроизведения этих событий.

По сути, как бухгалтерская книга.

Что такое событие в этом контексте?

Событие это факт, который уже произошёл и не меняется.

Например:
» PaymentReceived
» OrderConfirmed
» SubscriptionCancelled

События:
» не редактируются
» не удаляются
» только добавляются

Фактически база данных становится append-only.

Зачем вообще так усложнять?

Потому что это даёт мощные возможности из коробки:

» полная аудитируемость
» сквозная трассировка
» восстановление состояния на любой момент времени
» исторический дебаг: как мы вообще сюда пришли

Никаких дополнительных логов не нужно. История уже есть.

Но важно понимать: у этого подхода есть серьёзные trade-off-ы.

Event Sourcing усложняет всё остальное:

» чтобы читать текущее состояние, нужны проекции
» ментальная модель сложнее
» миграции событий - проблема и требуют аккуратности

Это сила в обмен на сложность.

Где Event Sourcing реально уместен?

Он хорошо заходит, когда:
» домен сложный
» нужна жёсткая аудитируемость
» события важнее состояния
» бизнес постоянно спрашивает «как мы к этому пришли»

Платежи, финансы, бухгалтерия, compliance — классические кандидаты.

Где его лучше не использовать?

» простые CRUD-системы
» тривиальная бизнес-логика
» команды без опыта работы с паттерном
» случаи, когда нужен только текущий стейт

Важное уточнение:

Event Sourcing не равен CQRS.
Их часто используют вместе, но одно не требует другого.

И напоследок главное.

Event Sourcing — это не оптимизация.

Это решение по моделированию.

Ты выбираешь смотреть на систему как на последовательность фактов, а не как на таблицу с изменяемыми значениями.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3🔥1
В SQLite около 155 800 строк кода, а тестовый набор - примерно 92 миллиона строк. Это примерно в 590 раз больше тестов, чем самого кода 🤯

Вот такой уровень тестирования нужен для настоящей продакшен-базы данных. Ниже — какие типы тестов у них есть.

» Тесты на нехватку памяти (OOM)
SQLite не может просто упасть, когда заканчивается память. На встраиваемых устройствах OOM — обычное дело. Они симулируют падения malloc в каждой возможной точке и проверяют, что база корректно это переживает.

» Тесты I/O-ошибок
Диски ломаются. Сеть отваливается. Права могут измениться посреди операции. SQLite подменяет файловую систему на кастомный слой, который может симулировать сбои после N операций, и проверяет, что данные не повреждаются.

» Краш-тесты
Что будет, если питание пропадёт посреди записи? Они симулируют крэш в случайные моменты во время записи, портят несинхронизированные данные, как это делает реальная файловая система, и проверяют, что транзакция либо полностью завершилась, либо чисто откатилась. Никакой порчи данных.

» Fuzz-тестирование
В SQLite кидают кривой SQL, битые файлы базы и случайный мусор. Инструмент dbsqlfuzz прогоняет около 500 миллионов мутаций тестов в день на 16 ядрах.

» 100% покрытие ветвлений
Каждая инструкция ветвления в ядре SQLite проверяется в обе стороны. Не просто «эта строка выполнялась», а «это условие было и true, и false».

Базы данных вообще не прощают ошибок :)

Если хочется копнуть глубже, советую почитать официальную документацию SQLite про их стратегию тестирования. Очень практично и по делу. А если понравился пост - ставь реакцию 👌

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🤯73
Два года назад парень сделал максимально простой демо-пример, который на уровне операционной системы показывает, что происходит, если не использовать пул соединений для Postgres.

С тех пор его рекомендуют даже LLM, и он регулярно получает такой фидбек:
«Впервые наглядно понял, как работает connection pooling».

Это и подтолкнуло поделиться этим видео с вами, друзья 🎷 - смотреть

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
2
Media is too big
VIEW IN TELEGRAM
🎬 Что это? А это второй выпуск нового интерактивного шоу «АйТир Лист» от МойОфис

«АйТир Лист» – это шоу, в котором эксперты оценивают технологии, компании, фреймворки и ИТ-решения по шкале от 1 до 4. Каждый выпуск — это 14 табличек от модератора, жаркие дискуссии и итоговый рейтинг, который поможет зрителям разобраться в актуальных трендах и сделать собственные выводы.

Во втором выпуске мы оценим фичи и идиомы C++.
Гости выпуска:
Данил Черепанов, архитектор Редакторов МойОфис
Антон Полухин, эксперт-разработчик C++ Техплатформы Городских сервисов Яндекса

🎥 Смотрите наш юбилейный второй выпуск там, где вам удобно:
VK | YouTube | RuTube

Реклама
ООО "НОВЫЕ ОБЛАЧНЫЕ ТЕХНОЛОГИИ"
ИНН: 7703807270
erid: 2W5zFG7z16x
🔥2🤔2💊2
This media is not supported in your browser
VIEW IN TELEGRAM
Элегантное разделение ответственности в Apache Kafka даёт кучу возможностей для масштабирования.

Но за это приходится платить компромиссами.

Производитель, потребитель и брокер.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM