Университет Хельсинки выложил бесплатный курс MOOC по Python
Начинаешь с базы. На последних занятиях учат писать игры на Pygame, работать с анимацией и физикой, так что в конце создашь свою первую настоящую игру.
👉 @BackendPortal
Начинаешь с базы. На последних занятиях учат писать игры на Pygame, работать с анимацией и физикой, так что в конце создашь свою первую настоящую игру.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4🤯1
Git-лайфхак
Хочешь нормальный граф коммитов по репе одной командой:
👉 @BackendPortal
Хочешь нормальный граф коммитов по репе одной командой:
git log --oneline --graph --decorate --all
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11🔥2
В Go 1.26 в пакет
Плюс добавили новые методы:
Теперь с рефлексией можно работать заметно удобнее и ближе к обычному Go-коду, без лишней возни с индексами и слайсами.
👉 @BackendPortal
reflect завезли итерируемые (range-able) итераторы.Плюс добавили новые методы:
Type.Methods()Type.Ins()Type.Outs()Value.Fields()Value.Methods()Теперь с рефлексией можно работать заметно удобнее и ближе к обычному Go-коду, без лишней возни с индексами и слайсами.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥1
Вот штука, которая звучит немного контринтуитивно про B+ деревья: вставлять ключи в отсортированном порядке реально быстро, но есть скрытая цена.
Когда ты вставляешь ключи последовательно (1, 2, 3, 4...), B+ дерево почти ничего не “перетряхивает”. Узлы не приходится постоянно делить и ребалансить: каждый новый ключ улетает в самый правый лист. Вставки выходят супер дешевыми: минимум ребалансинга, минимум затронутых дисковых блоков.
Но плата за это такая: появляется жесткая внутренняя фрагментация.
Поскольку все вставки идут по правому краю, “левые” узлы редко добиваются до полной емкости. В итоге в хранилище лежит куча полупустых страниц, которые жрут место. Страница, которая могла бы держать 100 ключей, по факту держит 50–60, и это потом размазывается по всему дереву.
Случайные вставки, наоборот, распределяют ключи равномернее по страницам. Они медленнее, потому что будут сплиты/ребаланс, зато по месту всё намного эффективнее.
Так что если ты делаешь bulk load, отсортированная вставка дает скорость. Но если тебе важна плотность (память/диск) в долгую, имеет смысл перемешать ключи или использовать специальные bulk-loading алгоритмы, которые пакуют страницы плотнее.
Короче, как обычно: “лучшего способа” на все случаи нет :)
👉 @BackendPortal
Когда ты вставляешь ключи последовательно (1, 2, 3, 4...), B+ дерево почти ничего не “перетряхивает”. Узлы не приходится постоянно делить и ребалансить: каждый новый ключ улетает в самый правый лист. Вставки выходят супер дешевыми: минимум ребалансинга, минимум затронутых дисковых блоков.
Но плата за это такая: появляется жесткая внутренняя фрагментация.
Поскольку все вставки идут по правому краю, “левые” узлы редко добиваются до полной емкости. В итоге в хранилище лежит куча полупустых страниц, которые жрут место. Страница, которая могла бы держать 100 ключей, по факту держит 50–60, и это потом размазывается по всему дереву.
Случайные вставки, наоборот, распределяют ключи равномернее по страницам. Они медленнее, потому что будут сплиты/ребаланс, зато по месту всё намного эффективнее.
Так что если ты делаешь bulk load, отсортированная вставка дает скорость. Но если тебе важна плотность (память/диск) в долгую, имеет смысл перемешать ключи или использовать специальные bulk-loading алгоритмы, которые пакуют страницы плотнее.
Короче, как обычно: “лучшего способа” на все случаи нет :)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Git tip : узнать, кто последний правил каждую строку файла, можно командой:
Примечание: работает только для того, что уже закоммичено. Незакоммиченные правки (текущие изменения в рабочем дереве) в blame не попадут.
👉 @BackendPortal
git blame <filename>Примечание: работает только для того, что уже закоммичено. Незакоммиченные правки (текущие изменения в рабочем дереве) в blame не попадут.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
image_2026-02-15_10-08-47.png
1.9 MB
SSH-мультиплексирование в Go: SFTP-передачи в 14 раз быстрее по одному соединению
Код: https://github.com/MYK12397/sftp-go
SFTP работает поверх SSH, а SSH из коробки мультиплексированный протокол. Одно TCP-соединение SSH может одновременно нести сотни независимых каналов. Каждый open/read/close файла это отдельный канал, а SSH-слой сам “перемежает” их по проводу.
Я сам это не осознавал, пока мой скрипт для перекачки файлов не ускорился с 22 минут до 94 секунд, при том что я не открывал ни одного дополнительного соединения.
Как работает SSH-мультиплексирование
Когда вы вызываете
При этом нет конкуренции за mutex на самом
👉 @BackendPortal
Код: https://github.com/MYK12397/sftp-go
SFTP работает поверх SSH, а SSH из коробки мультиплексированный протокол. Одно TCP-соединение SSH может одновременно нести сотни независимых каналов. Каждый open/read/close файла это отдельный канал, а SSH-слой сам “перемежает” их по проводу.
Я сам это не осознавал, пока мой скрипт для перекачки файлов не ускорился с 22 минут до 94 секунд, при том что я не открывал ни одного дополнительного соединения.
Как работает SSH-мультиплексирование
Когда вы вызываете
sftpClient.Open() в Go-пакете pkg/sftp, создается новый SSH-канал, а не новое соединение. Транспортный слой SSH мультиплексирует все каналы поверх одного TCP-сокета. То есть 80 горутин (мой кейс) могут параллельно читать разные файлы, все разделяя один sftp.Client.http://sftpClient.Open() это ключевая строка. Каждый вызов открывает новый SFTP file handle, который мапится на новый SSH-канал. SSH-библиотека (golang.org/x/crypto/ssh) прозрачно обрабатывает мультиплексирование этих каналов, перемешивая read-пакеты всех 80 горутин по одному TCP-сокету.При этом нет конкуренции за mutex на самом
sftp.Client(). В библиотеке внутренние локи на уровне пакетов, а не на уровне файлов. Горутина A читает байты из файла 1 и не блокирует горутину B, которая в это время открывает файл 2.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2
sqlc это генератор кода для Go на этапе генерации. Ты пишешь SQL-запросы, а sqlc парсит их вместе со схемой и на основе этих запросов генерирует типобезопасный Go-код (структуры, функции).
sqlc также ловит несовпадения со схемой еще до сборки (например, если в запросе указан столбец, которого не существует).
Link: https://github.com/sqlc-dev/sqlc
Поправка: это не генерация на “compile-time”. Это отдельный шаг генерации, который ты запускаешь вручную (или в CI) перед компиляцией:
👉 @BackendPortal
sqlc также ловит несовпадения со схемой еще до сборки (например, если в запросе указан столбец, которого не существует).
Link: https://github.com/sqlc-dev/sqlc
Поправка: это не генерация на “compile-time”. Это отдельный шаг генерации, который ты запускаешь вручную (или в CI) перед компиляцией:
sqlc generate # pre-build step
go build ./...
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - sqlc-dev/sqlc: Generate type-safe code from SQL
Generate type-safe code from SQL. Contribute to sqlc-dev/sqlc development by creating an account on GitHub.
👍5
В этом видео разбирают асинхронное чтение (read IO) в Postgres 18.
0:00 Вступление
1:30 Синхронные и асинхронные вызовы
3:00 Синхронный IO
6:30 Асинхронный IO
10:00 Синхронный IO в Postgres 17
17:20 Почему Async IO в Postgres 18 это непросто
20:00 io_method: worker
23:00 io_method: io_uring
29:30 io_method: sync
31:08 Async IO еще не готов!
31:30 Поддержка backend writers
32:36 Улучшения worker io_method
33:00 Поддержка direct IO
👉 @BackendPortal
0:00 Вступление
1:30 Синхронные и асинхронные вызовы
3:00 Синхронный IO
6:30 Асинхронный IO
10:00 Синхронный IO в Postgres 17
17:20 Почему Async IO в Postgres 18 это непросто
20:00 io_method: worker
23:00 io_method: io_uring
29:30 io_method: sync
31:08 Async IO еще не готов!
31:30 Поддержка backend writers
32:36 Улучшения worker io_method
33:00 Поддержка direct IO
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍3
Никогда не запускай запросы без таймаута.
Без него один “вредный” запрос или всплеск нагрузки легко приводит к затыкам и даже к даунтайму приложения. Давай разберем, почему.
Представь ситуацию: в приложение случайно попадает долгий запрос. Обычно база обрабатывает только короткоживущие запросы (10 мс или меньше), а тут внезапно появляется новый, который выполняется по 1000 мс каждый раз.
Он не только будет жрать ресурсы, но и резко увеличит число одновременных транзакций. В итоге мы упремся либо в лимит соединений, либо в лимиты по транзакциям, либо просто выжмем 100% CPU / IOPS у базы.
Теперь та же ситуация, но мы ставим таймаут 250 мс на каждую транзакцию (на стороне базы), а на стороне приложения делаем ретраи с экспоненциальным backoff + jitter. Так мы ограничиваем радиус поражения от одного запроса. Долгие запросы будут прибиваться, а backoff-логика снижает риск эффекта “стада” (thundering herd).
И если мониторить эти таймауты, можно быстро найти проблемный запрос и откатить изменение.
👉 @BackendPortal
Без него один “вредный” запрос или всплеск нагрузки легко приводит к затыкам и даже к даунтайму приложения. Давай разберем, почему.
Представь ситуацию: в приложение случайно попадает долгий запрос. Обычно база обрабатывает только короткоживущие запросы (10 мс или меньше), а тут внезапно появляется новый, который выполняется по 1000 мс каждый раз.
Он не только будет жрать ресурсы, но и резко увеличит число одновременных транзакций. В итоге мы упремся либо в лимит соединений, либо в лимиты по транзакциям, либо просто выжмем 100% CPU / IOPS у базы.
Теперь та же ситуация, но мы ставим таймаут 250 мс на каждую транзакцию (на стороне базы), а на стороне приложения делаем ретраи с экспоненциальным backoff + jitter. Так мы ограничиваем радиус поражения от одного запроса. Долгие запросы будут прибиваться, а backoff-логика снижает риск эффекта “стада” (thundering herd).
И если мониторить эти таймауты, можно быстро найти проблемный запрос и откатить изменение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Умоляю: не юзайте CTE
CTE это не медалька и не повод гордиться.
Не пишите их просто потому, что это выглядит “продвинуто”.
Иногда чистый прямой запрос лучше, чем “навороченный”.
Если ваш CTE не:
❌ улучшает читаемость
❌ помогает разложить сложность
❌ отделяет логические шаги
то это просто вертикальный скролл без смысла. Пишите обычный запрос. Прятать логику за лишней сложностью это не гениальность, это балласт.
CTE это просто инструмент. И как любой инструмент, не надо им злоупотреблять💚
👉 @BackendPortal
CTE это не медалька и не повод гордиться.
Не пишите их просто потому, что это выглядит “продвинуто”.
Иногда чистый прямой запрос лучше, чем “навороченный”.
Если ваш CTE не:
то это просто вертикальный скролл без смысла. Пишите обычный запрос. Прятать логику за лишней сложностью это не гениальность, это балласт.
CTE это просто инструмент. И как любой инструмент, не надо им злоупотреблять
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10💊3😁1
This media is not supported in your browser
VIEW IN TELEGRAM
React Doctor уже тут
Сканируй свой React-код на анти-паттерны:
▪️ лишние useEffect-ы
▪️ исправляет проблемы с доступностью (a11y)
▪️ prop drilling вместо context / композиции
Запускается как CLI или как агент skill. Гоняешь снова и снова, пока всё не проходит. Полностью open source.
Запусти это в терминале, чтобы попробовать:
исходный код
👉 @BackendPortal
Сканируй свой React-код на анти-паттерны:
Запускается как CLI или как агент skill. Гоняешь снова и снова, пока всё не проходит. Полностью open source.
Запусти это в терминале, чтобы попробовать:
npx -y react-doctor@latest
исходный код
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Топовый ресурс, чтобы учить алгоритмы программирования. Пошаговые визуальные объяснения и примеры кода.
На испанском и с графиками сложности.
40 алгоритмов, концептов и структур данных:
→ http://alg0.dev
👉 @BackendPortal
На испанском и с графиками сложности.
40 алгоритмов, концептов и структур данных:
→ http://alg0.dev
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Топ-5 юзкейсов Redis:
Два разработчика, Сара и Майк, решили собрать приложение доставки еды. Началось как проект на выходных, а к третьему месяцу у них уже реальные пользователи, реальный трафик и реальные проблемы. Вот как Redis спасает их на каждом этапе.
1. Redis как кэш
База начинает тормозить. Сара замечает: меню почти не меняются, но их дергают тысячи раз в день. Она ставит Redis перед базой: один раз достали меню, закэшировали на 10 минут.
2. Redis как хранилище сессий
Майк поднимает еще один сервер под пики вроде обеденного наплыва, и пользователи начинают жаловаться, что их рандомно выкидывает из аккаунта.
Причина простая: сессия сохранилась на Сервере 1, а следующий запрос улетел на Сервер 2.
Майк просто переносит все пользовательские сессии в Redis. Теперь не важно, какой сервер поймал запрос: юзеры остаются залогиненными.
3. Redis как rate limiter
Сара и Майк запускают акцию "50% на первый заказ"… И уже через час один тип оформил 47 заказов с 47 фейковых аккаунтов с одного IP.
Майк добавляет rate limiter на Redis: простой счетчик на IP, который сбрасывается каждый час. Абуз прекращается, а тип идет жить дальше.
4. Redis как Pub/Sub и очереди
Пользователи постоянно пишут: "мой заказ точно подтвержден?" Сара хочет отправлять письмо-подтверждение сразу после оформления заказа, но если делать это внутри запроса, чек-аут становится медленным.
Она пушит события о заказах в Redis-очередь, а фоновый воркер забирает их и шлет письма асинхронно. Теперь оформление выглядит мгновенным, и никто больше не дергает саппорт.
5. Redis как распределенные локи
У пользователя плохая сеть, он нажимает "Оформить заказ" два раза подряд. Оба запроса одновременно прилетают на сервер. Карта списывает два раза, оформляется два заказа, и в итоге прилетает злой отзыв.
Майк делает distributed lock на Redis: первый запрос забирает лок, второй видит, что лок занят, и получает отказ. Теперь списание одно, заказ один, и возможно даже будет отзыв на пять звезд.
Redis умеет гораздо больше. Но даже этих примеров хватает, чтобы понять: это инструмент, к которому можно тянуться каждый раз, когда что-то начинает ломаться под нагрузкой.
👉 @BackendPortal
Два разработчика, Сара и Майк, решили собрать приложение доставки еды. Началось как проект на выходных, а к третьему месяцу у них уже реальные пользователи, реальный трафик и реальные проблемы. Вот как Redis спасает их на каждом этапе.
1. Redis как кэш
База начинает тормозить. Сара замечает: меню почти не меняются, но их дергают тысячи раз в день. Она ставит Redis перед базой: один раз достали меню, закэшировали на 10 минут.
2. Redis как хранилище сессий
Майк поднимает еще один сервер под пики вроде обеденного наплыва, и пользователи начинают жаловаться, что их рандомно выкидывает из аккаунта.
Причина простая: сессия сохранилась на Сервере 1, а следующий запрос улетел на Сервер 2.
Майк просто переносит все пользовательские сессии в Redis. Теперь не важно, какой сервер поймал запрос: юзеры остаются залогиненными.
3. Redis как rate limiter
Сара и Майк запускают акцию "50% на первый заказ"… И уже через час один тип оформил 47 заказов с 47 фейковых аккаунтов с одного IP.
Майк добавляет rate limiter на Redis: простой счетчик на IP, который сбрасывается каждый час. Абуз прекращается, а тип идет жить дальше.
4. Redis как Pub/Sub и очереди
Пользователи постоянно пишут: "мой заказ точно подтвержден?" Сара хочет отправлять письмо-подтверждение сразу после оформления заказа, но если делать это внутри запроса, чек-аут становится медленным.
Она пушит события о заказах в Redis-очередь, а фоновый воркер забирает их и шлет письма асинхронно. Теперь оформление выглядит мгновенным, и никто больше не дергает саппорт.
5. Redis как распределенные локи
У пользователя плохая сеть, он нажимает "Оформить заказ" два раза подряд. Оба запроса одновременно прилетают на сервер. Карта списывает два раза, оформляется два заказа, и в итоге прилетает злой отзыв.
Майк делает distributed lock на Redis: первый запрос забирает лок, второй видит, что лок занят, и получает отказ. Теперь списание одно, заказ один, и возможно даже будет отзыв на пять звезд.
Redis умеет гораздо больше. Но даже этих примеров хватает, чтобы понять: это инструмент, к которому можно тянуться каждый раз, когда что-то начинает ломаться под нагрузкой.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19👍5
"Два struct-а с одинаковыми полями могут иметь разный размер, поэтому переставляй поля в struct-е, чтобы оптимизировать память".
Во многих случаях это плохой совет.
--- Контекст
В Go порядок полей внутри struct-а влияет на то, сколько байт padding-а компилятор добавит, чтобы соблюсти выравнивание (alignment). На 64-битной системе:
- int64, указатель и time.Time хотят выравнивание по 8 байтам.
- bool хочет выравнивание по 1 байту.
Если поставить маленькие поля между большими, Go часто вставляет padding, чтобы следующее 8-байтное поле все равно начиналось с границы в 8 байт. Это видно на приложенной картинке.
Этот padding это чистый мусор:
- Если struct впустую тратит 8 байт и ты держишь в памяти 1 000 000 таких объектов, это примерно 8 МБ, сожженных без пользы.
- Если тратит 16 байт, это примерно 16 МБ.
Ошибка в том, что перестановку полей считают бесплатной победой везде. Это не так.
Лучший порядок для минимального размера по памяти обычно такой: сначала поля с самым большим требованием к выравниванию. Но лучший порядок для скорости может быть другим: поля, которые используются вместе, лучше держать рядом.
Кэш-линии CPU обычно по 64 байта. Если твой hot path читает ID, Status и UpdatedAt вместе, то расположить эти поля рядом может быть быстрее, чем сделать раскладку на пару байт меньше, но размазать горячие поля по struct-у.
Плюс, если ты большую часть времени тратишь на JSON encode/decode в API, экономия на padding-е может просто утонуть в оверхеде сериализации. Поэтому слепая микрооптимизация иногда съедает больше времени разработчика, чем экономит серверного времени.
Поэтому относись к layout-у struct-а как к рефакторингу, который подтверждается измерениями:
- Сначала найди struct-ы, которые реально важны: их очень много и они долго живут. Типичные примеры: элементы в []T с сотнями тысяч записей, значения в map[string]T как кэш, или struct-ы, которые аллоцируются на каждый запрос в сервисе с высоким QPS.
- Запусти стандартный чекер выравнивания, чтобы не гадать. Например: http://golang.org/x/tools/go/analysis/passes/fieldalignment Его можно подключить в go vet через -vettool, и он также доступен в golangci-lint через опцию govet fieldalignment.
- Потом измени один struct, заново прогоняй бенчмарк и смотри и память, и throughput. Если бенчмарка нет, напиши самый маленький: создай 100 000 или 1 000 000 инстансов и измерь allocations и ns/op.
Неплохое правило по умолчанию, которое остается читаемым, простое:
- держи "горячие поля" рядом,
- держи вместе поля с "крупным выравниванием",
- не убивай ясность ради экономии, которую ты не можешь доказать, и просто держи связанные по смыслу поля вместе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤔3
Ты знал, что у Postgres есть ДВА in-memory кэша?
Каждый раз, когда Postgres читает строку, по факту данные приходят из одного из трех мест:
1.
2. OS page cache (кэш страниц ОС). Операционка использует свободную память как кэш недавно прочитанных страниц файловой системы. Чтение в Pg может промахнуться мимо
3. Файловая система / железо. Если данных нет ни в одном из кэшей, файловая система идет за ними на диск (это заметно медленнее).
Данные могут дублироваться в обоих кэшах одновременно! На мой взгляд, единый “общий” кэш мог бы быть приятным улучшением для Pg в будущем, хотя это огромная работа по реализации.
👉 @BackendPortal
Каждый раз, когда Postgres читает строку, по факту данные приходят из одного из трех мест:
1.
shared_buffers (кэш, которым управляет сам Postgres). Это самый “ближний” к Postgres слой с страницами данных, обычно самый быстрый.2. OS page cache (кэш страниц ОС). Операционка использует свободную память как кэш недавно прочитанных страниц файловой системы. Чтение в Pg может промахнуться мимо
shared_buffers, но нужная страница при этом уже лежит в кэше ОС. Это тоже очень быстро: остается только скопировать страницу в shared_buffers.3. Файловая система / железо. Если данных нет ни в одном из кэшей, файловая система идет за ними на диск (это заметно медленнее).
Данные могут дублироваться в обоих кэшах одновременно! На мой взгляд, единый “общий” кэш мог бы быть приятным улучшением для Pg в будущем, хотя это огромная работа по реализации.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥4
Vercel выкатили реально полезную штуку для локальной разработки
Называется Portless. Вместо того чтобы жить на захламленных портах типа
Под капотом это локальный прокси, который мапит эти понятные домены на нужные порты на твоей машине.
Почему это удобно:
▪️ не надо помнить случайные номера портов
▪️ локальные URL читаемые, по-человечески
▪️ имена стабильные, даже если порты поменялись
▪️ больше похоже на прод, где все часто разнесено по сабдоменам
▪️ удобнее для автоматизации и AI-агентов, меньше сюрпризов
Важно упомянуть, оно не выставляет твое приложение в интернет. Просто делает локальную разработку аккуратнее и организованнее :))
Ссылка на репо: http://github.com/vercel-labs/portless
👉 @BackendPortal
Называется Portless. Вместо того чтобы жить на захламленных портах типа
localhost:3000, можно использовать нормальные именованные адреса вроде app.localhost или api.localhost.Под капотом это локальный прокси, который мапит эти понятные домены на нужные порты на твоей машине.
Почему это удобно:
Важно упомянуть, оно не выставляет твое приложение в интернет. Просто делает локальную разработку аккуратнее и организованнее :))
Ссылка на репо: http://github.com/vercel-labs/portless
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Проектируем полезные логи для бэкендеров
Большинство девов логируют реактивно: добавили
1. Начинай со структурированного логирования: вместо обычного текста пиши JSON с едиными, предсказуемыми полями, по которым можно нормально искать.
Тогда твой мониторинг сможет алертить, фильтровать и строить графики, а логи можно будет “запрашивать” почти как базу данных.
2. Используй уровни логов по делу.
• INFO = ожидаемые бизнес-события (например, пользователь залогинился)
• WARN = обработанные аномалии (например, ретраим упавший вызов)
• ERROR = реальные фейлы, которые требуют внимания
• DEBUG = детали для разработки, в проде выключать
Большинство команд ставят ERROR вообще на все. Не надо так.
3. Всегда держи “чеклист контекста”:
Само сообщение лога почти бесполезно. Ценность дают контекстные поля, которые к нему приклеены, и именно они делают лог пригодным для действий.
• Идентификаторы:
• Значения:
• Состояние:
• Детали ошибки:
• Время:
Идентификаторы отвечают на “кто и что”, значения на “сколько”, состояние на “где мы в процессе”, детали ошибки на “что пошло не так”, а время на “как долго это длилось”.
4. Используй correlation ID:
Генерируй уникальный
Без этого дебажить параллельные запросы становится проблемнее.
5. Никогда не логируй чувствительные данные:
Не логируй пароли, токены, номера карт, сырой SQL с пользовательскими значениями, данные, возвращаемые запросами, и т.п.
Цель такая: любой инженер во время инцидента должен открыть логи и сразу понять, что произошло, даже не лазя в исходники.
👉 @BackendPortal
Большинство девов логируют реактивно: добавили
console.log, когда что-то сломалось, починили и пошли дальше. В итоге получаются в основном шумные логи, которые вообще ничего не говорят, когда прод полыхает.1. Начинай со структурированного логирования: вместо обычного текста пиши JSON с едиными, предсказуемыми полями, по которым можно нормально искать.
Тогда твой мониторинг сможет алертить, фильтровать и строить графики, а логи можно будет “запрашивать” почти как базу данных.
2. Используй уровни логов по делу.
• INFO = ожидаемые бизнес-события (например, пользователь залогинился)
• WARN = обработанные аномалии (например, ретраим упавший вызов)
• ERROR = реальные фейлы, которые требуют внимания
• DEBUG = детали для разработки, в проде выключать
Большинство команд ставят ERROR вообще на все. Не надо так.
3. Всегда держи “чеклист контекста”:
Само сообщение лога почти бесполезно. Ценность дают контекстные поля, которые к нему приклеены, и именно они делают лог пригодным для действий.
• Идентификаторы:
user_id, order_id, request_id• Значения:
amount, count, size• Состояние:
status, current_step• Детали ошибки:
error_code, exception• Время:
duration_msИдентификаторы отвечают на “кто и что”, значения на “сколько”, состояние на “где мы в процессе”, детали ошибки на “что пошло не так”, а время на “как долго это длилось”.
4. Используй correlation ID:
Генерируй уникальный
request_id на каждом входе в систему. Протаскивай его через каждую функцию, сервис и лог.Без этого дебажить параллельные запросы становится проблемнее.
5. Никогда не логируй чувствительные данные:
Не логируй пароли, токены, номера карт, сырой SQL с пользовательскими значениями, данные, возвращаемые запросами, и т.п.
Цель такая: любой инженер во время инцидента должен открыть логи и сразу понять, что произошло, даже не лазя в исходники.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2
This media is not supported in your browser
VIEW IN TELEGRAM
JWT за 60 секунд
Что такое JWT?
JWT = JSON Web Token
Компактный, URL-safe токен, который используют для:
- аутентификации
- авторизации
- безопасного общения между API
- шаринга идентичности между сервисами
Он цифрово подписан, поэтому его можно проверять и ему можно доверять.
🟢 Зачем вообще нужен JWT
Типичный флоу без JWT:
Пользователь → Приложение → База данных (хранилище сессий)
-сервер хранит сессии
-нужна память/хранилище
-сложно масштабировать в микросервисах
-больше инфраструктурной сложности
-за балансировщиком нужны sticky sessions
-в распределенных системах это плохо масштабируется
🟢 Тут и появляется JWT
- JWT это stateless-аутентификация.
Новый флоу:
Пользователь → Приложение → JWT → Клиент → API
-на сервере не хранится сессия
-токен несет идентичность пользователя и claims
-сервер только проверяет подпись
-отлично подходит для масштабируемых систем
🟢 Полный флоу JWT-запроса
1️⃣ пользователь логинится с кредами
2️⃣ сервер валидирует пользователя
3️⃣ сервер генерирует JWT (Header + Payload + Signature)
4️⃣ клиент сохраняет JWT (обычно в браузере/приложении)
5️⃣ клиент шлет JWT в заголовке Authorization
6️⃣ сервер проверяет подпись
7️⃣ если валидно → доступ выдан
Никакой поход в базу за сессией не нужен.
🟢 Где JWT используют в реальных системах?
-REST API
-аутентификация микросервисов
-OAuth2 / SSO
-API Gateway
-Kubernetes dashboards
-CI/CD инструменты
-мобильные приложения и SPA
-почти каждый современный cloud-native апп использует JWT
🟢 JWT в DevOps и System Design
DevOps-инженеру JWT нужен для:
-проектирования stateless-приложений
-масштабирования за Load Balancer’ами
-внедрения API security
-работы с IAM и OAuth-провайдерами
-защиты коммуникации микросервисов
-уменьшения зависимости от session storage
Stateless auth = лучше масштабируемость + проще инфраструктура
Спасибо, что дочитал.
👉 @BackendPortal
Что такое JWT?
JWT = JSON Web Token
Компактный, URL-safe токен, который используют для:
- аутентификации
- авторизации
- безопасного общения между API
- шаринга идентичности между сервисами
Он цифрово подписан, поэтому его можно проверять и ему можно доверять.
Типичный флоу без JWT:
Пользователь → Приложение → База данных (хранилище сессий)
-сервер хранит сессии
-нужна память/хранилище
-сложно масштабировать в микросервисах
-больше инфраструктурной сложности
-за балансировщиком нужны sticky sessions
-в распределенных системах это плохо масштабируется
- JWT это stateless-аутентификация.
Новый флоу:
Пользователь → Приложение → JWT → Клиент → API
-на сервере не хранится сессия
-токен несет идентичность пользователя и claims
-сервер только проверяет подпись
-отлично подходит для масштабируемых систем
Никакой поход в базу за сессией не нужен.
-REST API
-аутентификация микросервисов
-OAuth2 / SSO
-API Gateway
-Kubernetes dashboards
-CI/CD инструменты
-мобильные приложения и SPA
-почти каждый современный cloud-native апп использует JWT
DevOps-инженеру JWT нужен для:
-проектирования stateless-приложений
-масштабирования за Load Balancer’ами
-внедрения API security
-работы с IAM и OAuth-провайдерами
-защиты коммуникации микросервисов
-уменьшения зависимости от session storage
Stateless auth = лучше масштабируемость + проще инфраструктура
Спасибо, что дочитал.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍4
У тебя SaaS, где есть фича: загрузить и обработать большой файл.
Без брокера:
1. Юзер жмёт Upload → POST /upload
2. Сервер принимает файл и тут же начинает обработку (2 минуты)
3. И только потом отвечает
Если так делают многие, сервер забивается обработкой и перестаёт нормально обслуживать остальные запросы. Логин тормозит. Дашборд грузится долго. Всё начинает ехать.
С брокером (например RabbitMQ):
1. Юзер жмёт Upload
2. Сервер принимает файл и кладёт его в storage
3. Отправляет в RabbitMQ сообщение: “обработать файл ID 1”
(этот сервер здесь Producer)
4. RabbitMQ кладёт сообщение в queue (очередь задач)
5. Сервер отвечает почти сразу
6. RabbitMQ отдаёт это сообщение другому процессу, который забирает файл из storage и обрабатывает (Consumer)
Пайплайн:
Users → Producer → Broker → Consumer
RabbitMQ сам файл не обрабатывает. Он просто хранит задачу и выдаёт её воркеру, когда приходит очередь.
Что ты выигрываешь?
Быстрый ответ на запрос, сервер свободен для других действий (логин, загрузка дашборда), обработку можно масштабировать отдельно, и если что-то упало, задачу можно ретраить.
Но: теперь поток асинхронный, значит нужно делать обработку идемпотентной и нормально продумать ретраи.
Брокер не упрощает систему. Он делает её устойчивее, когда проект начинает расти.
👉 @BackendPortal
Без брокера:
1. Юзер жмёт Upload → POST /upload
2. Сервер принимает файл и тут же начинает обработку (2 минуты)
3. И только потом отвечает
Если так делают многие, сервер забивается обработкой и перестаёт нормально обслуживать остальные запросы. Логин тормозит. Дашборд грузится долго. Всё начинает ехать.
С брокером (например RabbitMQ):
1. Юзер жмёт Upload
2. Сервер принимает файл и кладёт его в storage
3. Отправляет в RabbitMQ сообщение: “обработать файл ID 1”
(этот сервер здесь Producer)
4. RabbitMQ кладёт сообщение в queue (очередь задач)
5. Сервер отвечает почти сразу
6. RabbitMQ отдаёт это сообщение другому процессу, который забирает файл из storage и обрабатывает (Consumer)
Пайплайн:
Users → Producer → Broker → Consumer
RabbitMQ сам файл не обрабатывает. Он просто хранит задачу и выдаёт её воркеру, когда приходит очередь.
Что ты выигрываешь?
Быстрый ответ на запрос, сервер свободен для других действий (логин, загрузка дашборда), обработку можно масштабировать отдельно, и если что-то упало, задачу можно ретраить.
Но: теперь поток асинхронный, значит нужно делать обработку идемпотентной и нормально продумать ретраи.
Брокер не упрощает систему. Он делает её устойчивее, когда проект начинает расти.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3