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

Связь: @devmangx

РКН: https://clck.ru/3FobxK
Download Telegram
Docker это не мини-виртуальные машины

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

1. Docker — это не виртуалка

Когда ты запускаешь docker run ubuntu, ты не создаешь «мини-компьютер».

Никакого нового ядра нет.
Контейнер использует то же ядро, что и хост — просто в изоляции.

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

2. Изоляция достигается через namespaces

Namespace говорит системе:
«Этот процесс видит только вот этот кусочек мира».

Примеры:

PID namespace — контейнер думает, что его процесс 1 — единственный.

NET namespace — у контейнера своя сеть и интерфейсы.

MNT namespace — своя файловая система с примонтированными ресурсами.

Так несколько контейнеров могут спокойно жить рядом, не мешая друг другу.

3. Cgroups ограничивают ресурсы

Контейнер может считать, что владеет всей машиной…
но control groups (cgroups) ставят реальные лимиты:

- максимум CPU (--cpus=2)
- максимум памяти (--memory=1g)
- лимиты на I/O или количество процессов

Если контейнер пытается выйти за рамки, ядро его просто отрубает 😅

4. Файловая система и слои (UnionFS)

Образ это не один файл, а набор слоев.
Каждая инструкция RUN, COPY или ADD в Dockerfile создает новый слой.

Когда контейнер запускается, поверх монтируется временный слой для записи.

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

5. Как контейнеры общаются между собой

Docker создает виртуальные сети внутри хоста.
Каждый контейнер получает свой внутренний IP.

Когда ты используешь --link или docker-compose,
ты просто задаешь внутренние DNS-имена.

Во внешний мир трафик не выходит,
пока ты сам не пробросишь порт через -p 8080:80.

6. Безопасность -изоляция не идеальна

Поскольку ядро общее, защита не такая жесткая, как у виртуалки.

Для этого и придуманы штуки вроде:

gVisor — песочница для системных вызовов
SELinux или AppArmor
rootless Docker

Если запускаешь сторонние контейнеры — лучше использовать их.

Так что же такое Docker на самом деле?

Это оркестратор изоляции:

- прячет ресурсы через namespaces
- ограничивает их через cgroups
- управляет файловой системой через UnionFS
- эмулирует сеть через network namespaces

Он ничего не эмулирует по-настоящему,
он просто создает очень правдоподобную иллюзию 👏

Понимание этого полностью меняет подход к дебагу и оптимизации.

Контейнер жрет всю оперативку? → смотри cgroups.
Не может подключиться к сети? → проверь network namespace.
Билды весят по 5 ГБ? → разбери слои образа.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥41
Когда backend dev сделал frontend

- он отзывчивый из коробки
- загружается за 0,00004 секунды

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
😁34🔥9👍7
Вчера пробовал cloudflared от Cloudflare, чтобы пробросить локально запущенное API для теста интеграции с GitHub — честно, 10/10.

Даже аккаунт Cloudflare не нужен.

Установил пакет и запустил:

cloudflared tunnel --url http://localhost:8000


И всё.

Раньше всегда пользовался ngrok, но решил попробовать это — понравилось, что для теста не нужен аккаунт.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
Пользователь сообщил: "Поиск работает медленно." Результаты вернулись за 8 секунд.

Кластер Elasticsearch был в порядке. Запрос оптимизирован. Индексы — здоровые.

Я проследил весь запрос от начала до конца:

Frontend → API: 45 мс

API → Elasticsearch: 180 мс

Запрос в Elasticsearch: 220 мс

API → Frontend: 7 480 мс

API сериализовал 50 000 результатов в JSON до пагинации.

Забирал все результаты

Конвертировал в JSON

Отправлял всё на фронт

Фронт показывал 10 элементов

Фикс: делать пагинацию на уровне Elasticsearch, а не в API.

Новый отклик: 312 мс.

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

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
11🤯5👍1
Kite — это современная лёгкая панель управления для Kubernetes, которая предоставляет метрики в реальном времени, поддерживает работу с несколькими кластерами, редактирование YAML и управление ресурсами через удобный интерфейс.

https://ku.bz/95jvldnx_

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥64
Производство упало. Health-чеки балансировщика валятся. Все инстансы помечены как unhealthy.

Зашёл по SSH на инстанс:

Приложение: запущено

CPU: 5%
Память: 40%
Диск: 15%
Сеть: ок

Ручной запрос к health-эндпоинту:

curl localhost/health
{"status": "ok"}


Отработал идеально.

Проверил логи балансировщика:

Health-check URL: /health


Ответ: timeout

Инстанс помечен как unhealthy

Проблема:

Локально health-эндпоинт отвечал за 100 мс

Таймаут балансировщика: 2 секунды

Должно с запасом хватать

Потом заметил: health-чек запускался каждые 5 секунд.

