Умоляю: не юзайте 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
Представь, что ты делаешь новостной агрегатор (типа Google News). Одна из самых больших проблем, с которой ты столкнешься, это дедупликация статей среди миллионов документов. Наивные сравнения O(n^2) тебя просто раздавят на масштабе. А реальное решение это MinHash + LSH.
MinHash превращает большое множество в маленькую, фиксированного размера сигнатуру так, что похожесть двух сигнатур приближенно соответствует жаккаровскому сходству (Jaccard similarity) исходных множеств. Jaccard similarity это просто пересечение множеств, деленное на их объединение; мера того, насколько сильно множества перекрываются.
Это быстрый вероятностный способ оценить “насколько эти два документа похожи”, не сравнивая их слово в слово.
Первый шаг это шинглинг: ты разбиваешь каждый документ на перекрывающиеся n-граммы (например, последовательности из 3 слов), а потом запускаешь MinHash на множестве этих шинглов. На выходе MinHash дает компактную сигнатуру, обычно 100-200 хеш-значений.
Ключевое свойство такое: вероятность того, что две сигнатуры разделят одно и то же минимальное хеш-значение, равна Jaccard similarity их исходных множеств шинглов. Так ты оцениваешь сходство, вообще не трогая сырой текст.
Но проблема сравнения все равно остается. Даже с компактными сигнатурами сравнивать каждую пару дорого. Тут и появляется LSH
Ты делишь каждую сигнатуру на b полос по r строк в каждой, и хешируешь каждую полосу в бакет. Два документа, которые достаточно похожи, с высокой вероятностью попадут в один и тот же бакет хотя бы в одной полосе, и уже только эти кандидатные пары ты реально сравниваешь.
Такой подход схлопывает миллиарды сравнений до миллионов, и именно так системы вроде Google News и ранние веб-краулеры дедупили контент на больших объемах. В нескольких гугловых статьях и инженерных блогах начала 2000-х прямо упоминается этот подход. Довольно просто и аккуратно.
И как почти всегда на масштабе: тебе не нужна идеальная система детекта похожести. Нужна быстрая и достаточно хорошая, потому что стоимость в итоге и диктует правила игры.
👉 @BackendPortal
MinHash превращает большое множество в маленькую, фиксированного размера сигнатуру так, что похожесть двух сигнатур приближенно соответствует жаккаровскому сходству (Jaccard similarity) исходных множеств. Jaccard similarity это просто пересечение множеств, деленное на их объединение; мера того, насколько сильно множества перекрываются.
Это быстрый вероятностный способ оценить “насколько эти два документа похожи”, не сравнивая их слово в слово.
Первый шаг это шинглинг: ты разбиваешь каждый документ на перекрывающиеся n-граммы (например, последовательности из 3 слов), а потом запускаешь MinHash на множестве этих шинглов. На выходе MinHash дает компактную сигнатуру, обычно 100-200 хеш-значений.
Ключевое свойство такое: вероятность того, что две сигнатуры разделят одно и то же минимальное хеш-значение, равна Jaccard similarity их исходных множеств шинглов. Так ты оцениваешь сходство, вообще не трогая сырой текст.
Но проблема сравнения все равно остается. Даже с компактными сигнатурами сравнивать каждую пару дорого. Тут и появляется LSH
Ты делишь каждую сигнатуру на b полос по r строк в каждой, и хешируешь каждую полосу в бакет. Два документа, которые достаточно похожи, с высокой вероятностью попадут в один и тот же бакет хотя бы в одной полосе, и уже только эти кандидатные пары ты реально сравниваешь.
Такой подход схлопывает миллиарды сравнений до миллионов, и именно так системы вроде Google News и ранние веб-краулеры дедупили контент на больших объемах. В нескольких гугловых статьях и инженерных блогах начала 2000-х прямо упоминается этот подход. Довольно просто и аккуратно.
И как почти всегда на масштабе: тебе не нужна идеальная система детекта похожести. Нужна быстрая и достаточно хорошая, потому что стоимость в итоге и диктует правила игры.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2😁2🔥1
Ускорь JSON-ответы FastAPI в 2 раза, а то и больше
1. Обновись до вышедшего FastAPI 0.131.0
2. Объявляй response model (тип возврата)
После этого🦀
https://fastapi.tiangolo.com/advanced/custom-response/#json-performance
👉 @BackendPortal
1. Обновись до вышедшего FastAPI 0.131.0
2. Объявляй response model (тип возврата)
После этого
@pydantic будет заниматься JSON-сериализацией на стороне Rust https://fastapi.tiangolo.com/advanced/custom-response/#json-performance
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍5
Сколько бы блогов, книг или статей ты ни прочитал, прототипирование все равно остается самым быстрым способом что-то понять. Вот мой воркфлоу:
- держу GitHub-репозиторий с названием
- каждая папка это один эксперимент
- если что-то кажется интересным, иду и реализую
- четко формулирую, что именно хочу понять
- нахожу абсолютный минимум того, что нужно
- пишу код, запускаю, итерируюсь
Ключевой момент тут это найти минимально необходимое, самый-самый минимум кода, который поможет тебе собрать нужное понимание. Сначала ты почти всегда будешь писать больше, чем нужно, но со временем начнешь подставлять данные, добавлять
И да, я понимаю, есть соблазн заопенсорсить прототип или превратить его в проект или стартап. Не надо. Помни, цель тут понять. Как только понял, все, закончил, двигаешься дальше.
Вчера, например, я собрал и реализовал разные типы
👉 @BackendPortal
- держу GitHub-репозиторий с названием
prototypes- каждая папка это один эксперимент
- если что-то кажется интересным, иду и реализую
- четко формулирую, что именно хочу понять
- нахожу абсолютный минимум того, что нужно
- пишу код, запускаю, итерируюсь
Ключевой момент тут это найти минимально необходимое, самый-самый минимум кода, который поможет тебе собрать нужное понимание. Сначала ты почти всегда будешь писать больше, чем нужно, но со временем начнешь подставлять данные, добавлять
sleep, мокать и делать правильные допущения.И да, я понимаю, есть соблазн заопенсорсить прототип или превратить его в проект или стартап. Не надо. Помни, цель тут понять. Как только понял, все, закончил, двигаешься дальше.
Вчера, например, я собрал и реализовал разные типы
join-ов и прогнал бенчмарки, чтобы посмотреть, как они реально себя ведут по производительности. Теорию я и так знал, но прототип дал мне реальные, пусть и грубые, цифры.Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥4
Большинство думают, что каждый
Это не так.
Разные языки, разные алгоритмы:
> C++ → Introsort
>
> Python → Timsort
>
> Java → Зависит от типа
>
>
> JavaScript → Зависит от движка
> Chrome V8 = гибрид в стиле Timsort
> Firefox = гибрид Merge Sort
> C → Нет фиксированной гарантии
>
> Go → PDQSort + Insertion
> Rust → Выбираешь сам
>
>
> Swift → Интроспективный гибрид
> Ближе к PDQSort + Insertion
Один и тот же
👉 @BackendPortal
.sort() работает одинаково во всех языках.Это не так.
Разные языки, разные алгоритмы:
> C++ → Introsort
>
std::sort() = Quicksort + Heapsort + Insertion> Python → Timsort
>
list.sort() = Stable (стабильная сортировка)> Java → Зависит от типа
>
Arrays.sort(Object[]) = Timsort (стабильная)>
Arrays.sort(int[]) = Dual-Pivot Quicksort> JavaScript → Зависит от движка
> Chrome V8 = гибрид в стиле Timsort
> Firefox = гибрид Merge Sort
> C → Нет фиксированной гарантии
>
qsort() обычно Quicksort> Go → PDQSort + Insertion
> Rust → Выбираешь сам
>
.sort() = стабильная Merge Sort>
.sort_unstable() = PDQSort> Swift → Интроспективный гибрид
> Ближе к PDQSort + Insertion
Один и тот же
.sort(), но в каждом языке за ним могут стоять разные алгоритмы.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3
Если ты учишь backend в 2026, прокачай вот эти 8 тем:
1️⃣ Дизайн REST API
↓
2️⃣ Аутентификация (JWT / OAuth)
↓
3️⃣ Индексы в базе данных
↓
4️⃣ Кэширование (Redis)
↓
5️⃣ Rate limiting
↓
6️⃣ Логирование и мониторинг
↓
7️⃣ База по Docker
↓
8️⃣ Основы system design
👉 @BackendPortal
↓
↓
↓
↓
↓
↓
↓
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍3
Что такое LGTM?
L – Loki
структурированные, поисковые, коррелируемые логи.
G – Grafana
визуализация всего, что происходит в системе.
T – Tempo
распределенный трейсинг между сервисами.
M – Mimir
истина про поведение системы в виде таймсерий.
Вместе они отвечают на три ключевых вопроса:
что произошло? → логи
насколько все плохо? → метрики
где конкретно тормозит? → трейсы
Без LGTM дебаг распределенных систем это гадание на кофейной гуще.❤️
Плейлист-курс по LGTM (Loki + Grafana + Tempo + Mimir)
👉 @BackendPortal
L – Loki
структурированные, поисковые, коррелируемые логи.
G – Grafana
визуализация всего, что происходит в системе.
T – Tempo
распределенный трейсинг между сервисами.
M – Mimir
истина про поведение системы в виде таймсерий.
Вместе они отвечают на три ключевых вопроса:
что произошло? → логи
насколько все плохо? → метрики
где конкретно тормозит? → трейсы
Без LGTM дебаг распределенных систем это гадание на кофейной гуще.
Плейлист-курс по LGTM (Loki + Grafana + Tempo + Mimir)
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10❤2💊1
Ваша база PostgreSQL уперлась в потолок.
Текущие метрики:
- База 2 ТБ на
- 85% read, 15% write
- Лаг read-replica: в среднем 200 мс, пики до 2 секунд
- Количество подключений в пик упирается в максимум (500)
- Самые медленные запросы: сложные JOIN’ы по 4 таблицам с 100M+ строк
- VACUUM не успевает, растет число мертвых кортежей (dead tuples)
- Хранилище растет на 50 ГБ/месяц
Команда спорит, что делать:
- Добавить PgBouncer для пуллинга соединений
- Внедрить read-replica + роутинг запросов
- Шардировать базу
- Вынести горячие таблицы в DynamoDB
- Залить деньгами (апгрейд до
В этом квартале можно выбрать только 2.
Какие 2 и в каком порядке?
👉 @BackendPortal
Текущие метрики:
- База 2 ТБ на
db.r5.4xlarge- 85% read, 15% write
- Лаг read-replica: в среднем 200 мс, пики до 2 секунд
- Количество подключений в пик упирается в максимум (500)
- Самые медленные запросы: сложные JOIN’ы по 4 таблицам с 100M+ строк
- VACUUM не успевает, растет число мертвых кортежей (dead tuples)
- Хранилище растет на 50 ГБ/месяц
Команда спорит, что делать:
- Добавить PgBouncer для пуллинга соединений
- Внедрить read-replica + роутинг запросов
- Шардировать базу
- Вынести горячие таблицы в DynamoDB
- Залить деньгами (апгрейд до
db.r5.12xlarge)В этом квартале можно выбрать только 2.
Какие 2 и в каком порядке?
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Нашел эту статью о транзакциях в базах данных и реализации ACID в реляционных базах данных действительно интересной, рекомендую прочитать.
https://www.datacamp.com/blog/acid-transactions
👉 @BackendPortal
https://www.datacamp.com/blog/acid-transactions
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🔥2
Паттерны сложности по времени, которые надо знать, чтобы не тупить на собесах
1️⃣
2️⃣ Два вложенных цикла
3️⃣
(потому что суммарно
4️⃣
5️⃣
6️⃣ Два раздельных цикла по
(в Big-O константы отбрасываем:
7️⃣
8️⃣
9️⃣
(типичный merge sort)
1️⃣ 0️⃣
(наивная рекурсия Фибоначчи, без мемоизации)
Если умеешь сходу маппить “паттерн → сложность”, вопросы про time complexity на интервью перестают быть проблемой.
👉 @BackendPortal
for (i = 0; i < n; i++) → O(n)(n × n) → O(n²)for (j = 0; j < i; j++) внутри внешнего цикла → O(n²)(потому что суммарно
1 + 2 + ... + (n-1))i = i * 2 пока i < n → O(log n)i = i / 2 пока i > 1 → O(log n)n → O(n)(в Big-O константы отбрасываем:
O(n) + O(n) = O(n))while (n > 0) n /= 2 → O(log n)T(n) = T(n-1) + O(1) → O(n)T(n) = 2T(n/2) + O(n) → O(n log n)(типичный merge sort)
T(n) = T(n-1) + T(n-2) → O(2ⁿ)(наивная рекурсия Фибоначчи, без мемоизации)
Если умеешь сходу маппить “паттерн → сложность”, вопросы про time complexity на интервью перестают быть проблемой.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7