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

Связь: @devmangx

РКН: https://clck.ru/3FobxK
Download Telegram
image_2025-09-06_08-52-23.png
234.7 KB
Базовые компоненты современного backend-системы

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
API Rate Limiting и Throttling

Rate limiting — это механизм, который контролирует количество запросов к API за определённый промежуток времени. Он нужен, чтобы защитить систему от перегрузки и злоупотреблений, распределить нагрузку между пользователями и обеспечить стабильную работу сервера.

Например, можно разрешать не более ста запросов в минуту для одного пользователя. Такой подход помогает предотвращать DoS-атаки, сохраняет ресурсы сервера, поддерживает равные условия доступа и повышает стабильность API.

Throttling — это управление потоком запросов, когда после достижения лимита новые запросы не блокируются, а обрабатываются с задержкой или ставятся в очередь.

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

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

Для реализации этих механизмов используют разные техники.

→ Token Bucket разрешает запросы, если есть свободные токены, которые постепенно восстанавливаются.
→ Leaky Bucket обрабатывает запросы с фиксированной скоростью, а избыточные либо отбрасываются, либо ставятся в очередь.
→ Fixed Window ограничивает количество запросов в фиксированном временном окне, например в течение одной минуты.
→ Sliding Window работает по схожему принципу, но в скользящем интервале, что обеспечивает более плавный контроль нагрузки.

В реальном мире такие подходы встречаются повсюду. Twitter API ограничивает количество запросов на пользователя каждые пятнадцать минут. GitHub API устанавливает лимиты на количество авторизованных запросов в час. AWS API Gateway сочетает оба механизма и даёт разработчикам гибкие инструменты для управления нагрузкой.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84🔥3
Как понять, что твоя стратегия кеширования правильная?

Ключевая метрика — процент запросов, когда данные находятся в кеше.

Это называется коэффициент попаданий в кеш и показывает, как часто ты можешь переиспользовать закешированный объект.

Вот как замаксить этот коэффициент:

I. Размер пространства ключей

Единственный способ найти элемент в кеше — точно совпасть по ключу.
Чем меньше возможных ключей, тем эффективнее кеш.
Всегда думай, как уменьшить количество возможных ключей.

II. Размер кеша и элементов

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

III. Долговечность


Во многих случаях можно кешировать объекты на предопределённое время, так называемый Time to Live, TTL.
В других случаях ты не можешь рисковать устаревшими данными и должен инвалидировать объекты в кеше.
В общем, чем дольше ты можешь держать элементы в кеше, тем выше шанс их переиспользовать.

Большинство кейсов, хорошо подходящих для кеширования, имеют высокий ratio чтений к записям.
Потому что закешированные элементы можно создать один раз и хранить длительное время, пока они не истекут или не станут невалидными.

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

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍4
Реверс-прокси одновременно играет роль и бэкенда, и фронтенда. Клиенты подключаются к реверс-прокси как к бэкенду, а он в свою очередь подключается к апстрим-бэкендам, уже выступая для них фронтендом.

В обоих направлениях можно использовать разные протоколы. Например, клиенты могут работать по HTTP/1.1, а соединение к бэкенду апгрейдиться до HTTP/2.

В итоге запросы по h1 собираются и идут через один апстримный h2-стрим, или даже h2-h2. Это открывает возможность для довольно интересных архитектур бэкенда. Обрати внимание: NGINX не использует HTTP/2 для апстримов, а HAProxy — использует.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3
Охотьтесь на N+1 и убирайте их

Проблема N+1-запросов опасна и легко может ускользнуть из виду. Сценарий такой. Один запрос получает набор данных. Затем для каждой строки нужен ещё один запрос. Количество запросов при загрузке страницы зависит от размера выборки, и если N большой, производительность падает

Пример на псевдокоде

// один запрос
users = db.query('SELECT * FROM users')

// превращается в N дополнительных
for (const user of users) {
posts = db.query(`
SELECT * FROM posts
WHERE user_id = user->id`)
user.posts = posts
}
// только теперь можно вернуть результат


Лучше переписать на один запрос с JOIN, чтобы забрать всё сразу

results = await db.query(
`SELECT u.*, p.*
FROM users u
LEFT JOIN posts p
ON u.id = p.user_id`)


Интересный момент в том, что иногда N+1 почти не заметен. Если N маленький, база настроена и находится рядом с приложением, всё может работать быстро. Но если N=100, сразу ощущается тормоз и база нагружается лишней работой. Исправив это, вы улучшите UX и снизите нагрузку на сервер БД

Иногда такие запросы пишут руками. Но часто их генерирует ORM незаметно для вас. В любом случае избавляйтесь от них

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
9🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
Нашёл классный опенсорс инструмент: ConfMap