Приложение логировало каждый health-чек. В файл. Файл разросся до 47 ГБ.

Каждый health-чек:

- Открывал 47-гиговый лог
- Добавлял одну строку
- Закрывал файл
- Занимал 3 секунды из-за размера файла
- Укладывался в таймаут? Нет, получался timeout

Фикс: отключил логирование health-чеков. Время ответа вернулось к 100 мс.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍131
У тебя микросервисная архитектура. OrderService должен дать сигнал EmailService, чтобы тот отправил письмо. Ты поднимаешь простую очередь - Redis или RabbitMQ. OrderService пушит задачу, EmailService её читает. Всё вроде бы работает.

Потом появляется AnalyticsService, которому тоже нужно знать об этом заказе. Но уже поздно, ведь EmailService прочитал и удалил сообщение. Тогда ты добавляешь костыль: OrderService пишет сразу в две очереди. Потом приходит FraudService и теперь уже три. В итоге OrderService превращается в хрупкий, связанный узел, от которого всё зависит.

Ты слышал про Kafka и думаешь: «Да это просто очередь, только сложнее». Но нет. Kafka это не очередь, а лог. И вот это всё меняет.

В обычной очереди, как в RabbitMQ, сообщение живёт как таска в туду-листе. Консьюмер его забирает, и оно исчезает. Если сервис упал то сообщение потеряно, если не строить сложный retry. И только одна группа консьюмеров может получить сообщение.

В Kafka всё иначе. Сообщения это события, которые не удаляются после чтения. Они публикуются в топик, например all-orders, и записываются в файл, как в git-лог, в порядке поступления. Эти данные устойчивы и защищены от сбоев по умолчанию.

Самое интересное начинается, когда понимаешь, что консьюмеры ничего не "вытаскивают". Они просто читают лог, начиная с определённого offset. EmailService читает лог, AnalyticsService читает тот же лог, только в своём темпе, FraudService тоже. Каждый в своей consumer group, и Kafka это не волнует. OrderService просто один раз "кричит в пустоту" и не заботится, кто услышит. Всё максимально развязано.

А теперь представь, что EmailService упал. Всё равно не страшно, ведь сообщение осталось в логе. После перезапуска он продолжит читать с того места, где остановился. Потерь нет. Потом ты выкатываешь новый RecommendationService с ИИ и говоришь ему: «Начни с начала топика all-orders, прочитай последние полгода истории и построй модель». Он спокойно переигрывает прошлое. С очередью так сделать нельзя.

Kafka это не message bus. Это распределённый, отказоустойчивый и постоянный источник истины для всей компании. По сути, центральная нервная система современного бизнеса, который живёт на данных.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍104💊2😁1
Forwarded from Мир Linux
This media is not supported in your browser
VIEW IN TELEGRAM
Программисты, откопал вам годноту для прокачки алгоритмов: визуальный тренажёр с пошаговым выполнением кода

70+ алгоритмов на JavaScript, Java и C++, всё интерактивно и с наглядной визуализацией

Забираем здесь 🍯

@linuxos_tg
11
Структура данных B-Tree реально крутая штука. Базы данных используют B-деревья для хранения данных на диске, разбивая всё на страницы , обычно по 4–8 КБ. Все операции ввода-вывода происходят именно с этими страницами как единицами.

Как устроена страница

Один из популярных способов организовать данные внутри страницы, называется slotted page structure.
Она начинается с заголовка, за ним идут указатели на ячейки, которые ссылаются на ячейки данных в конце страницы.

Пока ты добавляешь данные:

указатели растут слева направо,

а сами ячейки растут справа налево,
встречаясь где-то посередине.

Эта середина — формально "свободное место", но прикол в том, что оно может содержать что угодно. Страница и всё дерево вообще не заботятся, что там лежит.

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

Буферный пул и «грязные» страницы

Базы данных ещё поддерживают buffer pool, это кэш страниц, загруженных с диска. Эти страницы часто переиспользуются.
И вот тут появляется интересная оптимизация:
вызов memset (который обнуляет память) занимает время, поэтому базы часто вообще не затирают старые данные.
Удаление записи это просто удаление указателя, но данные на диске остаются.

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

Зарезервированное место в конце страницы

Помнишь, я говорил, что ячейки растут справа налево?
Если ты специально оставишь немного свободного места в конце страницы до начала области ячеек, B-дерево продолжит работать как ни в чём не бывало.
Эта область не используется самим деревом, и в неё можно записывать что угодно.

SQLite использует этот трюк для фичи reserved space.
Расширения могут сохранять свои данные прямо в каждой странице, не ломая работу дерева.
Например, туда пишут метаданные для шифрования или контрольных сумм.

Кстати, у SQLite есть настройка PRAGMA secure_delete, которая при удалении затирает содержимое нулями, чтобы мусор не утёк никуда , это уже для безопасности.

