Мы прогнали проверку безопасности. У 90% наших K8s pod'ов оказался примонтирован Service Account token в /var/run/secrets/...
Мы спросили у разработчиков: вы вообще используете это для обращения к K8s API?
Ответ: нет.
Проблема в том, что automountServiceAccountToken по умолчанию true. Токен получает каждый pod, даже если он ему вообще не нужен.
Риск огромный. Если pod взломали (например, через SSRF), атакер сразу получает токен для запросов к API.
Фикс: теперь по умолчанию ставим automountServiceAccountToken: false на всех Deployment'ах
👉 @BackendPortal
Мы спросили у разработчиков: вы вообще используете это для обращения к K8s API?
Ответ: нет.
Проблема в том, что automountServiceAccountToken по умолчанию true. Токен получает каждый pod, даже если он ему вообще не нужен.
Риск огромный. Если pod взломали (например, через SSRF), атакер сразу получает токен для запросов к API.
Фикс: теперь по умолчанию ставим automountServiceAccountToken: false на всех Deployment'ах
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Хочешь быструю базу? Выбирай диск с головой.
EBS подходит для нагрузок с небольшим количеством операций ввода-вывода. Но если нагрузка серьезная, он быстро превращается либо в узкое место, либо в черную дыру бюджета.
Самые частые варианты EBS: gp3 и io2. Оба — сетевые SSD, но по скорости заметно отличаются.
gp3 дешевле, но сильно ограничен по IOPS (максимум 16k) и по скорости ощущается слабее, чем io2.
io2 может выдавать до 64k IOPS (256k c Block Express) и обычно работает очень бодро. Но стоит БОЛЬШИХ денег. Переход с gp3 на io2 легко умножает стоимость хранилища раза в пять.
Лучший вариант? Локальные NVMe диски. Они самые быстрые и часто самые выгодные по деньгам. Если позаботиться о репликации и безопасности данных, это просто победа для производительности базы.
👉 @BackendPortal
EBS подходит для нагрузок с небольшим количеством операций ввода-вывода. Но если нагрузка серьезная, он быстро превращается либо в узкое место, либо в черную дыру бюджета.
Самые частые варианты EBS: gp3 и io2. Оба — сетевые SSD, но по скорости заметно отличаются.
gp3 дешевле, но сильно ограничен по IOPS (максимум 16k) и по скорости ощущается слабее, чем io2.
io2 может выдавать до 64k IOPS (256k c Block Express) и обычно работает очень бодро. Но стоит БОЛЬШИХ денег. Переход с gp3 на io2 легко умножает стоимость хранилища раза в пять.
Лучший вариант? Локальные NVMe диски. Они самые быстрые и часто самые выгодные по деньгам. Если позаботиться о репликации и безопасности данных, это просто победа для производительности базы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2
В распределенных системах обычно используют два подхода к хешированию. Выбор зависит от компромиссов.
Consistent hashing делает упор на скорость поиска и масштабируемость.
Rendezvous hashing ставит на первое место равномерное распределение нагрузки.
Суть простая:
• для каждого ключа считаем рейтинг всех серверов
• ключ уходит на сервер с максимальным рейтингом
• при добавлении или удалении серверов нужно сохранить эту схему
Рейтинг считается так: берем ключ, по очереди хешируем вместе с каждым сервером. Сервер с наибольшим значением хеша назначается для этого ключа.
Если сервер S удаляется, переназначаются только те ключи, для которых S был лучшим. Они переходят на сервер со вторым по величине рейтингом. Если сервер S добавляется, только те ключи, у которых S окажется выше всех в рейтинге, переедут на него.
Обычный rendezvous hashing — O(N) по времени на расчет хешей для каждого ключа. Есть вариант (skeleton-based), который сокращает это до O(log N). Дополнительная память не нужна, потому что рейтинг для ключа считается динамически.
👉 @BackendPortal
Consistent hashing делает упор на скорость поиска и масштабируемость.
Rendezvous hashing ставит на первое место равномерное распределение нагрузки.
Суть простая:
• для каждого ключа считаем рейтинг всех серверов
• ключ уходит на сервер с максимальным рейтингом
• при добавлении или удалении серверов нужно сохранить эту схему
Рейтинг считается так: берем ключ, по очереди хешируем вместе с каждым сервером. Сервер с наибольшим значением хеша назначается для этого ключа.
Если сервер S удаляется, переназначаются только те ключи, для которых S был лучшим. Они переходят на сервер со вторым по величине рейтингом. Если сервер S добавляется, только те ключи, у которых S окажется выше всех в рейтинге, переедут на него.
Обычный rendezvous hashing — O(N) по времени на расчет хешей для каждого ключа. Есть вариант (skeleton-based), который сокращает это до O(log N). Дополнительная память не нужна, потому что рейтинг для ключа считается динамически.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Большинство инженеров действительно начинают не с той стороны.
Сначала накидывают Kubernetes, Terraform, сервис-меш, мониторинг, а потом удивляются, почему всё тормозит и разваливается под нагрузкой.
Хороший порядок обучения выглядит примерно так:
- Сети
Разобраться что такое TCP, что внутри HTTP, зачем нужен DNS, как работает routing и чем задержка отличается от пропускной способности.
Без этого все последующие знания, как дом на песке.
- Базы данных
Индексирование, транзакции, репликация, шардинг.
Если не понимаешь как хранить и доставать данные = не понимаешь как масштабировать систему.
- Кэширование
Redis, мемкеш, CDN.
Правильно закэшировал = снял 70 процентов нагрузки.
- Очереди и стримы
Kafka, RabbitMQ и прочие.
Это подушка безопасности, когда трафик внезапно летит очень сильно
- Балансировка нагрузки
Разные стратегии, sticky-сессии, health-checks.
Если не умеешь равномерно раскладывать запросы, то горизонтальное масштабирование превращается в клоунаду🤡
- Практика на классических задачах
Сократи ссылки.
Ограничь скорость.
Сделай чат, ленту новостей, уведомления.
Боевое обучение без огромных рисков.
- Пост-мортемы
Лучший учитель — чужой факап.
Читаешь разбор инцидентов и видишь закономерности.
В итоге ты начинаешь думать не о «микросервисной архитектуре ради микросервисов», а о базовых законах:
задержка, надежность, пропускная способность, доступность, деньги.
Вот когда у тебя это в голове, то любые диаграммы становятся просто формой записи мыслей, а не магией бога-DevOps.
👉 @BackendPortal
Сначала накидывают Kubernetes, Terraform, сервис-меш, мониторинг, а потом удивляются, почему всё тормозит и разваливается под нагрузкой.
Хороший порядок обучения выглядит примерно так:
- Сети
Разобраться что такое TCP, что внутри HTTP, зачем нужен DNS, как работает routing и чем задержка отличается от пропускной способности.
Без этого все последующие знания, как дом на песке.
- Базы данных
Индексирование, транзакции, репликация, шардинг.
Если не понимаешь как хранить и доставать данные = не понимаешь как масштабировать систему.
- Кэширование
Redis, мемкеш, CDN.
Правильно закэшировал = снял 70 процентов нагрузки.
- Очереди и стримы
Kafka, RabbitMQ и прочие.
Это подушка безопасности, когда трафик внезапно летит очень сильно
- Балансировка нагрузки
Разные стратегии, sticky-сессии, health-checks.
Если не умеешь равномерно раскладывать запросы, то горизонтальное масштабирование превращается в клоунаду
- Практика на классических задачах
Сократи ссылки.
Ограничь скорость.
Сделай чат, ленту новостей, уведомления.
Боевое обучение без огромных рисков.
- Пост-мортемы
Лучший учитель — чужой факап.
Читаешь разбор инцидентов и видишь закономерности.
В итоге ты начинаешь думать не о «микросервисной архитектуре ради микросервисов», а о базовых законах:
задержка, надежность, пропускная способность, доступность, деньги.
Вот когда у тебя это в голове, то любые диаграммы становятся просто формой записи мыслей, а не магией бога-DevOps.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥1
Учебник по Java от Андрея Иванцова теперь доступен онлайн на GitBook. В нём собрано всё, что нужно новичку: от простых типов данных и строк до исключений и коллекций. Материал подан по делу, с примерами кода и понятными объяснениями.
Ссылка для тех, кто хочет прокачаться: andrey-ivantsov.gitbook.io/java
👉 @BackendPortal
Ссылка для тех, кто хочет прокачаться: andrey-ivantsov.gitbook.io/java
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Знал, что у Git есть свой собственный сетевой протокол?
Он не использует HTTP, а гоняет бинарный протокол поверх сырого TCP, построенный на формате передачи pkt-line.
Можно глянуть, как это работает, если выставить переменную окружения GIT_TRACE_PACKET=1. Тогда видно, как Git в реальном времени общается с удалённым репозиторием.
Pkt-line это бинарная строка переменной длины. Первые четыре байта содержат длину всей строки в шестнадцатеричном виде. Это значение включает и сами эти четыре байта.
Git отправляет пачку строк want и have, чтобы показать, какие объекты ему нужны. Сервер отвечает сжатыми pack-файлами только с недостающими данными. В итоге получается минимальный и очень компактный бинарный поток с низкими задержками, который отлично масштабируется на огромных репах.
По сравнению с HTTPS этот родной протокол быстрее, потому что ему не мешают HTTP-заголовки, TLS-рукопожатия и статлесс-циклы запросов. Это постоянный двунаправленный канал, заточенный под Git’овскую модель данных.
И да: свой протокол у Git появился потому, что иногда нужен транспорт, спроектированный под твою граф-структуру объектов.
👉 @BackendPortal
Он не использует HTTP, а гоняет бинарный протокол поверх сырого TCP, построенный на формате передачи pkt-line.
Можно глянуть, как это работает, если выставить переменную окружения GIT_TRACE_PACKET=1. Тогда видно, как Git в реальном времени общается с удалённым репозиторием.
Pkt-line это бинарная строка переменной длины. Первые четыре байта содержат длину всей строки в шестнадцатеричном виде. Это значение включает и сами эти четыре байта.
Git отправляет пачку строк want и have, чтобы показать, какие объекты ему нужны. Сервер отвечает сжатыми pack-файлами только с недостающими данными. В итоге получается минимальный и очень компактный бинарный поток с низкими задержками, который отлично масштабируется на огромных репах.
По сравнению с HTTPS этот родной протокол быстрее, потому что ему не мешают HTTP-заголовки, TLS-рукопожатия и статлесс-циклы запросов. Это постоянный двунаправленный канал, заточенный под Git’овскую модель данных.
И да: свой протокол у Git появился потому, что иногда нужен транспорт, спроектированный под твою граф-структуру объектов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
У SQL есть решение почти под любую задачу с данными. Освой его по-серьёзке и жизнь станет проще.
Вот самый простой способ вывести отчёт по продажам.
Если делаешь отчёты, одних итогов мало.
Нужны подытоги.
И вот тут все обычно косячат. Пишут GROUP BY… и забывают про WITH ROLLUP.
Пример.
Есть таблица Sales с такими полями:
И тебе нужно получить отчёт: подытоги по каждому товару и один общий итог по всем.
Один GROUP BY этого не сделает.
WITH ROLLUP — сделает.
WITH ROLLUP используется вместе с GROUP BY, чтобы добавить строки с суммами: подытоги и общий итог.
Что фактически делает WITH ROLLUP:
Обычные строки: каждая комбинация product + region и её сумма продаж.
Подытоги: там, где region = NULL, показывается сумма по товару.
Общий итог: product = NULL и region = NULL — сумма всех продаж.
Вот разница между «уметь писать SQL» и «знать SQL».
👉 @BackendPortal
Вот самый простой способ вывести отчёт по продажам.
Если делаешь отчёты, одних итогов мало.
Нужны подытоги.
И вот тут все обычно косячат. Пишут GROUP BY… и забывают про WITH ROLLUP.
Пример.
Есть таблица Sales с такими полями:
product — название товара
region — регион продаж
sales_amount — сумма продаж
И тебе нужно получить отчёт: подытоги по каждому товару и один общий итог по всем.
Один GROUP BY этого не сделает.
WITH ROLLUP — сделает.
WITH ROLLUP используется вместе с GROUP BY, чтобы добавить строки с суммами: подытоги и общий итог.
Что фактически делает WITH ROLLUP:
Обычные строки: каждая комбинация product + region и её сумма продаж.
Подытоги: там, где region = NULL, показывается сумма по товару.
Общий итог: product = NULL и region = NULL — сумма всех продаж.
Вот разница между «уметь писать SQL» и «знать SQL».
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍5
Media is too big
VIEW IN TELEGRAM
Хочешь лучше разобраться в B-деревьях?
Попробуй http://btree.app Это отдельные песочницы с визуализациями, которые сделаны для статьи про B-деревья и индексы в базах данных. Полезно, чтобы понять вставку, поиск и расщепление узлов в B-деревьях.
Если вы не видели статью, которая сопровождает это: вот
👉 @BackendPortal
Попробуй http://btree.app Это отдельные песочницы с визуализациями, которые сделаны для статьи про B-деревья и индексы в базах данных. Полезно, чтобы понять вставку, поиск и расщепление узлов в B-деревьях.
Если вы не видели статью, которая сопровождает это: вот
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Cloudflare поделилась цифрами про интернет-трафик в больших масштабах, и там много любопытного.
Половина всех TCP-соединений укладывается всего в 12 пакетов или меньше. Средний ответ от серверов Cloudflare — примерно 4,8 КБ для HTTP/1.X и около 6 КБ для HTTP/2. Большинство веб-запросов мизерные.
А вот что интересно дальше. Хотя средняя длительность соединения всего 4,7 секунды, некоторые живут сутками. При этом среднее соединение отправляет в 3,78 раза больше данных, чем получает. Веб сильно завязан на загрузку контента.
Распределение классическое — «слоны и мыши». Маленькая доля соединений гоняет миллионы пакетов (стриминг, большие загрузки), тогда как огромная часть — крошечные (API, мелкие ресурсы веб-страниц).
В большинстве соединений проходит всего один HTTP-запрос, даже несмотря на мультиплексирование в HTTP/2. Это касается как пользовательского трафика, так и автоматических запросов из дата-центров.
Интернет гораздо более всплесковый и мимолётный, чем может казаться.
Надеюсь, тебе тоже показалось это занятным.
👉 @BackendPortal
Половина всех TCP-соединений укладывается всего в 12 пакетов или меньше. Средний ответ от серверов Cloudflare — примерно 4,8 КБ для HTTP/1.X и около 6 КБ для HTTP/2. Большинство веб-запросов мизерные.
А вот что интересно дальше. Хотя средняя длительность соединения всего 4,7 секунды, некоторые живут сутками. При этом среднее соединение отправляет в 3,78 раза больше данных, чем получает. Веб сильно завязан на загрузку контента.
Распределение классическое — «слоны и мыши». Маленькая доля соединений гоняет миллионы пакетов (стриминг, большие загрузки), тогда как огромная часть — крошечные (API, мелкие ресурсы веб-страниц).
В большинстве соединений проходит всего один HTTP-запрос, даже несмотря на мультиплексирование в HTTP/2. Это касается как пользовательского трафика, так и автоматических запросов из дата-центров.
Интернет гораздо более всплесковый и мимолётный, чем может казаться.
Надеюсь, тебе тоже показалось это занятным.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7
В ноябре 1991 года Тим Бернерс-Ли создал первый вариант протокола, позже получивший название HTTP v0.9, как часть спецификации сервиса WWW
👉 @BackendPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10
Подключение backend API на фронтенде: продвинутый способ
→ Используй TanStack Query для кэширования и фонового refetch.
→ Внедри AbortController для отмены запросов при смене маршрута.
→ Добавь интерсепторы Axios для обновления токена и retry-логики.
→ Держи типизированный слой API для чистых контрактов между FE и BE.
→ Применяй WebSocket для реального времени вместо polling.
Умелая обработка и оркестрация API важны.
👉 @BackendPortal
→ Используй TanStack Query для кэширования и фонового refetch.
→ Внедри AbortController для отмены запросов при смене маршрута.
→ Добавь интерсепторы Axios для обновления токена и retry-логики.
→ Держи типизированный слой API для чистых контрактов между FE и BE.
→ Применяй WebSocket для реального времени вместо polling.
Умелая обработка и оркестрация API важны.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥4❤3
Когда-нибудь задумывался, как эти капчи с «выбери все светофоры» вообще понимают, что ты всё сделал правильно?
Рассказываю.
Там нет никакой магии. Всё сводится к токену и проверке хеша.
Когда страница загружается, бэкенд генерирует challenge id, сохраняет правильный хеш и отдает браузеру подписанный токен, в котором указано «это челлендж X».
Когда ты кликаешь по квадратикам, твой выбор хешируется, и браузер отправляет на сервер хеш ответа + тот самый токен.
Сервер просто проверяет: совпадает ли хеш с эталоном и не истек ли токен (и не подделан ли он).
Если всё ок — ты человек.
Если нет — добро пожаловать на очередной раунд «найди все эти чёртовы светофоры».
На демо маленький пример на Rust, который показывает ту же логику:
👉 @BackendPortal
Рассказываю.
Там нет никакой магии. Всё сводится к токену и проверке хеша.
Когда страница загружается, бэкенд генерирует challenge id, сохраняет правильный хеш и отдает браузеру подписанный токен, в котором указано «это челлендж X».
Когда ты кликаешь по квадратикам, твой выбор хешируется, и браузер отправляет на сервер хеш ответа + тот самый токен.
Сервер просто проверяет: совпадает ли хеш с эталоном и не истек ли токен (и не подделан ли он).
Если всё ок — ты человек.
Если нет — добро пожаловать на очередной раунд «найди все эти чёртовы светофоры».
На демо маленький пример на Rust, который показывает ту же логику:
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍4😁1
Лез в бэкенд и наткнулся на штуку под названием consistent hashing (согласованное хеширование).
Если честно, на этом дерьме держится пол-интернета.
Оно решает, какой сервер «владеет» твоими данными, и умудряется сохранять стабильность, даже когда сервера приходят и уходят.
Обычные балансировщики нагрузки вроде nginx round robin просто перемешивают всё заново при любом изменении ноды.
А более умные — HAProxy, AWS ALB, Envoy, Gloo Mesh используют consistent hashing, чтобы данные оставались на том же месте.
Технология старая, но до сих пор везде: кэши CDN, шарды баз данных, даже в инфраструктуре для ИИ.
В новых конфигурациях иногда добавляют bounded loads, чтобы одна нода не сгорела от запросов к LLM.
Накидал маленькую версию на Rust и, честно, это до смешного простая штука.
👉 @BackendPortal
Если честно, на этом дерьме держится пол-интернета.
Оно решает, какой сервер «владеет» твоими данными, и умудряется сохранять стабильность, даже когда сервера приходят и уходят.
Обычные балансировщики нагрузки вроде nginx round robin просто перемешивают всё заново при любом изменении ноды.
А более умные — HAProxy, AWS ALB, Envoy, Gloo Mesh используют consistent hashing, чтобы данные оставались на том же месте.
Технология старая, но до сих пор везде: кэши CDN, шарды баз данных, даже в инфраструктуре для ИИ.
В новых конфигурациях иногда добавляют bounded loads, чтобы одна нода не сгорела от запросов к LLM.
Накидал маленькую версию на Rust и, честно, это до смешного простая штука.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤7
Все пользуются Docker, но почти никто не умеет дебажить контейнеры по-настоящему.
Нет, я не про docker logs, docker inspect или docker exec.
Я про docker events.
Скорее всего, ты даже не знал, что она существует.
А ведь она стримит низкоуровневые реальные события Docker-демона и не только твой контейнер, а всё, что происходит в системе.
Представь ситуацию:
контейнер постоянно рестартует в проде, а у тебя локально всё ок.
Ты, как обычно, заходишь на сервер и начинаешь стандартный ритуал отладки:
docker logs — пусто
docker inspect — статичная инфа
docker exec — не успеваешь подключиться, контейнер уже сдох
Знакомо?
Дальше ты, скорее всего, начинаешь шаманить с Dockerfile и гоняешь docker run по кругу,
потому что никогда не пользовался docker events.
А теперь попробуй так:
Вывод может быть таким:
И вот оно.
Healthcheck упал → контейнер убит → Docker сам его перезапустил.
А твои обычные логи?
Они это не покажут, потому что healthcheck работает вне твоего основного процесса.
Бонус:
Отфильтровать по времени:
Получить структурированный вывод (JSON):
Хотите полную картину системы во время сбоя? Просто убери фильтр:
И прежде чем кто-то скажет:
"В нормальной инфраструктуре есть Grafana, Loki, Prometheus, Observability и всё такое…"
Да, да. Удачи отлаживать с их помощью:
- OOM-килы, которые происходят до того, как метрики успевают собраться
- Неподмонтированные volume’ы
- Упал init-контейнер
- Сайдкар, который молча рестартует
А docker events всё это видит.
В реальном времени.
Если ты дебажишь Docker без docker events,
ты не дебажишь — ты угадываешь.
👉 @BackendPortal
Нет, я не про docker logs, docker inspect или docker exec.
Я про docker events.
Скорее всего, ты даже не знал, что она существует.
А ведь она стримит низкоуровневые реальные события Docker-демона и не только твой контейнер, а всё, что происходит в системе.
Представь ситуацию:
контейнер постоянно рестартует в проде, а у тебя локально всё ок.
Ты, как обычно, заходишь на сервер и начинаешь стандартный ритуал отладки:
docker logs — пусто
docker inspect — статичная инфа
docker exec — не успеваешь подключиться, контейнер уже сдох
Знакомо?
Дальше ты, скорее всего, начинаешь шаманить с Dockerfile и гоняешь docker run по кругу,
потому что никогда не пользовался docker events.
А теперь попробуй так:
docker events --filter container=<your_container_id>
Вывод может быть таким:
2025-05-04T18:20:01Z container create ...
2025-05-04T18:20:02Z container start ...
2025-05-04T18:20:03Z container health_status: unhealthy ...
2025-05-04T18:20:04Z container kill signal=SIGTERM
2025-05-04T18:20:04Z container restart
И вот оно.
Healthcheck упал → контейнер убит → Docker сам его перезапустил.
А твои обычные логи?
Они это не покажут, потому что healthcheck работает вне твоего основного процесса.
Бонус:
Отфильтровать по времени:
docker events --since 30m --until "2025-05-04T18:00:00"
Получить структурированный вывод (JSON):
docker events --format '{{json .}}'Хотите полную картину системы во время сбоя? Просто убери фильтр:
docker events
И прежде чем кто-то скажет:
"В нормальной инфраструктуре есть Grafana, Loki, Prometheus, Observability и всё такое…"
Да, да. Удачи отлаживать с их помощью:
- OOM-килы, которые происходят до того, как метрики успевают собраться
- Неподмонтированные volume’ы
- Упал init-контейнер
- Сайдкар, который молча рестартует
А docker events всё это видит.
В реальном времени.
Если ты дебажишь Docker без docker events,
ты не дебажишь — ты угадываешь.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11🔥8👍4
Вот интересный трюк с UUID, про который знают немногие: UUIDv5.
В схемах баз данных обычно используют UUIDv7 как инкрементные первичные ключи или UUIDv4 для случайных идентификаторов. Но UUIDv5 почти не встречается, хотя в некоторых задачах он идеальное решение.
Представь ситуацию: пользовательские данные должны соответствовать требованиям GDPR. Пользователь запросил удаление аккаунта, мы стираем запись из таблицы users и все связанные записи по userId во внешних ключах. Позже пользователь подаёт жалобу в банк или Apple по старой транзакции, как нам найти его предыдущие операции, если userId уже нет?
Или, допустим, пользователь оформил подписку, потом удалил аккаунт и зарегистрировался заново, как реализовать обязательную для Apple функцию восстановления покупок?
Здесь и помогает UUIDv5.
При входе через OAuth2 мы можем связать (provider + openid + domain) и сгенерировать на их основе уникальный UUIDv5, назовём его accountToken.
В транзакциях мы передаём accountToken как идентификатор пользователя во внешние системы, вместо userId.
Если пользователь потом удаляет аккаунт, но позже снова входит тем же способом, генерируется тот же accountToken. Мы можем по нему найти старые данные транзакций и решить спор без восстановления личных данных.
Таким образом:
- соблюдается приватность и требования GDPR, личная информация пользователя действительно удалена;
- UUIDv5 accountToken обезличен и хэширован, обратное восстановление невозможно;
- при этом сохраняется возможность анонимного анализа и проверки транзакций (например, хранение истории 7 лет для финансовых и налоговых проверок).
Отличный баланс между комплаенсом и практической функциональностью.
Причина использовать UUID, а не просто склеивать строки и хэшировать их, в том, что Apple требует, чтобы accountToken, передаваемый при оплате, был в формате UUID. Кроме того, если взять домен приложения в качестве seed для UUIDv5 и объединить его с provider и openid, получается более стандартизированная и совместимая реализация.
👉 @BackendPortal
В схемах баз данных обычно используют UUIDv7 как инкрементные первичные ключи или UUIDv4 для случайных идентификаторов. Но UUIDv5 почти не встречается, хотя в некоторых задачах он идеальное решение.
Представь ситуацию: пользовательские данные должны соответствовать требованиям GDPR. Пользователь запросил удаление аккаунта, мы стираем запись из таблицы users и все связанные записи по userId во внешних ключах. Позже пользователь подаёт жалобу в банк или Apple по старой транзакции, как нам найти его предыдущие операции, если userId уже нет?
Или, допустим, пользователь оформил подписку, потом удалил аккаунт и зарегистрировался заново, как реализовать обязательную для Apple функцию восстановления покупок?
Здесь и помогает UUIDv5.
При входе через OAuth2 мы можем связать (provider + openid + domain) и сгенерировать на их основе уникальный UUIDv5, назовём его accountToken.
В транзакциях мы передаём accountToken как идентификатор пользователя во внешние системы, вместо userId.
Если пользователь потом удаляет аккаунт, но позже снова входит тем же способом, генерируется тот же accountToken. Мы можем по нему найти старые данные транзакций и решить спор без восстановления личных данных.
Таким образом:
- соблюдается приватность и требования GDPR, личная информация пользователя действительно удалена;
- UUIDv5 accountToken обезличен и хэширован, обратное восстановление невозможно;
- при этом сохраняется возможность анонимного анализа и проверки транзакций (например, хранение истории 7 лет для финансовых и налоговых проверок).
Отличный баланс между комплаенсом и практической функциональностью.
Причина использовать UUID, а не просто склеивать строки и хэшировать их, в том, что Apple требует, чтобы accountToken, передаваемый при оплате, был в формате UUID. Кроме того, если взять домен приложения в качестве seed для UUIDv5 и объединить его с provider и openid, получается более стандартизированная и совместимая реализация.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15❤4
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