Он превращает YAML и JSON-конфиги в интерактивные майнд-мапы. Можно искать ключи и значения, кликать по нодам, сворачивать ветки и быстро разбираться даже в самых запутанных структурах.

Забираем здесь: ConfMap или c GitHub 🤩

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥54💊1
Тесты это не про баги. Это про скорость.

Позвольте объяснить.

Безошибочный код это вымысел.

Но быстрая и бесстрашная итерация? Это реально. И именно для этого нужны тесты.

Хороший набор тестов делает 3 вещи:

- Ломается, когда вы что-то ломаете.
- Объясняет поведение лучше, чем ваши комментарии.
- Даёт уверенность двигаться быстро.

Если работать с кодом страшно, значит, у вас недостаточно тестов или не те тесты.

Тесты это не лишнее.
Вы не пишете их, чтобы угодить менеджеру.
Вы пишете их, чтобы иметь возможность рефакторить без страха.

Скорость это прибыль. Тесты делают скорость безопасной.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍1🔥1
Большинство думает, что SQL медленный. Это не так.

Медленные у них запросы. Лови простое введение в функциональные индексы.

Что такое функциональный индекс?

• Обычный индекс говорит: «Я помогу тебе быстрее найти значение в этой колонке».
• Функциональный индекс говорит: «Я помогу тебе быстрее найти результат функции».

Пример:

-- Обычный фильтр (медленно)
WHERE EXTRACT(YEAR FROM order_date) = 2023;

-- С функциональным индексом
CREATE INDEX idx_order_year ON orders ((EXTRACT(YEAR FROM order_date)));


Теперь YEAR() не вычисляется для каждой строки — он просто ищется в индексе, как в словаре.

Зачем тебе это?
Ты постоянно пишешь такие запросы:

LOWER(email) → поиск без учёта регистра
SUBSTRING(code, 1, 4) → поиск по части строки
price * quantity → вычисляемые поля
EXTRACT(MONTH FROM signup_date) → фильтр по месяцу

И все они будут медленными без функционального индекса.

Когда использовать?

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

Запомни:

I. Функциональные индексы хранят результат функции.
II. Они избавляют от пересчёта при каждом запросе.
III. Делают тяжёлые фильтры очень быстрыми.
IV. Но жрут место и работают только с детерминированными функциями.

Сохрани это. Внедри. Поделись с тем, кто всё ещё пишет тормозные запросы.

Спокойствие, только SQL 🥺

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥5
За каждой масштабируемой системой стоит очередь. За каждым падением —> неправильно использованная очередь.

Очереди повсюду - фоновые задачи, потоки событий, брокеры сообщений.

Они основа масштабируемых систем, но также и частая причина сбоев.

Базовые определения

I. Очередь: структура данных или система для хранения задач/сообщений в порядке FIFO (First-In-First-Out).
II. Продюсер: компонент, отправляющий сообщения в очередь.
III. Консьюмер: компонент, читающий и обрабатывающий сообщения из очереди.
IV. Брокер: промежуточное ПО для управления очередями (например, RabbitMQ, Kafka, SQS).
V. Подтверждение: сигнал, что сообщение успешно обработано.
VI. Очередь «мёртвых писем» (DLQ): очередь для сообщений, которые не удалось обработать.
VII. Идемпотентность: гарантия, что повторная обработка сообщения не создаст дублирующих побочных эффектов.
VIII. Visibility Timeout: время, в течение которого сообщение «невидимо» для других, пока оно обрабатывается.

Лучшие практики / Подводные камни

I. Используй идемпотентных консьюмеров → предотвращает двойную обработку.
II. Определяй политики повторных попыток (экспоненциальная задержка, ограничение числа попыток).
III. Мониторь длину очереди и задержку обработки как ключевые метрики здоровья.
IV. Используй очереди «мёртвых писем» для упавших сообщений.
V. Гарантируй порядок сообщений только тогда, когда это критично для бизнеса (порядок повышает стоимость и сложность).
VI. Держи сообщения маленькими и самодостаточными.
VII. Всегда включай correlation ID для трассировки.

Производительность

I. Для пропускной способности → параллельные консьюмеры или партиции.
II. Для надёжности → сохраняй сообщения, если критично (компромисс: скорость).
III. Для масштабируемости → авто-масштабирование консьюмеров.

Паттерны

I. Work Queue → распределение задач между воркерами.
II. Pub/Sub → широковещательная рассылка множеству подписчиков.
III. Delayed Queue → повторная попытка позже или планирование задач.
IV. Priority Queue → приоритетная обработка срочных сообщений.


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

Используешь неправильно — получаешь сбои. Используешь правильно — получаешь масштабируемость, устойчивость и скорость.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
6
Делюсь настоящей сокровищницей по систем-дизайну.