Если коротко: B-Tree не просто эффективная структура, она ещё и невероятно продумана для работы с реальным диском, где каждая операция чтения и записи стоит дорого.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
😁21
Платежи не дают второго шанса.

Вот решение, которое стояло перед Марко

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

Но платежам плевать на «низкую задержку».
Им важно одно и это не списывать деньги дважды.

Перед ним были такие варианты:

A → Строгая консистентность

Хранить сгенерированный клиентом idempotency key и финальный ответ в надежной БД.
Уникальное ограничение отсекает дубликаты.
Аудируемо. Правильно. Чуть медленнее.

B → Хак с Redis и TTL

SETNX-лок → обработка → кеширование результата.
Очень быстро… пока Redis не перезапустится, TTL не сгорит раньше времени или не случится разделение сети.
И вот ты уже списал деньги дважды и несколько дней «разбираешься».

C → Вера в магию Kafka

Публикуешь событие и надеешься на “exactly-once” в стриме.
Но в платежах корректность нужна до того, как ты возвращаешь успех.
Это решает масштаб, но не ответственность.

D → Починим потом

Позволяешь двойным списаниям происходить.
Потом проводишь аудит, делаешь возвраты, извиняешься и тд
Дешево в реализации. Дорого в доверии.

Марко выбрал A.
Потому что «быстрые» варианты становятся самыми дорогими, когда в игру вступают реальные деньги.

В финтехе побеждает корректность. Всегда.
Задержка раздражает, но двойное списание уничтожает доверие.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍64
Векторные базы данных простыми словами

Представь, у тебя есть 10 000 описаний товаров. Пользователь ищет "удобная уличная мебель".

Обычная база данных:

Ищет точные совпадения слов

Находит товары с "удобная" ИЛИ "уличная" ИЛИ "мебель"

Пропускает "уютные кресла для террасы", хотя это то же самое

Ключевые слова — тупой способ поиска

Векторная база данных:

Превращает запрос в набор чисел, отражающих смысл: [0.2, 0.8, 0.1, 0.9, ...]

Каждое описание товара тоже превращается в такие числа

Сравнивает эти "векторы" и ищет похожие по смыслу

Находит "уютные кресла для террасы", потому что векторы похожи

Смысловой поиск — умный поиск

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

Шаг 1. Превращаем текст в векторы (массивы чисел)

"comfortable chair" → [0.2, 0.7, 0.1, 0.4, ...]

"cozy seat" → [0.3, 0.8, 0.2, 0.5, ...]

Похожие фразы → похожие числа

Это делает AI-модель, например OpenAI embeddings

Шаг 2. Храним векторы

В обычной БД хранят текст

В векторной — массив чисел для каждого объекта

Индексируют их, чтобы быстро искать по схожести

Оптимизировано под "найди похожие", а не "найди точное"

Шаг 3. Ищем по схожести

Запрос: "outdoor furniture"

Превращается в [0.3, 0.6, 0.2, 0.8, ...]

Система ищет ближайшие векторы (через cosine similarity)

Результаты сортируются по степени похожести

Где это используется:

- Поиск товаров, который понимает смысл, а не только слова
- Поиск по документации, который находит релевантные ответы
- Рекомендательные системы
- Чатботы, ищущие похожие вопросы
- Обнаружение аномалий

Популярные векторные базы

Pinecone = управляемая, простая, но дорогая
Weaviate = опенсорс, с кучей функций
Milvus = быстрая и масштабируемая, но сложная
pgvector = расширение для Postgres, простое и удобное
Qdrant = быстрая, написана на Rust

Спорная, но практичная мысль

В большинстве проектов тебе не нужна отдельная векторная база.
Начни с Postgres + pgvector = этого хватает, пока у тебя меньше 1 миллиона векторов.
Когда масштаб вырастет, тогда уже смотри в сторону специализированных решений.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥31
Совет по Docker

Как понять, что раздувает образ

Любой Docker-образ состоит из слоев.
Каждая строка в Dockerfile добавляет новый слой.

По этим слоям можно понять, почему образ получается большим, долго собирается или плохо кешируется.

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

Используй утилиту dive.

Она показывает наглядно:

- какие слои созданы
- какие файлы добавлены или изменены
- сколько места занимает каждый слой

Когда начинаешь изучать слои образа, можно быстро выяснить:

• какая команда в Dockerfile добавляет лишний вес
• как оптимизировать сборку, чтобы образ был меньше и собирался быстрее

Dive также дает оценку «эффективности» образа. Она показывает, насколько много данных дублируется или просто впустую занимает место в слоях.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍83🔥2
Это моя любимая статья про внутренности B-деревьев.
Джереми Коул работал с MySQL в Twitter, Google и Shopify. Один из самых прошаренных MySQL-инженеров в мире, а его блог просто кладезь полезной инфы.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Реализовали ограничение API по IP. 1000 запросов в час на один IP. Идеальная защита от злоупотреблений.

