This media is not supported in your browser
VIEW IN TELEGRAM
Не все процессоры одинаковы.
На этом графике задержек показано сравнение апгрейда r6id → i7i.
Количество vCPU то же, объём RAM тот же, оба варианта используют локальные SSD.
И всё же переход на более новую инстанс-серию даёт заметный прирост производительности.
👉 @BackendPortal
На этом графике задержек показано сравнение апгрейда r6id → i7i.
Количество vCPU то же, объём RAM тот же, оба варианта используют локальные SSD.
И всё же переход на более новую инстанс-серию даёт заметный прирост производительности.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Запуск и управление контейнерами Docker
Изучите, как запускать контейнеры самых разных типов (серверы, базы данных, CLI-инструменты и т.д.), взаимодействовать с ними и сформировать чёткое понимание того, как Docker управляет вашими приложениями «под капотом».
Здесь: Docker 101: Run and Manage Containers
👉 @BackendPortal
Изучите, как запускать контейнеры самых разных типов (серверы, базы данных, CLI-инструменты и т.д.), взаимодействовать с ними и сформировать чёткое понимание того, как Docker управляет вашими приложениями «под капотом».
Здесь: Docker 101: Run and Manage Containers
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4🔥1
Когда количество записей в базе переваливает за миллиард, запросы, которые раньше выполнялись за миллисекунды, начинают тянуться по несколько секунд, а пакетные задачи по несколько часов. Такие просадки в производительности становятся катастрофой для любой системы. А здесь речь идёт о платежах, заказах и бухгалтерских данных финансовой платформы, где бизнес не допускает даже секунды простоя.
Эта статья основана на реальном кейсе и показывает пошаговое решение проблемы. Суть подхода в том, чтобы разбить риски на управляемые этапы: сначала перенести «холодные» неизменяемые данные, обрабатывая их параллельно по шардам по первичному ключу, временно отключив индексы ради ускорения. Затем включить механизм двойной записи: каждая новая транзакция одновременно пишется и в старую, и в новую базу. Неудачные записи отправляются в Kafka для повторных попыток, чтобы гарантировать итоговую согласованность данных.
Самое интересное решение - это фаза «теневого чтения». Пользовательские запросы по-прежнему читаются из старой базы, но в фоне тот же запрос выполняется и на новой, а результаты сравниваются. Этот этап длится несколько недель, и именно за это время команда выявляет проблемы, которые невозможно поймать в тестовой среде: различия в обработке часовых поясов, поведении по умолчанию при NULL-значениях, правилах сортировки символов и т. п. Эти нюансы всплывают только под реальной нагрузкой.
Финальное переключение проводится ранним утром, когда трафик минимален. К этому моменту кэш и индексы новой базы заранее «разогреты» синтетическими запросами. Затем постепенно переводится поток чтений, управляемый через feature-флаги. Команда отслеживает задержки, процент ошибок и бизнес-метрики на дашбордах в Grafana, подтверждая успех миграции только спустя 24 часа стабильной работы.
Такой подход можно смело брать на вооружение при миграциях баз данных, например, в рамках перехода на инфраструктуру Xinchuang. Здесь выделяются три ключевых принципа:
Постепенный контроль рисков: каждый шаг можно проверить и при необходимости откатить.
Валидация на реальном трафике: «теневое чтение» выявляет несовместимости лучше любых тестов.
Наблюдаемость прежде всего: от внутренних WAL-логов и hit-рейтов кэша до бизнес-метрик по заказам и выручке, полный мониторинг позволяет вовремя заметить аномалии.
👉 @BackendPortal
Эта статья основана на реальном кейсе и показывает пошаговое решение проблемы. Суть подхода в том, чтобы разбить риски на управляемые этапы: сначала перенести «холодные» неизменяемые данные, обрабатывая их параллельно по шардам по первичному ключу, временно отключив индексы ради ускорения. Затем включить механизм двойной записи: каждая новая транзакция одновременно пишется и в старую, и в новую базу. Неудачные записи отправляются в Kafka для повторных попыток, чтобы гарантировать итоговую согласованность данных.
Самое интересное решение - это фаза «теневого чтения». Пользовательские запросы по-прежнему читаются из старой базы, но в фоне тот же запрос выполняется и на новой, а результаты сравниваются. Этот этап длится несколько недель, и именно за это время команда выявляет проблемы, которые невозможно поймать в тестовой среде: различия в обработке часовых поясов, поведении по умолчанию при NULL-значениях, правилах сортировки символов и т. п. Эти нюансы всплывают только под реальной нагрузкой.
Финальное переключение проводится ранним утром, когда трафик минимален. К этому моменту кэш и индексы новой базы заранее «разогреты» синтетическими запросами. Затем постепенно переводится поток чтений, управляемый через feature-флаги. Команда отслеживает задержки, процент ошибок и бизнес-метрики на дашбордах в Grafana, подтверждая успех миграции только спустя 24 часа стабильной работы.
Такой подход можно смело брать на вооружение при миграциях баз данных, например, в рамках перехода на инфраструктуру Xinchuang. Здесь выделяются три ключевых принципа:
Постепенный контроль рисков: каждый шаг можно проверить и при необходимости откатить.
Валидация на реальном трафике: «теневое чтение» выявляет несовместимости лучше любых тестов.
Наблюдаемость прежде всего: от внутренних WAL-логов и hit-рейтов кэша до бизнес-метрик по заказам и выручке, полный мониторинг позволяет вовремя заметить аномалии.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2
Podman — «альтернативный» контейнерный рантайм, который на первый взгляд напоминает Docker своими командами «
Начните работу с Podman на https://labs.iximiuz.com/challenges/start-container-with-podman
👉 @BackendPortal
podman pull», «podman run», «podman exec» и т. д. Однако под капотом он использует несколько иную бездемонную архитектуруНачните работу с Podman на https://labs.iximiuz.com/challenges/start-container-with-podman
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥3🤔1
Запросы к базе тормозили. Все винтили базу.
RDS ок: 12% CPU, время запросов меньше 10 мс.
Выяснилось, что на одну загрузку страницы шли 47 последовательных запросов. Каждый быстрый, а вместе это 470 мс чистого ожидания.
Исправили одним SQL JOIN. Узкое место было в логике приложения, не в базе.
👉 @BackendPortal
RDS ок: 12% CPU, время запросов меньше 10 мс.
Выяснилось, что на одну загрузку страницы шли 47 последовательных запросов. Каждый быстрый, а вместе это 470 мс чистого ожидания.
Исправили одним SQL JOIN. Узкое место было в логике приложения, не в базе.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍4
Веб работает поверх HTTP.
А HTTP без состояния: сервер не помнит, что было между запросами.
Если ты переходишь со страницы на страницу, сервер не знает, что это всё ещё ты. Нужно как-то сказать ему: «эй, я тот же самый».
Для этого и существуют Cookies.
Cookie это кусочек данных, который браузер сохраняет и отправляет серверу при каждом запросе.
Классический пример: хранение токена сессии (например, JWT) для авторизации.
Но не все данные стоит отправлять на сервер.
Есть вещи, важные только для интерфейса: тема (светлая/тёмная), язык, прошёл ли пользователь onboarding и т. п.
Для этого есть Web Storage, и у него два варианта:
localStorage — данные сохраняются даже после закрытия браузера.
sessionStorage — очищается, как только закрываешь вкладку.
Итог:
Cookies для данных, которые должны идти на сервер.
Storage для того, что должно оставаться только в браузере.
👉 @BackendPortal
А HTTP без состояния: сервер не помнит, что было между запросами.
Если ты переходишь со страницы на страницу, сервер не знает, что это всё ещё ты. Нужно как-то сказать ему: «эй, я тот же самый».
Для этого и существуют Cookies.
Cookie это кусочек данных, который браузер сохраняет и отправляет серверу при каждом запросе.
Классический пример: хранение токена сессии (например, JWT) для авторизации.
Но не все данные стоит отправлять на сервер.
Есть вещи, важные только для интерфейса: тема (светлая/тёмная), язык, прошёл ли пользователь onboarding и т. п.
Для этого есть Web Storage, и у него два варианта:
localStorage — данные сохраняются даже после закрытия браузера.
sessionStorage — очищается, как только закрываешь вкладку.
Итог:
Cookies для данных, которые должны идти на сервер.
Storage для того, что должно оставаться только в браузере.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍12
Недавно я говорил о том, чтобы просто использовать Postgres вместо Kafka. Вот Apache-лицензированный stateless-прокси для Kafka с подключаемым бэкендом на Postgres (или SQLite, или S3).
Что мешает встроить это прямо в Postgres как расширение?
Такое расширение могло бы предоставлять SQL-функции для pub/sub и поднимать настоящий Kafka TCP-сервер (через background worker). Тогда всё оставалось бы совместимым с Kafka-протоколом прямо внутри базы. И при этом обе части использовали бы одни и те же таблицы.
👉 @BackendPortal
Что мешает встроить это прямо в Postgres как расширение?
Такое расширение могло бы предоставлять SQL-функции для pub/sub и поднимать настоящий Kafka TCP-сервер (через background worker). Тогда всё оставалось бы совместимым с Kafka-протоколом прямо внутри базы. И при этом обе части использовали бы одни и те же таблицы.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍3
Ты логинишься, начинаешь сессию… но для сервера каждый запрос выглядит как новый.
Откуда он знает, что это снова ты?
Для этого и придумали JWT
Это токен, который сервер генерирует, чтобы идентифицировать пользователя. В нем лежат данные вроде id или email, а сам токен подписан секретным ключом, чтобы его нельзя было подделать.
Он не хранит пароли или что-то сверхчувствительное - только минимум, по которому сервер сможет узнать тебя позже.
Схема работает так:
Ты отправляешь логин и пароль на сервер.
Сервер проверяет их, создает JWT и подписывает его секретным ключом.
Токен отправляется в браузер, который сохраняет его, например, в куке.
С каждым новым запросом браузер снова отправляет этот токен.
Сервер проверяет подпись и, если все ок, понимает, что запрос идет от того же пользователя.
Так и работает аутентификация в статeless-среде вроде HTTP.
Иногда используют еще и refresh token, чтобы обновлять JWT, когда тот истечет.
Есть и другие подходы: сервер может хранить сессии у себя и искать нужную запись по каждому запросу.
👉 @BackendPortal
Откуда он знает, что это снова ты?
Для этого и придумали JWT
Это токен, который сервер генерирует, чтобы идентифицировать пользователя. В нем лежат данные вроде id или email, а сам токен подписан секретным ключом, чтобы его нельзя было подделать.
Он не хранит пароли или что-то сверхчувствительное - только минимум, по которому сервер сможет узнать тебя позже.
Схема работает так:
Ты отправляешь логин и пароль на сервер.
Сервер проверяет их, создает JWT и подписывает его секретным ключом.
Токен отправляется в браузер, который сохраняет его, например, в куке.
С каждым новым запросом браузер снова отправляет этот токен.
Сервер проверяет подпись и, если все ок, понимает, что запрос идет от того же пользователя.
Так и работает аутентификация в статeless-среде вроде HTTP.
Иногда используют еще и refresh token, чтобы обновлять JWT, когда тот истечет.
Есть и другие подходы: сервер может хранить сессии у себя и искать нужную запись по каждому запросу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤8😁1
Разработчик объявил о завершении работы над Conflux — модульным акторным движком для совместной работы в реальном времени, написанным на Rust.
В проекте используются CRDT через Yrs, комнатный WebSocket и акторная модель для конкурентности. В свежую версию добавлены JWT, аутентификация, трекинг сессий, синхронизация awareness и дашборд-эндпоинт для просмотра активных комнат.
Каждая комната изолирована и живёт по своему циклу: поднимается, работает и очищается автоматически.
Исходники уже доступны на GitHub, а позже автор опубликует блог с подробностями архитектуры и объяснением, как под капотом устроена синхронизация CRDT.
👉 @BackendPortal
В проекте используются CRDT через Yrs, комнатный WebSocket и акторная модель для конкурентности. В свежую версию добавлены JWT, аутентификация, трекинг сессий, синхронизация awareness и дашборд-эндпоинт для просмотра активных комнат.
Каждая комната изолирована и живёт по своему циклу: поднимается, работает и очищается автоматически.
Исходники уже доступны на GitHub, а позже автор опубликует блог с подробностями архитектуры и объяснением, как под капотом устроена синхронизация CRDT.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔6❤1
Стратегии версионирования API:
1. Версионирование через URI— добавление номера версии в URL для ясности и простоты.
Пример:
2. Версионирование через путь — версия встраивается непосредственно в путь API для наглядности.
Пример:
3. Query Parameter Versioning — версия указывается как параметр запроса, сохраняя чистоту структуры URL.
Пример:
4. Subdomain Versioning — для каждой версии используются отдельные поддомены, полностью разделяя их.
Пример:
5. Header Versioning — версия передаётся в заголовках запроса, URL остаётся неизменным.
Пример:
6. Timestamp Versioning — версии основаны на временных метках, что обеспечивает гибкость при релизах.
Пример:
7. Content Negotiation — использует заголовок
Пример:
8. Semantic Versioning — следует семантическому версионированию (например,
Пример:
👉 @BackendPortal
1. Версионирование через URI— добавление номера версии в URL для ясности и простоты.
Пример:
/api/v1/products.2. Версионирование через путь — версия встраивается непосредственно в путь API для наглядности.
Пример:
/api/v2/products.3. Query Parameter Versioning — версия указывается как параметр запроса, сохраняя чистоту структуры URL.
Пример:
/api/products?version=1.4. Subdomain Versioning — для каждой версии используются отдельные поддомены, полностью разделяя их.
Пример:
v2.api.example.com/products.5. Header Versioning — версия передаётся в заголовках запроса, URL остаётся неизменным.
Пример:
GET /products Header: Accept: application/vnd.example.v1+json.6. Timestamp Versioning — версии основаны на временных метках, что обеспечивает гибкость при релизах.
Пример:
/api/products?version=2023-10-01.7. Content Negotiation — использует заголовок
Accept для запроса разных версий и форматов. Пример:
GET /products Header: Accept: application/json; version=1.8. Semantic Versioning — следует семантическому версионированию (например,
v1.0.0) для обозначения основных, второстепенных и патчевых изменений. Пример:
/api/products/v1.0.0Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Насколько быстро каждый язык перемножает две матрицы 1000×1000?
Примерные бенчмарки:
C++: ~220 мс
Rust: ~250 мс
Go: ~500 мс
Java: ~700 мс
Python (NumPy): ~80 мс*
JS: ~3 с
*NumPy под капотом дергает оптимизированный C/BLAS – на чистом Python это заняло бы несколько секунд.
Перемножение матриц – вычислительно тяжелая задача, в которой основную роль играют операции с плавающей запятой и работа с кэшем.
Большинство реализаций используют классический тройной цикл O(n³), который отлично подходит для проверки сырой производительности CPU и того, насколько хорошо компилятор оптимизирует вложенные циклы.
👉 @BackendPortal
Примерные бенчмарки:
C++: ~220 мс
Rust: ~250 мс
Go: ~500 мс
Java: ~700 мс
Python (NumPy): ~80 мс*
JS: ~3 с
*NumPy под капотом дергает оптимизированный C/BLAS – на чистом Python это заняло бы несколько секунд.
Перемножение матриц – вычислительно тяжелая задача, в которой основную роль играют операции с плавающей запятой и работа с кэшем.
Большинство реализаций используют классический тройной цикл O(n³), который отлично подходит для проверки сырой производительности CPU и того, насколько хорошо компилятор оптимизирует вложенные циклы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4
Уменьшил размер Docker-образа с 2.1GB до 180MB. Деплой стал в 8 раз быстрее.
Как выглядел исходный Dockerfile:
Проблемы:
Что изменили:
1. Базовый образ
ubuntu:latest (2.1GB) → alpine:latest (5MB)
2. Зависимости
3. Оптимизация слоев
4. .dockerignore
Исключили .git, tests, docs
Минус 800MB мусора
Итоговый размер: 180MB
Результат:
Pull: 6 минут → 45 секунд
Сборка: 8 минут → 2 минуты
Частота деплоев: 2 раза в день → 15 раз
Стоимость registry: $340/мес → $60/мес
Уязвимости: 47 → 3
Старт pod в Kubernetes: 90 секунд → 12 секунд
Каждый мегабайт в образе стоит времени и денег. Оптимизируй Docker-образы так же, как оптимизируешь код.
👉 @BackendPortal
Как выглядел исходный Dockerfile:
Брался ubuntu:latest
Все ставилось через apt
В образ попадали дев зависимости
Копировалась вся директория проекта
Остались билд-артефакты
Не было оптимизации слоев
Проблемы:
Pull занимал 6–8 минут
Хранилище в registry стоило дорого
Деплой тянулся слишком долго
Скан безопасности показал 47 уязвимостей
Большинство — из ненужных пакетов
Что изменили:
1. Базовый образ
ubuntu:latest (2.1GB) → alpine:latest (5MB)
2. Зависимости
Убрали дев зависимости
Использовали multi-stage build
В прод версию попали только нужные пакеты
3. Оптимизация слоев
Сначала копировали requirements
Устанавливали зависимости
Потом копировали исходники
Использовали кэш слоев Docker
4. .dockerignore
Исключили .git, tests, docs
Минус 800MB мусора
Итоговый размер: 180MB
Результат:
Pull: 6 минут → 45 секунд
Сборка: 8 минут → 2 минуты
Частота деплоев: 2 раза в день → 15 раз
Стоимость registry: $340/мес → $60/мес
Уязвимости: 47 → 3
Старт pod в Kubernetes: 90 секунд → 12 секунд
Каждый мегабайт в образе стоит времени и денег. Оптимизируй Docker-образы так же, как оптимизируешь код.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13💊6🤔4😁2🔥1
Когда нужно работать с данными в реальном времени, обычный HTTP не лучший вариант.
В HTTP клиент отправляет запрос, сервер отвечает и соединение закрывается. И важный момент: коммуникацию всегда инициирует клиент.
Для статей или обычных страниц это норм. Но если ты пишешь чат, такой подход развалится.
Придётся каждые пару секунд спрашивать сервер: "Есть новые сообщения?" Это грузит CPU, создаёт кучу лишних запросов и добавляет задержку. Такой подход называется polling.
Чтобы это решить, появился WebSocket.
Главная идея:
Примерный флоу:
Клиент делает обычный запрос, но с заголовком upgrade, предлагая переключить протокол.
Сервер принимает.
Открывается постоянный двунаправленный канал.
После этого любая сторона может слать сообщения без ожидания запроса.
Теперь сервер может сразу уведомить клиента о новом сообщении. Без polling, с минимальной задержкой.
WebSocket используют в чатах, играх, лайв-дашбордах и совместной работе вроде Google Docs.
Но важно понимать: WebSocket нужен не всегда.
Если UI не меняется постоянно на глазах у пользователя, обычного HTTP более чем достаточно.
Чтобы проще запомнить:
HTTP это как письма.
WebSocket это телефонный звонок.
👉 @BackendPortal
В HTTP клиент отправляет запрос, сервер отвечает и соединение закрывается. И важный момент: коммуникацию всегда инициирует клиент.
Для статей или обычных страниц это норм. Но если ты пишешь чат, такой подход развалится.
Придётся каждые пару секунд спрашивать сервер: "Есть новые сообщения?" Это грузит CPU, создаёт кучу лишних запросов и добавляет задержку. Такой подход называется polling.
Чтобы это решить, появился WebSocket.
Главная идея:
"Соединение остаётся открытым, и обе стороны могут общаться когда захотят."
Примерный флоу:
Клиент делает обычный запрос, но с заголовком upgrade, предлагая переключить протокол.
Сервер принимает.
Открывается постоянный двунаправленный канал.
После этого любая сторона может слать сообщения без ожидания запроса.
Теперь сервер может сразу уведомить клиента о новом сообщении. Без polling, с минимальной задержкой.
WebSocket используют в чатах, играх, лайв-дашбордах и совместной работе вроде Google Docs.
Но важно понимать: WebSocket нужен не всегда.
Если UI не меняется постоянно на глазах у пользователя, обычного HTTP более чем достаточно.
Чтобы проще запомнить:
HTTP это как письма.
WebSocket это телефонный звонок.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🔥3🤔1
Заголовки безопасности сломали мобильное приложение
Никто не протестировал мобилку — и вот что получилось.
Что изменили
- Добавили security headers в API:
-
-
-
-
- Почувствовали себя уверенно насчет безопасности
Что пошло не так
- Деплой в пятницу вечером
- Веб-приложение работало нормально
- Мобильное приложение полностью упало
- Данные не грузились
- Итог: инцидент на выходных
Расследование
- API показывал успешные запросы
- Логи мобильного клиента показывали ошибки
- Ответы:
- Но мобильное приложение получало пустые данные
- Сетевой слой просто отбрасывал ответы
Виновник
-
- Приложение использовало встроенный WebView
- CSP блокировал WebView при обработке ответов
- Браузерные правила безопасности применялись в мобильном контексте
- Хедер предназначен для браузеров, а не для API
Почему это пропустили
- Тестировали только веб
- Мобильная команда не была подключена к изменению
- Не было mobile testing в staging
- Предположили, что заголовки безопасны "по умолчанию"
- Не было feature-флагов для отката
Экстренный фикс
- Временно удалили CSP
- Горячий фикс в production
- Мобилка снова заработала
- Итого: 8 часов даунтайма
Правильное решение
- Разные заголовки для API и веба
- Логика на основе
- Отдельная CSP-политика для мобильных клиентов
- Полное кроссплатформенное тестирование
- Feature-флаги для security-изменений
Урон
- Даунтайм: 2 часа
- Затронутых пользователей: 125 000
- Рейтинг в сторе: 4.7
Security headers не универсальны.
Тестируйте на всех платформах.
Web security и API security — разные вещи.
👉 @BackendPortal
Никто не протестировал мобилку — и вот что получилось.
Что изменили
- Добавили security headers в API:
-
Content-Security-Policy-
X-Frame-Options-
X-Content-Type-Options-
Strict-Transport-Security- Почувствовали себя уверенно насчет безопасности
Что пошло не так
- Деплой в пятницу вечером
- Веб-приложение работало нормально
- Мобильное приложение полностью упало
- Данные не грузились
- Итог: инцидент на выходных
Расследование
- API показывал успешные запросы
- Логи мобильного клиента показывали ошибки
- Ответы:
200 OK- Но мобильное приложение получало пустые данные
- Сетевой слой просто отбрасывал ответы
Виновник
-
Content-Security-Policy- Приложение использовало встроенный WebView
- CSP блокировал WebView при обработке ответов
- Браузерные правила безопасности применялись в мобильном контексте
- Хедер предназначен для браузеров, а не для API
Почему это пропустили
- Тестировали только веб
- Мобильная команда не была подключена к изменению
- Не было mobile testing в staging
- Предположили, что заголовки безопасны "по умолчанию"
- Не было feature-флагов для отката
Экстренный фикс
- Временно удалили CSP
- Горячий фикс в production
- Мобилка снова заработала
- Итого: 8 часов даунтайма
Правильное решение
- Разные заголовки для API и веба
- Логика на основе
User-Agent- Отдельная CSP-политика для мобильных клиентов
- Полное кроссплатформенное тестирование
- Feature-флаги для security-изменений
Урон
- Даунтайм: 2 часа
- Затронутых пользователей: 125 000
- Рейтинг в сторе: 4.7
Security headers не универсальны.
Тестируйте на всех платформах.
Web security и API security — разные вещи.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥3👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Разработчик ускорил загрузку сайта при работе в браузере ladybird почти в три раза. Время рендера сократилось примерно с одной секунды до четырёхсот миллисекунд.
Оптимизация получилась за счёт двух изменений:
- в HTTP-кеш добавили поддержку heuristic freshness lifetime в соответствии с RFC 9110 и 9111
- рендер теперь стартует только после получения всех CSS-импортов, так что эффект FOUC больше не появляется
👉 @BackendPortal
Оптимизация получилась за счёт двух изменений:
- в HTTP-кеш добавили поддержку heuristic freshness lifetime в соответствии с RFC 9110 и 9111
- рендер теперь стартует только после получения всех CSS-импортов, так что эффект FOUC больше не появляется
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤4
Большинство споров про Docker рано или поздно приходят к одному вопросу: slim или alpine, какой базовый образ выбрать?
Alpine очень маленький, выглядит привлекательно, если хочется сильно урезать размер образа. Но он использует musl вместо glibc, поэтому некоторые приложения ведут себя иначе, часть библиотек работает криво, а отладка может превратиться
Хороший вариант, если у тебя простое приложение или статический бинарник без кучи зависимостей на уровне ОС.
Slim-образы, вроде debian:slim или node:22-slim, больше Alpine, но всё ещё намного легче полноценных системных образов.
Они используют glibc, так что большинство тулов и библиотек работает нормально.
Обычно это означает меньше сюрпризов в проде, проще дебаг и лучше совместимость с документацией и примерами в сети.
Для большинства веб-приложений, API и инструментов slim = более безопасный выбор по умолчанию. Размер образа всё ещё небольшой, скачивается быстро, безопасность ок, и при этом не приходится ловить странные баги, связанные с musl.
Alpine имеет смысл, если ты:
👉 @BackendPortal
Alpine очень маленький, выглядит привлекательно, если хочется сильно урезать размер образа. Но он использует musl вместо glibc, поэтому некоторые приложения ведут себя иначе, часть библиотек работает криво, а отладка может превратиться
Хороший вариант, если у тебя простое приложение или статический бинарник без кучи зависимостей на уровне ОС.
Slim-образы, вроде debian:slim или node:22-slim, больше Alpine, но всё ещё намного легче полноценных системных образов.
Они используют glibc, так что большинство тулов и библиотек работает нормально.
Обычно это означает меньше сюрпризов в проде, проще дебаг и лучше совместимость с документацией и примерами в сети.
Для большинства веб-приложений, API и инструментов slim = более безопасный выбор по умолчанию. Размер образа всё ещё небольшой, скачивается быстро, безопасность ок, и при этом не приходится ловить странные баги, связанные с musl.
Alpine имеет смысл, если ты:
поставляешь один статический бинарник
хорошо понимаешь свои зависимости
готов разруливать совместимость, если что-то поедет боком
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥4🤔1
Вопрос:
Поздравляю. У тебя есть заказ на товар, которого нет на складе.
И как ты это будешь фиксить?
👉 @BackendPortal
try {
call_order_service();
call_inventory_service(); // уменьшаем остатки
} catch (Exception e) {
// лол, и что теперь? Заказ уже создан.
}Поздравляю. У тебя есть заказ на товар, которого нет на складе.
И как ты это будешь фиксить?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1🔥1
Случайные UUID заметно просаживают производительность базы
Ты перешел с integer ID (1, 2, 3…) на UUID (a1b2-3c4d-…) ради безопасности или распределенной генерации.
И вдруг вставки стали медленнее. Иногда намного.
Причина простая - фрагментация индекса.
Большинство индексов в базах данных это B-деревья (сбалансированные сортированные структуры). Физическое расположение данных в индексе реально важно.
Последовательные ID
Когда ты вставляешь последовательные целые числа (1, 2, 3), новые записи всегда попадают в правую страницу листа индекса.
Все максимально предсказуемо:
- записи идут последовательно
- кэш работает эффективно
- страницы заполняются полностью
Это почти максимальная скорость, на которую способна твоя база.
Случайные UUIDv4
UUIDv4 генерируются равномерно случайно. Вставка может попасть в любое место структуры B-дерева.
Из-за хаотичного распределения:
База должна постоянно подгружать случайные страницы с диска в память. Это random I/O.
Page splitting: когда страница заполнена, ее приходится делить на две, оставляя обе наполовину пустыми.
Эффект "швейцарского сыра": индекс раздувается, полон дыр и плохо использует RAM и место на диске.
Когда размер индекса превышает доступную оперативку, пропускная способность записи может просесть на 20–90%.
UUIDv7
Хватит использовать UUIDv4 в качестве primary key. Переходи на UUIDv7 (стандарт RFC 9562).
UUIDv7 содержит timestamp в начале, так что значения становятся сортируемыми.
Что это дает:
Генерация без центрального счетчика
Вставки идут монотонно, почти как обычные последовательные числа
Фрагментация индекса исчезает
Защита от угадывания ID (хотя по ID можно понять время вставки)
Получается удобство UUID, но без потерь по производительности.
Короче, UUIDv7 норм. UUIDv4 не особо, если используешь как primary key.
👉 @BackendPortal
Ты перешел с integer ID (1, 2, 3…) на UUID (a1b2-3c4d-…) ради безопасности или распределенной генерации.
И вдруг вставки стали медленнее. Иногда намного.
Причина простая - фрагментация индекса.
Большинство индексов в базах данных это B-деревья (сбалансированные сортированные структуры). Физическое расположение данных в индексе реально важно.
Последовательные ID
Когда ты вставляешь последовательные целые числа (1, 2, 3), новые записи всегда попадают в правую страницу листа индекса.
Все максимально предсказуемо:
- записи идут последовательно
- кэш работает эффективно
- страницы заполняются полностью
Это почти максимальная скорость, на которую способна твоя база.
Случайные UUIDv4
UUIDv4 генерируются равномерно случайно. Вставка может попасть в любое место структуры B-дерева.
Из-за хаотичного распределения:
База должна постоянно подгружать случайные страницы с диска в память. Это random I/O.
Page splitting: когда страница заполнена, ее приходится делить на две, оставляя обе наполовину пустыми.
Эффект "швейцарского сыра": индекс раздувается, полон дыр и плохо использует RAM и место на диске.
Когда размер индекса превышает доступную оперативку, пропускная способность записи может просесть на 20–90%.
UUIDv7
Хватит использовать UUIDv4 в качестве primary key. Переходи на UUIDv7 (стандарт RFC 9562).
UUIDv7 содержит timestamp в начале, так что значения становятся сортируемыми.
Что это дает:
Генерация без центрального счетчика
Вставки идут монотонно, почти как обычные последовательные числа
Фрагментация индекса исчезает
Защита от угадывания ID (хотя по ID можно понять время вставки)
Получается удобство UUID, но без потерь по производительности.
Короче, UUIDv7 норм. UUIDv4 не особо, если используешь как primary key.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤4🔥4🤔1
SQL + SELECT = выбор данных
SQL + JOIN = объединение данных
SQL + WHERE = фильтрация
SQL + GROUP BY = агрегация
SQL + ORDER BY = сортировка
SQL + UNION = объединение запросов
SQL + INSERT = добавление записей
SQL + UPDATE = изменение данных
SQL + DELETE = удаление записей
SQL + CREATE TABLE = проектирование структуры
SQL + ALTER TABLE = изменение схемы
SQL + DROP TABLE = удаление таблицы
SQL + INDEX = ускорение запросов
SQL + VIEW = виртуальные таблицы
SQL + подзапросы = вложенные запросы
SQL + хранимые процедуры = автоматизация задач
SQL + триггеры = автоматические реакции на события
SQL + CTE = рекурсивные запросы
SQL + оконные функции = продвинутая аналитика
SQL + транзакции = целостность данных
SQL + ACID = надежные операции
SQL + хранилища данных = работа с большими объёмами
SQL + ETL = преобразование данных
SQL + партиционирование = работа с большими таблицами
SQL + репликация = высокая доступность
SQL + шардинг = масштабирование базы
SQL + JSON = полуструктурированные данные
SQL + XML = структурированные данные
SQL + безопасность данных = защита информации
SQL + оптимизация запросов = повышение производительности
SQL + управление данными = контроль качества данных
Please open Telegram to view this post
VIEW IN TELEGRAM
💊12❤6🔥2😁1
25 золотых правил системного дизайна
👉 @BackendPortal
1. Система с упором на чтение
> Используй кэш (Redis/Memcached) для частых запросов вроде профилей пользователей
2. Низкая задержка
> Используй кэш и CDN (Cloudflare), чтобы раздавать статику ближе к пользователю
3. Система с упором на запись
> Используй Message Queue (Kafka) для буферизации большого объема записей (логи, аналитика)
4. ACID-требования
> Используй SQL (PostgreSQL) для строгих транзакций вроде банковских операций
5. Неструктурированные данные
> Используй NoSQL (MongoDB) для гибких схем, например каталогов товаров
6. Сложные медиа-ресурсы
> Используй Blob Storage (AWS S3) для видео, изображений и больших файлов
7. Сложные предварительные расчёты
> Используй Message Queue + Cache для асинхронной генерации контента (например ленты новостей)
8. Поиск при больших объемах данных
> Используй Elasticsearch для полнотекстового поиска и автокомплита
9. Масштабирование SQL
> Используй шардирование, чтобы разделить большие таблицы на несколько инстансов
10. Высокая доступность
> Используй Load Balancer (NGINX) чтобы распределять трафик и избегать перегрузки
11. Глобальная доставка данных
> Используй CDN для стабильного стриминга и раздачи контента по всему миру
12. Графовые данные
> Используй Graph DB (Neo4j) для соцсетей, рекомендаций и связей между сущностями
13. Масштабирование компонентов
> Используй горизонтальное масштабирование, а не просто апгрейд железа
14. Быстрые запросы к базе
> Используй индексы на ключевых колонках вроде email или user_id
15. Пакетные задачи
> Используй Batch Processing для отчётов, расчётов или периодических задач
16. Защита от злоупотреблений
> Используй Rate Limiter, чтобы предотвращать DDoS и спам запросов к API
17. Доступ к микросервисам
> Используй API Gateway для авторизации, маршрутизации и SSL-терминации
18. Единая точка отказа
> Добавляй Redundancy (Active-Passive), чтобы сервис продолжал работать при сбоях
19. Отказоустойчивость данных
> Используй репликацию (Master-Slave), чтобы данные не терялись при падении узлов
20. Реальное время
> Используй WebSockets для чатов, лайв-обновлений, лайв-результатов
21. Обнаружение сбоев
> Используй Heartbeat-пинг, чтобы проверять статус сервисов каждые несколько секунд
22. Целостность данных
> Используй Checksums (MD5/SHA) чтобы проверить, что загруженные файлы не повреждены
23. Децентрализованное состояние
> Используй Gossip Protocol, чтобы ноды обменивались статусами без центрального сервера
24. Эффективное кеширование
> Используй Consistent Hashing, чтобы добавлять или убирать кэш-ноды без полного пересчёта ключей
25. Работа с геоданными
> Используй Quadtree или Geohash для быстрых запросов вроде поиска ближайших водителей
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Хочешь избежать проблем, когда Cloudflare падает?
Или когда La Liga блокирует твои страницы?
Разработчик сделал open-source CLI, чтобы можно было легко отключать этот сервис в проектах за пару секунд.
👉 @BackendPortal
Или когда La Liga блокирует твои страницы?
Разработчик сделал open-source CLI, чтобы можно было легко отключать этот сервис в проектах за пару секунд.
$ npx disable-cloudflare@latest
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9