В этом репозитории собрана огромная коллекция материалов о том, как строить масштабируемые, надежные и быстрые системы. Тут есть статьи инженеров из FAANG и других компаний, реальные кейсы с архитектурами, которые выдерживают миллиарды запросов, схемы и принципы работы сервисов, а также разборы фейлов, после которых компании восстанавливали свои системы с нуля.

И бонусом идёт шпаргалка для подготовки к собеседованиям по систем-дизайну. 🎉

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
4
This media is not supported in your browser
VIEW IN TELEGRAM
Что такое обработка данных

Обработка данных это сбор, манипулирование и анализ данных для получения полезной информации или инсайтов.

Суть в том, чтобы превращать сырые данные в осмысленную и применимую информацию с помощью разных инструментов, техник и алгоритмов.

Обработка данных бывает разных типов: пакетная (batch), в реальном времени (real-time) и потоковая (stream processing).

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

В реальном времени данные обрабатываются сразу по мере поступления.

Основные шаги обработки данных:

I. Сбор данных
Первый шаг — собрать данные. Это можно сделать через опросы, сенсоры, веб-скрейпинг или API.

II. Очистка данных
Сырые данные часто содержат ошибки, дубли и пропуски. Очистка данных это поиск и исправление этих проблем, чтобы данные были точными и согласованными.

III. Преобразование данных
После очистки данные нужно привести в формат, удобный для анализа. Это может включать агрегацию данных, конвертацию типов или нормализацию.

IV. Анализ данных
После преобразования данные анализируются с помощью статистики или машинного обучения, чтобы выявить закономерности и инсайты.

V. Визуализация данных
Визуализация это представление обработанных данных в наглядной форме (графики, диаграммы, карты). Это помогает заинтересованным сторонам легко понимать и интерпретировать результаты.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
This media is not supported in your browser
VIEW IN TELEGRAM
Сегодня отмечается День программиста!

256-й день года выбран не случайно:
Дата праздника объясняется расчетом: 2 (двоичная система исчисления) в степени 8 (количество битов в байте). То есть 2^8= 256. Поэтому в обычный год день программиста 13 сентября, а в високосный — 12 сентября


С праздником, коллеги! ☺️

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
21😁2
Да, CDN снижает задержки за счёт кэширования контента ближе к пользователям, но есть интересная оптимизация, которую они используют, чтобы ещё сильнее уменьшить latency

TCP страдает от slow start -> когда устанавливается новое TCP-соединение, оно сразу не работает на полной пропускной способности. Вместо этого оно стартует консервативно с небольшого количества сегментов и удваивает их каждый RTT, пока не обнаружит перегрузку.

Этот ramp-up может занимать несколько итераций, прежде чем достигнет оптимальной пропускной способности, что проблематично для latency-sensitive приложений. Это серьёзная проблема для CDN, потому что даже несколько лишних RTT на масштабе большого количества пользователей обходятся дорого.

CDN решают это с помощью persistent connection pools к origin-серверам. Вместо того чтобы создавать новое соединение для каждого запроса пользователя, они поддерживают пул долгоживущих соединений между edge-узлами и origin-серверами.

Интересная часть —> это pre-warming в периоды низкой нагрузки.

CDN периодически отправляют небольшие объёмы данных (например, health check или запросы на валидацию кэша) по этим idle-соединениям. Это поддерживает TCP congestion window на максимуме и предотвращает её уменьшение из-за простоя.

Небольшой расчёт, чтобы показать эффект.

Если поддерживать congestion window разогретой, она работает на 64KB вместо 4KB. Это исключает задержку 3–7 RTT, которая возникла бы в противном случае.

Для соединения с RTT 50 мс это экономит 150–350 мс latency - а это очень значимо на масштабе веба.

Надеюсь, вам было интересно. И, как всегда, копайте глубже. 🪰

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥115
This media is not supported in your browser
VIEW IN TELEGRAM
SQLZap это прям находка

sqlzap.com — это онлайн-платформа для тренировок SQL-запросов в браузере. Что-то вроде интерактивного тренажёра

Идеально чтобы натаскать руку (как Leetcode, только для SQL)

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
7🔥2
Как TikTok справляется с миллионами коротких видео в реальном времени?

TikTok использует микросервисную архитектуру, где разные функции (загрузка видео, лента, комментарии, рекомендации) разбиты на независимые сервисы.

Когда вы открываете TikTok, ваш запрос проходит через балансировщики нагрузки и API-шлюзы, которые мгновенно направляют вас к нужному сервису.

Видео хранятся в распределенном облачном хранилище и доставляются через глобальные CDN (Content Delivery Networks). Это обеспечивает быструю загрузку ленты с минимальной буферизацией вне зависимости от вашего местоположения.

