Немного разобрался с тем, как работают блокировки в PostgreSQL. Главный вывод: разные SQL-команды захватывают разные режимы блокировок, и многие из них специально сделаны совместимыми друг с другом, чтобы минимизировать конкуренцию за блокировки.
Даже обычный SELECT захватывает блокировку, которая препятствует выполнению некоторых «тяжёлых» операций (например, VACUUM FULL, REINDEX и т. п.). Оказалось, существует удивительно много сочетаний SQL-команд, которые могут или не могут выполняться одновременно.
И ещё: вот отличный сайт, который наглядно показывает в виде графа, какие SQL-команды могут выполняться параллельно.
👉 @KodBlog
Даже обычный SELECT захватывает блокировку, которая препятствует выполнению некоторых «тяжёлых» операций (например, VACUUM FULL, REINDEX и т. п.). Оказалось, существует удивительно много сочетаний SQL-команд, которые могут или не могут выполняться одновременно.
И ещё: вот отличный сайт, который наглядно показывает в виде графа, какие SQL-команды могут выполняться параллельно.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥2🍾1
Если версии NuGet-пакетов в вашем .NET-решении разбросаны по файлам проектов, в будущем вам неизбежно придётся заниматься их приведением в порядок.
Central Package Management позволяет вынести версии пакетов в
Проекты просто ссылаются на пакет. Версия хранится в одном файле.
Меньше археологии в зависимостях.
👉 @KodBlog
Central Package Management позволяет вынести версии пакетов в
Directory.Packages.props.Проекты просто ссылаются на пакет. Версия хранится в одном файле.
Меньше археологии в зависимостях.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🍾2
This media is not supported in your browser
VIEW IN TELEGRAM
Создавайте первоклассную документацию для своего API или проекта.
Starlight предлагает всё необходимое: высокую скорость благодаря Astro, встроенную оптимизацию для SEO, доступность и поиск, а также поддержку Markdown, MDX и нескольких языков.
→ http://starlight.astro.build/es
👉 @KodBlog
Starlight предлагает всё необходимое: высокую скорость благодаря Astro, встроенную оптимизацию для SEO, доступность и поиск, а также поддержку Markdown, MDX и нескольких языков.
→ http://starlight.astro.build/es
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾1
Масштабирование веб-приложений до 1 000 000 пользователей
Мне довелось работать над крупной системой, которой пользовались более миллиона человек. Вот как мы масштабировали её, чтобы она справлялась с таким объёмом трафика.
Изначально приложение представляло собой классический монолит: один сервер приложений и один сервер базы данных. Такая архитектура отлично работала несколько лет, но по мере роста числа пользователей система начала замедляться. Стало ясно, что нужны изменения.
Следующим этапом стало горизонтальное масштабирование Web API, чтобы обрабатывать большее количество запросов. Экземпляр базы данных при этом масштабировали вертикально (scale up), увеличивая его вычислительные ресурсы. Однако вскоре именно база данных стала узким местом.
Кэширование уже использовалось, но это был простой локальный кэш в памяти каждого сервера приложений. Поэтому мы внедрили распределённое кэширование на базе Redis. После этого нагрузка на базу данных значительно снизилась, поскольку большая часть запросов начала обслуживаться из кэша. Дополнительным преимуществом стало заметное улучшение производительности и отзывчивости системы.
Главная мысль, которую я хочу донести: решайте ту проблему, которая существует сейчас. Разработчики часто склонны к избыточному проектированию , пытаясь заранее подготовить систему к масштабам, которых она ещё не достигла.
И ещё один важный момент: зачем вообще масштабировать приложение, которое не приносит прибыли? Разработчики редко задумываются о финансовой стороне вопроса. Не забывайте, что приложение обычно существует для решения бизнес-задач. А бизнес сложно назвать успешным, если он не приносит прибыль.
👉 @KodBlog
Мне довелось работать над крупной системой, которой пользовались более миллиона человек. Вот как мы масштабировали её, чтобы она справлялась с таким объёмом трафика.
Изначально приложение представляло собой классический монолит: один сервер приложений и один сервер базы данных. Такая архитектура отлично работала несколько лет, но по мере роста числа пользователей система начала замедляться. Стало ясно, что нужны изменения.
Следующим этапом стало горизонтальное масштабирование Web API, чтобы обрабатывать большее количество запросов. Экземпляр базы данных при этом масштабировали вертикально (scale up), увеличивая его вычислительные ресурсы. Однако вскоре именно база данных стала узким местом.
Кэширование уже использовалось, но это был простой локальный кэш в памяти каждого сервера приложений. Поэтому мы внедрили распределённое кэширование на базе Redis. После этого нагрузка на базу данных значительно снизилась, поскольку большая часть запросов начала обслуживаться из кэша. Дополнительным преимуществом стало заметное улучшение производительности и отзывчивости системы.
Главная мысль, которую я хочу донести: решайте ту проблему, которая существует сейчас. Разработчики часто склонны к избыточному проектированию , пытаясь заранее подготовить систему к масштабам, которых она ещё не достигла.
И ещё один важный момент: зачем вообще масштабировать приложение, которое не приносит прибыли? Разработчики редко задумываются о финансовой стороне вопроса. Не забывайте, что приложение обычно существует для решения бизнес-задач. А бизнес сложно назвать успешным, если он не приносит прибыль.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2🍾2
Чёрт… Это может перевернуть всё представление об эмуляторах AWS.
Команда разработчиков отказалась от привычного подхода к созданию эмуляторов AWS и представила Floci.
Это один исполняемый файл на Go размером всего 13 МиБ, который менее чем за 1 секунду запускает 45 сервисов AWS (S3, Lambda, DynamoDB, SQS, SNS, IAM, CloudFormation, Step Functions и другие). Никакого Docker. Никакого LocalStack. Никаких счетов за AWS. Никаких 4 ГБ оперативной памяти, занятых контейнерами. Никакого ожидания по 30 секунд.
Достаточно скачать исполняемый файл, запустить его — и у вас локально работает практически вся инфраструктура AWS.
https://github.com/floci-io/floci
👉 @KodBlog
Команда разработчиков отказалась от привычного подхода к созданию эмуляторов AWS и представила Floci.
Это один исполняемый файл на Go размером всего 13 МиБ, который менее чем за 1 секунду запускает 45 сервисов AWS (S3, Lambda, DynamoDB, SQS, SNS, IAM, CloudFormation, Step Functions и другие). Никакого Docker. Никакого LocalStack. Никаких счетов за AWS. Никаких 4 ГБ оперативной памяти, занятых контейнерами. Никакого ожидания по 30 секунд.
Достаточно скачать исполняемый файл, запустить его — и у вас локально работает практически вся инфраструктура AWS.
https://github.com/floci-io/floci
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍2🍾2
А кто-о-о это сделал: они полностью переписали PostgreSQL на Rust и он уже проходит 100% официальных тестов PostgreSQL 😔
Важно: это не форк, а полностью новая реализация с нуля на Rust, которая на данный момент:
• Проходит все 46 066 запросов из regression suite PostgreSQL 18.3.
• Совместима на уровне диска (можно запустить её напрямую с вашим текущим каталогом данных).
• Имеет рабочее демо в браузере.
Цель проекта — сделать одну из самых сложных баз данных в мире значительно проще для модификации, расширения и оптимизации изнутри, используя Rust и AI-assisted programming.
И самое безумное: уже существует WIP-версия (пока не опубликована), которая обещает быть на 50% быстрее на транзакционных нагрузках и примерно в 300 раз быстрее на аналитических нагрузках.
РЕПО 👇
https://github.com/malisper/pgrust
👉 @KodBlog
Важно: это не форк, а полностью новая реализация с нуля на Rust, которая на данный момент:
• Проходит все 46 066 запросов из regression suite PostgreSQL 18.3.
• Совместима на уровне диска (можно запустить её напрямую с вашим текущим каталогом данных).
• Имеет рабочее демо в браузере.
Цель проекта — сделать одну из самых сложных баз данных в мире значительно проще для модификации, расширения и оптимизации изнутри, используя Rust и AI-assisted programming.
И самое безумное: уже существует WIP-версия (пока не опубликована), которая обещает быть на 50% быстрее на транзакционных нагрузках и примерно в 300 раз быстрее на аналитических нагрузках.
РЕПО 👇
https://github.com/malisper/pgrust
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15🤣5🍾1
Правильно ли вы внедряете зависимости в контроллеры?
Многие разработчики не знают об этом.
Внедрять зависимости в контроллеры можно двумя способами:
- через конструктор;
- через внедрение в метод (method injection).
Приходилось работать с раздутыми контроллерами, в конструктор которых передают слишком много зависимостей?
При этом конкретный endpoint использует лишь часть из них.
❌ В результате память расходуется впустую: все зависимости, переданные через конструктор, создаются в куче при создании контроллера — независимо от того, будут они использоваться или нет.
✅ Так почему бы не внедрять только те зависимости, которые действительно нужны, прямо в метод endpoint?
Теперь это можно делать без атрибута
Внедряя зависимости только там, где они действительно нужны, вы повышаете читаемость, упрощаете поддержку и улучшаете производительность контроллеров.
А какой подход предпочитаете вы? 👇
👉 @KodBlog
Многие разработчики не знают об этом.
Внедрять зависимости в контроллеры можно двумя способами:
- через конструктор;
- через внедрение в метод (method injection).
Приходилось работать с раздутыми контроллерами, в конструктор которых передают слишком много зависимостей?
При этом конкретный endpoint использует лишь часть из них.
❌ В результате память расходуется впустую: все зависимости, переданные через конструктор, создаются в куче при создании контроллера — независимо от того, будут они использоваться или нет.
✅ Так почему бы не внедрять только те зависимости, которые действительно нужны, прямо в метод endpoint?
Теперь это можно делать без атрибута
[FromServices] — он больше не требуется. Всё работает так же, как и в Minimal APIs.Внедряя зависимости только там, где они действительно нужны, вы повышаете читаемость, упрощаете поддержку и улучшаете производительность контроллеров.
А какой подход предпочитаете вы? 👇
Please open Telegram to view this post
VIEW IN TELEGRAM
👎8👍4❤2🍾1
Как мигрировать монолит на микросервисы без полного переписывания системы?
Одна из широко используемых стратегий — Strangler Pattern.
Вместо того чтобы заменять всё приложение целиком, вы переносите функциональность поэтапно — по одному модулю за раз.
Например, уведомления.
Сейчас уведомления обрабатываются внутри монолита.
Вы создаёте микросервис, который берёт эту функциональность на себя.
С этого момента отправка уведомлений выполняется новым сервисом, а остальная часть приложения продолжает работать в монолите.
После того как вы убедились, что всё работает корректно, вы удаляете эту функциональность из монолита и повторяете процесс со следующим модулем.
Как это обычно реализуют?
Один из самых распространённых вариантов — разместить перед приложением API Gateway или Reverse Proxy.
Этот компонент принимает запросы и решает, куда их направить:
в монолит;
в новый микросервис.
Так старая и новая системы могут сосуществовать на протяжении всей миграции.
👉 @KodBlog
Одна из широко используемых стратегий — Strangler Pattern.
Вместо того чтобы заменять всё приложение целиком, вы переносите функциональность поэтапно — по одному модулю за раз.
Например, уведомления.
Сейчас уведомления обрабатываются внутри монолита.
Вы создаёте микросервис, который берёт эту функциональность на себя.
С этого момента отправка уведомлений выполняется новым сервисом, а остальная часть приложения продолжает работать в монолите.
После того как вы убедились, что всё работает корректно, вы удаляете эту функциональность из монолита и повторяете процесс со следующим модулем.
Как это обычно реализуют?
Один из самых распространённых вариантов — разместить перед приложением API Gateway или Reverse Proxy.
Этот компонент принимает запросы и решает, куда их направить:
в монолит;
в новый микросервис.
Так старая и новая системы могут сосуществовать на протяжении всей миграции.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾3
Совет по GitHub Actions: не предоставляйте
Задаче сборки обычно достаточно прав на чтение.
Задаче публикации релиза могут потребоваться права на запись.
Боту, работающему с issues или комментариями, нужен уже другой набор разрешений.
Настраивайте
https://docs.github.com/en/actions/tutorials/authenticate-with-github_token
👉 @KodBlog
GITHUB_TOKEN больше прав доступа, чем действительно требуется конкретной задаче Задаче сборки обычно достаточно прав на чтение.
Задаче публикации релиза могут потребоваться права на запись.
Боту, работающему с issues или комментариями, нужен уже другой набор разрешений.
Настраивайте
permissions отдельно для каждого workflow или конкретной задачи. Начинайте с минимально необходимых прав и добавляйте новые только тогда, когда без них действительно что-то перестаёт работать.https://docs.github.com/en/actions/tutorials/authenticate-with-github_token
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🍾1
Модель предметной области (Domain Model) и DTO решают две разные задачи. В тот момент, когда один класс начинает выполнять обе, вы создаете ловушку для самого себя в будущем.
Вот с чего начинается большинство проектов. Один класс
Именно эта надежда и является проблемой.
Добавили новый столбец в базу данных, забыли про атрибут — и внутренний
Разделите их — и конфликт исчезнет.
Оставьте в доменной модели класс
Теперь внутренние поля не могут «утечь», потому что их просто нет в классе, который возвращает API. Доменная модель может свободно меняться в соответствии с требованиями бизнеса. Контракт API изменяется только тогда, когда вы сами принимаете такое решение. А версионирование становится предсказуемым и скучным в хорошем смысле слова: вы просто добавляете новый DTO.
Главное различие заключается в вопросе, на который отвечает каждый класс. Доменная модель отвечает на вопрос: «Какие здесь действуют бизнес-правила?». DTO отвечает на вопрос: «Что должен видеть внешний мир?». И почти никогда это не один и тот же ответ.
Два класса кажутся лишней работой в первый день, но могут избавить вас от ломающего изменения на девяностый.
Стоит поделиться этим, если ваше API хоть раз случайно отдавало данные, которые не должно было.
👉 @KodBlog
Вот с чего начинается большинство проектов. Один класс
Product. В нем есть Id, Name и Price, а также InternalSku и CostPrice, которые внешний мир никогда не должен видеть. Поэтому вы ставите [JsonIgnore] на внутренние поля и надеетесь, что никто не добавит новое свойство, забыв его скрыть.Именно эта надежда и является проблемой.
Добавили новый столбец в базу данных, забыли про атрибут — и внутренний
CostPrice уходит клиенту. Достаточно одной миграции EF Core, чтобы контракт вашего публичного API незаметно изменился. Один класс выполняет две разные задачи, и они начинают конфликтовать каждый раз, когда вы что-то меняете.Разделите их — и конфликт исчезнет.
Оставьте в доменной модели класс
Product, который содержит InternalSku и CostPrice как init-only свойства, а также всю бизнес-логику. Отдельно создайте record ProductDto, в котором будут только Id, Name и Price. Именно этот тип и должен возвращаться наружу.Теперь внутренние поля не могут «утечь», потому что их просто нет в классе, который возвращает API. Доменная модель может свободно меняться в соответствии с требованиями бизнеса. Контракт API изменяется только тогда, когда вы сами принимаете такое решение. А версионирование становится предсказуемым и скучным в хорошем смысле слова: вы просто добавляете новый DTO.
Главное различие заключается в вопросе, на который отвечает каждый класс. Доменная модель отвечает на вопрос: «Какие здесь действуют бизнес-правила?». DTO отвечает на вопрос: «Что должен видеть внешний мир?». И почти никогда это не один и тот же ответ.
Два класса кажутся лишней работой в первый день, но могут избавить вас от ломающего изменения на девяностый.
Стоит поделиться этим, если ваше API хоть раз случайно отдавало данные, которые не должно было.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4🍾2
Как быстрее всего выполнить массовую вставку данных в SQL?
Независимо от того, разрабатываете ли вы платформу для аналитики данных, переносите legacy-систему или подключаете большой поток новых пользователей, в какой-то момент вам, скорее всего, понадобится вставить в базу данных огромный объем данных.
Поэтому важно понимать, какие техники быстрой массовой вставки доступны в C# и EF Core.
EF Core — вполне приемлемый вариант. Он предлагает привычный developer experience, и хотя его производительность не самая высокая, для вашего сценария ее может быть достаточно.
Если нужна более высокая производительность, еще один вариант — библиотека EF Bulk Extensions. Работа с ней по-прежнему ощущается как работа с EF, и это дополнительный плюс.
Все еще нужны более быстрые вставки? Тогда ваш выбор —
👉 @KodBlog
Независимо от того, разрабатываете ли вы платформу для аналитики данных, переносите legacy-систему или подключаете большой поток новых пользователей, в какой-то момент вам, скорее всего, понадобится вставить в базу данных огромный объем данных.
Поэтому важно понимать, какие техники быстрой массовой вставки доступны в C# и EF Core.
EF Core — вполне приемлемый вариант. Он предлагает привычный developer experience, и хотя его производительность не самая высокая, для вашего сценария ее может быть достаточно.
Если нужна более высокая производительность, еще один вариант — библиотека EF Bulk Extensions. Работа с ней по-прежнему ощущается как работа с EF, и это дополнительный плюс.
Все еще нужны более быстрые вставки? Тогда ваш выбор —
SqlBulkCopy. Это самый быстрый способ вставить большой объем данных в SQL Server. В PostgreSQL есть команда COPY, которая работает схожим образом.Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1🍾1
Я добавил одну строку, чтобы сделать моё приложение с Azure SQL надёжнее.
Она сразу же сломала все транзакции в моём коде.
Вот что произошло.
Azure SQL — это общая мультитенантная служба. Она может кратковременно разрывать подключения во время аварийного переключения, масштабирования и скачков нагрузки.
Это временные сбои. Они быстро проходят, и повторная попытка через небольшой промежуток времени почти всегда завершается успешно.
На локальном SQL Server вы почти никогда с ними не сталкиваетесь. В облаке это нормальное явление.
EF Core решает эту проблему одной строкой:
→ EnableRetryOnFailure(maxRetryCount: 5)
Теперь неуспешные команды автоматически выполняются повторно, причём задержка между попытками постепенно увеличивается. Больше никаких случайных падений в продакшене из-за единственного разорванного подключения.
Повторные попытки выполняются только при временных ошибках, поэтому реальная проблема, например нарушение ограничения, не будет скрыта.
Но есть одна ловушка, о которой никто не предупреждает.
❌ Как только вы включаете повторные попытки, эта строка начинает выбрасывать исключение:
→ using var tx = context.Database.BeginTransaction();
Почему? Стратегия повторных попыток должна иметь возможность повторно выполнить ВСЮ операцию как единое целое.
Транзакция, созданная вручную, охватывает только часть вашего кода. EF Core не может безопасно повторно выполнить половину операции, поэтому не позволяет запускать транзакцию таким способом.
✅ Решение — обернуть работу в стратегию выполнения:
→ var strategy = context.Database.CreateExecutionStrategy();
→ await strategy.ExecuteAsync(async () => { ... ваша транзакция здесь ... });
Теперь весь блок повторно выполняется как единое целое. Транзакция и повторные попытки наконец работают вместе, а при временном сбое весь блок корректно выполняется заново.
На этой детали спотыкается почти каждая команда, которая переносит EF Core в облако.
Они включают повторные попытки, выкатывают приложение, а затем наблюдают, как транзакции начинают падать при первом же кратковременном сбое базы данных под нагрузкой.
Исправление занимает две строки. А ошибка, которую оно предотвращает, может стоить вам целых выходных, потраченных на отладку.
👉 @KodBlog
Она сразу же сломала все транзакции в моём коде.
Вот что произошло.
Azure SQL — это общая мультитенантная служба. Она может кратковременно разрывать подключения во время аварийного переключения, масштабирования и скачков нагрузки.
Это временные сбои. Они быстро проходят, и повторная попытка через небольшой промежуток времени почти всегда завершается успешно.
На локальном SQL Server вы почти никогда с ними не сталкиваетесь. В облаке это нормальное явление.
EF Core решает эту проблему одной строкой:
→ EnableRetryOnFailure(maxRetryCount: 5)
Теперь неуспешные команды автоматически выполняются повторно, причём задержка между попытками постепенно увеличивается. Больше никаких случайных падений в продакшене из-за единственного разорванного подключения.
Повторные попытки выполняются только при временных ошибках, поэтому реальная проблема, например нарушение ограничения, не будет скрыта.
Но есть одна ловушка, о которой никто не предупреждает.
❌ Как только вы включаете повторные попытки, эта строка начинает выбрасывать исключение:
→ using var tx = context.Database.BeginTransaction();
Почему? Стратегия повторных попыток должна иметь возможность повторно выполнить ВСЮ операцию как единое целое.
Транзакция, созданная вручную, охватывает только часть вашего кода. EF Core не может безопасно повторно выполнить половину операции, поэтому не позволяет запускать транзакцию таким способом.
✅ Решение — обернуть работу в стратегию выполнения:
→ var strategy = context.Database.CreateExecutionStrategy();
→ await strategy.ExecuteAsync(async () => { ... ваша транзакция здесь ... });
Теперь весь блок повторно выполняется как единое целое. Транзакция и повторные попытки наконец работают вместе, а при временном сбое весь блок корректно выполняется заново.
На этой детали спотыкается почти каждая команда, которая переносит EF Core в облако.
Они включают повторные попытки, выкатывают приложение, а затем наблюдают, как транзакции начинают падать при первом же кратковременном сбое базы данных под нагрузкой.
Исправление занимает две строки. А ошибка, которую оно предотвращает, может стоить вам целых выходных, потраченных на отладку.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾2
image_2026-07-14_07-07-25.png
1.3 MB
Инвалидация кеша: почему удаление данных — одна из самых сложных задач в разработке программного обеспечения
Кеширование делает приложения быстрыми.
Но рано или поздно каждая система сталкивается с одним вопросом:
Что происходит, когда исходные данные изменяются?
Именно здесь начинается инвалидация кеша.
Что такое инвалидация кеша?
Представьте такой поток запроса:
Пользователь
│
▼
Кеш Redis
│
▼
База данных
Первый запрос:
> Промах кеша
> Чтение из базы данных
> Сохранение в Redis
Все последующие запросы выполняются быстро.
До тех пор, пока...
Данные не изменятся.
Пример
Товар стоит: ₹999
Значение закешировано в Redis.
Позже...
Администратор обновляет цену: ₹899
Теперь в базе данных хранится новая цена.
Но Redis по-прежнему возвращает: ₹999
Пользователи видят устаревшую информацию.
Почему это сложно? Все кешированные копии должны оставаться синхронизированными.
Иногда в системе используются:
> Кеш браузера
> CDN
> Redis
> Память приложения
Одно обновление может потребовать инвалидации данных сразу в нескольких местах.
Распространённые стратегии инвалидации кеша
1. Time-To-Live (TTL)
TTL = 10 минут
Кеш автоматически истекает.
Просто.
Но до истечения срока действия пользователи могут видеть устаревшие данные.
2. Удаление при обновлении
При каждом изменении базы данных:
Обновление БД
│
Удаление кеша
Следующий запрос заново создаёт запись в кеше.
Это один из самых распространённых подходов.
3. Write-Through Cache
При каждой операции записи обновляются:
> База данных
> Кеш
Они остаются синхронизированными.
4. Инвалидация на основе событий
Когда данные изменяются...
Публикуется событие.
Каждый сервис очищает свой кеш.
Идеальный подход для распределённых систем.
Пример из реального проекта
В приложении для электронной коммерции обновляется цена товара.
Без инвалидации кеша:
> Веб-сайт → ₹999
> Мобильное приложение → ₹999
> База данных → ₹899
Клиенты получают несогласованную информацию.
Распространённые ошибки
❌ Забывают инвалидировать кеш
❌ Устанавливают слишком большие значения TTL
❌ Кешируют часто изменяющиеся данные
❌ Обновляют базу данных, но не кеш
Главный выводs
> Кеширование делает системы быстрыми.
> Инвалидация кеша обеспечивает корректность данных.
> Кеш, который никогда не истекает, рано или поздно становится некорректным.
> Завтра мы разберём разные стратегии кеширования:
> Cache-Aside, Read-Through, Write-Through и Write-Back
👉 @KodBlog
Кеширование делает приложения быстрыми.
Но рано или поздно каждая система сталкивается с одним вопросом:
Что происходит, когда исходные данные изменяются?
Именно здесь начинается инвалидация кеша.
Что такое инвалидация кеша?
Представьте такой поток запроса:
Пользователь
│
▼
Кеш Redis
│
▼
База данных
Первый запрос:
> Промах кеша
> Чтение из базы данных
> Сохранение в Redis
Все последующие запросы выполняются быстро.
До тех пор, пока...
Данные не изменятся.
Пример
Товар стоит: ₹999
Значение закешировано в Redis.
Позже...
Администратор обновляет цену: ₹899
Теперь в базе данных хранится новая цена.
Но Redis по-прежнему возвращает: ₹999
Пользователи видят устаревшую информацию.
Почему это сложно? Все кешированные копии должны оставаться синхронизированными.
Иногда в системе используются:
> Кеш браузера
> CDN
> Redis
> Память приложения
Одно обновление может потребовать инвалидации данных сразу в нескольких местах.
Распространённые стратегии инвалидации кеша
1. Time-To-Live (TTL)
TTL = 10 минут
Кеш автоматически истекает.
Просто.
Но до истечения срока действия пользователи могут видеть устаревшие данные.
2. Удаление при обновлении
При каждом изменении базы данных:
Обновление БД
│
Удаление кеша
Следующий запрос заново создаёт запись в кеше.
Это один из самых распространённых подходов.
3. Write-Through Cache
При каждой операции записи обновляются:
> База данных
> Кеш
Они остаются синхронизированными.
4. Инвалидация на основе событий
Когда данные изменяются...
Публикуется событие.
Каждый сервис очищает свой кеш.
Идеальный подход для распределённых систем.
Пример из реального проекта
В приложении для электронной коммерции обновляется цена товара.
Без инвалидации кеша:
> Веб-сайт → ₹999
> Мобильное приложение → ₹999
> База данных → ₹899
Клиенты получают несогласованную информацию.
Распространённые ошибки
❌ Забывают инвалидировать кеш
❌ Устанавливают слишком большие значения TTL
❌ Кешируют часто изменяющиеся данные
❌ Обновляют базу данных, но не кеш
Главный выводs
> Кеширование делает системы быстрыми.
> Инвалидация кеша обеспечивает корректность данных.
> Кеш, который никогда не истекает, рано или поздно становится некорректным.
> Завтра мы разберём разные стратегии кеширования:
> Cache-Aside, Read-Through, Write-Through и Write-Back
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🍾2
Встречайте .NET 11 Preview 6!
https://devblogs.microsoft.com/dotnet/dotnet-11-preview-6/
Возможности в этой предварительной версии — просто вау
#dotnet #mvpbuzz
👉 @KodBlog
https://devblogs.microsoft.com/dotnet/dotnet-11-preview-6/
Возможности в этой предварительной версии — просто вау
#dotnet #mvpbuzz
Please open Telegram to view this post
VIEW IN TELEGRAM
Microsoft News
.NET 11 Preview 6 is now available!
Find out about the new features in .NET 11 Preview 6 across runtime, SDK, libraries, ASP.NET Core, .NET MAUI, C#, Entity Framework Core, F#, and container images.
❤4🍾2🥴1
Служебные учётные записи задают контекст безопасности, который службы Windows, запланированные задачи и приложения используют для доступа к локальным и сетевым ресурсам.
В материале разбирается, что такое служебные учётные записи, какие проблемы они могут создавать, а также как выбрать и настроить подходящий тип локальной или управляемой учётной записи в Windows Server 2025.
https://learn.microsoft.com/en-us/training/modules/understand-windows-service-accounts/
👉 @KodBlog
В материале разбирается, что такое служебные учётные записи, какие проблемы они могут создавать, а также как выбрать и настроить подходящий тип локальной или управляемой учётной записи в Windows Server 2025.
https://learn.microsoft.com/en-us/training/modules/understand-windows-service-accounts/
Please open Telegram to view this post
VIEW IN TELEGRAM
Docs
Understand Windows Server service accounts - Training
Describe the purpose and common problems of Windows Server service accounts, and select and configure the correct local or managed account type, including the Windows Server 2025 delegated Managed Service Account (dMSA).
🍾2
В .NET есть коллекция, из которой данные читаются в 2–4 раза быстрее, чем из
Большинство разработчиков ни разу её не использовали.
Она называется
Идея простая:
> Создаёте коллекцию один раз, читаете из неё много раз и больше никогда не изменяете.
Такие данные наверняка уже есть в ваших проектах:
- коды стран;
- названия ролей;
- feature flags;
- разрешённые расширения файлов.
Вы загружаете их при старте приложения и больше не меняете.
Но обычный
Он по-прежнему готов к добавлению и удалению элементов, а также к изменению размера — операциям, которые вы никогда не выполните. За эту гибкость приходится платить при каждом чтении.
Почему Frozen-коллекции быстрее
Когда вы вызываете
После этого он выбирает наиболее подходящую внутреннюю структуру:
- для коротких строковых ключей используется оптимизированное хеширование;
- для небольших диапазонов целых чисел может применяться прямая индексация;
- для маленьких множеств используется быстрый линейный поиск.
Вы один раз платите за создание коллекции и затем постоянно получаете более быстрые операции чтения.
Компромисс простой:
- ❌ создание медленнее в 2–10 раз;
- ✅ чтение быстрее в 2–4 раза, а для строк выигрыш может быть ещё больше.
Когда использовать
- Для lookup-таблиц, которые загружаются при старте и больше не изменяются.
- Вместо длинного
- Для любой коллекции с большим количеством операций чтения, которая создаётся один раз на запрос.
Когда не использовать
- Если коллекция должна изменяться после создания: методов
- Если данные будут прочитаны всего несколько раз.
- Если проект всё ещё работает на .NET 7 или более старой версии.
👉 @KodBlog
DictionaryБольшинство разработчиков ни разу её не использовали.
Она называется
FrozenDictionary — а для множеств есть FrozenSet. Обе коллекции появились в .NET 8.Идея простая:
> Создаёте коллекцию один раз, читаете из неё много раз и больше никогда не изменяете.
Такие данные наверняка уже есть в ваших проектах:
- коды стран;
- названия ролей;
- feature flags;
- разрешённые расширения файлов.
Вы загружаете их при старте приложения и больше не меняете.
Но обычный
Dictionary об этом не знает.Он по-прежнему готов к добавлению и удалению элементов, а также к изменению размера — операциям, которые вы никогда не выполните. За эту гибкость приходится платить при каждом чтении.
Почему Frozen-коллекции быстрее
Когда вы вызываете
ToFrozenDictionary, .NET тратит дополнительное время на анализ данных.После этого он выбирает наиболее подходящую внутреннюю структуру:
- для коротких строковых ключей используется оптимизированное хеширование;
- для небольших диапазонов целых чисел может применяться прямая индексация;
- для маленьких множеств используется быстрый линейный поиск.
Вы один раз платите за создание коллекции и затем постоянно получаете более быстрые операции чтения.
Компромисс простой:
- ❌ создание медленнее в 2–10 раз;
- ✅ чтение быстрее в 2–4 раза, а для строк выигрыш может быть ещё больше.
Когда использовать
- Для lookup-таблиц, которые загружаются при старте и больше не изменяются.
- Вместо длинного
switch по строковым литералам — например, с проверкой через Contains.- Для любой коллекции с большим количеством операций чтения, которая создаётся один раз на запрос.
Когда не использовать
- Если коллекция должна изменяться после создания: методов
Add и Remove нет.- Если данные будут прочитаны всего несколько раз.
- Если проект всё ещё работает на .NET 7 или более старой версии.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤3🍌2🍾1
.NET 11 Preview 6 включает Extension Indexers из C# 15.
Например, теперь можно расширять такие типы, как
Более выразительный код и более естественные API.
#dotnet #CSharp #NET11
👉 @KodBlog
Например, теперь можно расширять такие типы, как
IReadOnlyList<T>, чтобы получать последний элемент через ^1 — без изменения самой коллекции и без дублирования вспомогательной логики.Более выразительный код и более естественные API.
#dotnet #CSharp #NET11
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3🍾2
This media is not supported in your browser
VIEW IN TELEGRAM
Postgres 19 обрабатывает всплески нагрузки так, как и должна работать инфраструктура.
Не за счёт одного фиксированного пула I/O-воркеров, рассчитанного на некий вымышленный «средний» день.
А динамически.
→ Нагрузка резко растёт
→ Очередь операций ввода-вывода увеличивается
→ PostgreSQL это замечает
→ Запускаются дополнительные воркеры
→ Очередь разгружается
→ Когда нагрузка снижается, лишние воркеры завершают работу
Без ручного вмешательства.
Без постоянного избыточного резервирования ресурсов.
И без крошечного пула воркеров, который захлёбывается под продакшен-нагрузкой.
PostgreSQL превращается в инфраструктуру, которая сама адаптируется к нагрузке, а не требует, чтобы вы постоянно за ней присматривали.
👉 @KodBlog
Не за счёт одного фиксированного пула I/O-воркеров, рассчитанного на некий вымышленный «средний» день.
А динамически.
→ Нагрузка резко растёт
→ Очередь операций ввода-вывода увеличивается
→ PostgreSQL это замечает
→ Запускаются дополнительные воркеры
→ Очередь разгружается
→ Когда нагрузка снижается, лишние воркеры завершают работу
Без ручного вмешательства.
Без постоянного избыточного резервирования ресурсов.
И без крошечного пула воркеров, который захлёбывается под продакшен-нагрузкой.
PostgreSQL превращается в инфраструктуру, которая сама адаптируется к нагрузке, а не требует, чтобы вы постоянно за ней присматривали.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🍾2
Паттерн Options в .NET — это одна из тех фич, которые я стабильно использую во всех своих C#-проектах
✅ Более чистое управление конфигами
✅ Сильно типизированные классы
✅ Простая интеграция с DI
✅ Без проблем работает с
Почему это важно
Вместо того чтобы раскидывать значения конфигов по всему коду, ты централизуешь их в структурированных классах. Это не только улучшает читаемость, но и делает код более тестируемым и удобным в сопровождении.
Обычно это выглядит так
🔹 Определяешь конфиг в
🔹 Создаёшь POCO-класс
🔹 Биндишь его через
🔹 Инжектишь в сервисы через
Просто. Масштабируемо. Аккуратно.
А ты используешь этот паттерн у себя или до сих пор дёргаешь значения конфигов через😃
👉 @KodBlog
appsettings.json, secrets.json, Azure Key Vault и прочим Почему это важно
Вместо того чтобы раскидывать значения конфигов по всему коду, ты централизуешь их в структурированных классах. Это не только улучшает читаемость, но и делает код более тестируемым и удобным в сопровождении.
Обычно это выглядит так
appsettings.json .AddOptions<T>().BindConfiguration() IOptions<T> Просто. Масштабируемо. Аккуратно.
А ты используешь этот паттерн у себя или до сих пор дёргаешь значения конфигов через
IConfiguration["key"] Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3❤2🍾1
using var client = new HttpClient(); внутри цикла выглядит как ответственное управление ресурсами. На деле это утечка сокетов.Каждый новый экземпляр
HttpClient создаёт собственный пул соединений, а после вызова Dispose сокеты остаются в состоянии TIME_WAIT примерно на четыре минуты. Под нагрузкой доступные порты заканчиваются, и вы получаете SocketException, хотя сервер полностью исправен.Вместо этого внедрите
IHttpClientFactory. Одна строка — и проблема решена.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍4🍾2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🍾1