Неделя спустя: легитимный клиент уперся в лимит. Пожаловался, что у них сервис сломался.

Они сидели за корпоративным NAT. 500 сотрудников делили один IP. Лимит кончился за 20 минут.

Переключили ограничение на API-ключ. Проблема решена.

Еще через неделю: бот-атака. 50 000 запросов в час. Разные API-ключи. Абьюз бесплатного тарифа.

Сделали ограничение и по IP, и по API-ключу. Проблема решена.

Еще через неделю: DDoS. 10 000 разных IP и 10 000 разных бесплатных API-ключей.

Rate limiting оказался бесполезен против распределенной атаки.

Настоящее решение:

Ограничение по IP для неавторизованных эндпоинтов

Ограничение по API-ключу для авторизованных эндпоинтов

Анализ поведения для поиска подозрительных паттернов

CAPTCHA для подозрительного трафика

CloudFlare спереди для защиты от DDoS

Лимиты по стоимости на бесплатный тариф

Нет одной универсальной стратегии rate limiting. Нужны слои. IP, пользователь, аккаунт, поведение и внешняя DDoS-защита.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
17👍5
Большинство проблем с производительностью возникают не из-за плохих запросов.

А из-за кривых таблиц.

Каждый CREATE TABLE это решение, которое потом аукнется:

• типы данных
• индексы
• ограничения
• партиционирование

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

Читать тут → ссылка

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥72
Foreign keys и constraints. Многие путают эти понятия.

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

Foreign key constraint: механизм, который заставляет СУБД контролировать целостность внешних ключей. Он гарантирует, что значения во внешнем ключе (post -> user_id) ссылаются на реальную запись в другой таблице (user -> id).

Constraints это полезная фича (помогает с той самой буквой C в ACID), но за удобство приходится платить. Вставки, обновления и удаления на таблицах с constraints требуют дополнительных вычислений и IO для проверки.

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

Базы данных, как мир бесконечных компромиссов. 🚬

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
API ускорили, трафик похудел

В продакшн завезли gzip-сжатие. Размер ответов упал примерно на 85%, а задержка почти на 60%.

До:

Средний ответ 240 KB
Передача ~400 мс

Трафик обходился в ~220 $ в месяц

После:

Средний ответ 36 KB
Передача ~48 мс
Трафик снизился до ~70 $ в месяц

Добавили compression middleware и сразу получили:

Загрузка быстрее на 88%
Минус 68% по расходам на пропускную способность

Маленькое изменение. Большая разница.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥116
Наш основной файл состояния Terraform весил 15 МБ. В нём была описана вся наша AWS-организация.

terraform plan занимал 20 минут и часто падал по таймауту.

Никто не хотел к нему прикасаться. Это был наш самый большой технический долг.

Рефакторинг занял 3 месяца:
- Инфраструктуру не меняли.
- Через terraform state mv переносили ресурсы из огромного state-файла в более мелкие логические (например, networking.tfstate, security.tfstate, app-foo.tfstate).
- Terragrunt использовали для оркестрации зависимостей между новыми маленькими state-ами.

Теперь план для одного приложения занимает 30 секунд. Наконец-то можно безопасно вносить изменения.

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Пентестер получил root-доступ к нашему Kubernetes-кластера за 15 минут. Вот что он эксплуатировал.

Цепочка атаки:

- Нашёл открытый Kubernetes Dashboard (это наш косяк)
- На Dashboard был service account только с view-доступом (мы считали это безопасным)
- Service account мог читать Secrets во всех namespaces
- В одном из Secrets были AWS-креды
- С этими кредами получил доступ к EC2 instance profile
- Instance profile имел полный Kubernetes admin через IAM
- Через kubectl поднял привилегированный pod
- Сделал escape на node
- Root-доступ ко всему кластеру

Что мы думали сделали правильно:

- Dashboard был read-only
- Secrets были зашифрованы at rest
- NetworkPolicy настроены
- Регулярные безопасности обновления

Что мы упустили:

- Dashboard вообще не должен быть доступен снаружи
- Service accounts должны работать по принципу наименьших привилегий
- Secrets не должны хранить AWS-креды (нужен IRSA)
- Pod Security Policies не были включены
- Узлы не были достаточно защищены

Исправление заняло 2 недели:

- Полностью убрали Kubernetes Dashboard
- Внедрили IRSA для всех pod'ов, которым нужен доступ к AWS
- Включили строгие PSP / Pod Security Standards
- Провели аудит всех RBAC-разрешений
- Регулярные пентесты

Стоимость: 24K $ за пентест
Ценность: предотвратили потенциально катастрофический взлом

👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯9🔥54