Ядро TikTok работает на ключевых сервисах (API). Сервис аутентификации управляет логинами и аккаунтами, сервис профилей пользователей хранит вашу активность, а сервис ленты формирует персонализированный список видео.

Знаменитая «For You Page» работает через сервис рекомендаций, который использует AI и машинное обучение для ранжирования и подбора видео. Отдельный сервис поиска помогает быстро находить тренды и авторов.

За кулисами TikTok обрабатывает огромные объемы данных. Поведение пользователей, лайки, время просмотра и взаимодействия постоянно поступают в модели машинного обучения, чтобы рекомендации обновлялись в реальном времени.

Базы данных специализированы: одни — для аккаунтов пользователей, другие — для метаданных видео, третьи — для аналитики.

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

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

Технический стек TikTok:

🔸Frontend: React, Node.js, TypeScript
🔸Backend: Golang, Python, Java, Scala
🔸API-коммуникация: gRPC, GraphQL
🔸Mobile: Swift (iOS), Kotlin (Android)
🔸Базы данных: MySQL, Redis, Cassandra, TiDB
🔸Messaging: Apache Kafka, Pulsar
🔸Обработка данных: Apache Flink, Hadoop, Spark, Hive
🔸Безопасность: собственная IAM, слои шифрования, мониторинг трафика
🔸Хранилище видео: распределенное облако + глобальный CDN (собственный CDN ByteDance)
🔸DevOps: Kubernetes, Docker, Prometheus, Grafana, Chaos Testing
🔸Машинное обучение: TensorFlow, PyTorch, собственные AI-фреймворки ByteDance


👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
18
Каждый разработчик в растущем e-commerce сталкивался с этим вопросом:

Как масштабировать процесс создания заказов во время флеш-распродажи?

Есть 4 варианта.
Работает только один.

Разберём по порядку:

I. Синхронное создание заказа

. Запрос блокируется.
. Запись в БД в "горячем" пути.
. Ложится под нагрузкой.
. Не масштабируется.

II. Асинхронная обработка через очередь

. Принимаем заказ.
. Кладём его в очередь.
. Быстро возвращаем ответ.
. Обрабатываем позже.

Это развязывает API и нагрузку:

. Масштабируется.
. Переживает пиковые всплески.
. Даёт контроль.
. Работает, потому что очередь берёт удар на себя.

III. Централизованный сервис заказов

. Один большой сервис.
. Один большой bottleneck.
. Код проще, проблемы те же.
. Разваливается на масштабе.

IV. Сплошные микросервисы

. Вносит задержки, координацию и новые точки отказа.
. Всё ещё не сглаживает пиковую нагрузку.
. Инструмент не для этой задачи.

Компромиссы (они всегда есть):

I. Eventual consistency.
II. Нужна идемпотентность (и так критично).
III. Нужно мониторить состояние очереди.
IV. Требуются компенсирующие транзакции.
V. Очередь сама по себе не решает всё.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
2
Краткая шпаргалка по шаблонам проектирования

Автор: Jason McDonald.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
9
Клиентское кэширование в HTTP работает так

Сервер может отдавать два типа ресурсов — статические и динамические. Статические данные не меняются между запросами, поэтому их можно кэшировать на стороне клиента с помощью специальных HTTP-заголовков.

Когда клиент впервые делает GET-запрос к ресурсу, локальный кэш проверяет его наличие. Если ресурса нет, запрос уходит на сервер. Сервер в ответе указывает, что данные можно закэшировать -> заголовок Cache-Control задаёт время жизни ресурса, а ETag определяет его конкретную версию. Кэш сохраняет ответ и возвращает его клиенту.

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

Если ресурс в кеше устарел, кэш отправляет новый запрос на сервер с условным заголовком, например If-None-Match, где указывает сохранённую версию. Если сервер имеет новую версию, он возвращает её. Если изменений не было, он отвечает кодом 304 Not Modified, и клиент продолжает использовать локальные данные.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92
Вопрос по системному дизайну

Как убедиться, что реплика синхронизирована с мастером и что данные корректны?
Мастер отправляет репликам логические операции, которые они применяют по порядку:

{"op": "add", "id": "apple"}
{"op": "add", "id": "apple"}
{"op": "remove", "id": "orange"}


После того как реплика обработала эти изменения (добавила два яблока, удалила один апельсин), как проверить, что оба узла в итоге пришли к одному и тому же состоянию?

Требования:

• Проверка должна работать за O(delta), где delta — это набор применённых изменений
• Проверка состояния должна занимать минимально возможное количество памяти

Дополнительно:

• Должна быть поддержка операций удаления
• Может ли система определить, где произошло расхождение?
• Может ли она определить, когда произошло расхождение?

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