Использовать очередь сообщений вместо HTTP-запроса целесообразно в ситуациях, когда тебе важно развязать сервисы по времени, обеспечить надёжность доставки, повысить масштабируемость и устойчивость системы.
Circuit Breaker (предохранитель) — шаблон устойчивости, предотвращающий постоянные попытки вызвать неработающий сервис.
Три состояния:
Состояние | Описание |
---|---|
Closed | Все вызовы проходят |
Open | Вызовы блокируются (B недоступен) |
Half-Open | Периодически пробуем снова |
Как работает:
Open
Half-Open
: пробный вызовClosed
, иначе остаётся Open
Библиотеки:
Реализация ASP.NET Core:
dotnet add package Polly
dotnet add package Microsoft.Extensions.Http.Polly
using Polly;
using Polly.CircuitBreaker;
builder.Services.AddHttpClient("ExternalApi", client =>
{
client.BaseAddress = new Uri("https://example.com/api/");
})
.AddTransientHttpErrorPolicy(policyBuilder =>
policyBuilder.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(30)
)
);
Retry (повторный запрос) — это механизм, при котором клиент повторяет неудачный вызов через определённый промежуток времени.
Настраивается:
timeout
, 5xx
, network errors
) Политика при которой пользователю полагается сколько то запросов в какой то промежуток времени.
Реализация ASP.NET Core
dotnet add package AspNetCoreRateLimit
Config:
{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"Period": "1m",
"Limit": 100,
"HttpStatusCode": 429
}
}
Используй разные лимиты для разных клиентов/уровней доступа
Exponential backoff — это способ увеличения задержки между попытками:
Пример:
Это снижает нагрузку на умирающий сервис и повышает устойчивость.
Часто комбинируется с джиттером (jitter) — небольшим случайным смещением, чтобы избежать "шторма" повторов от всех клиентов.
DLQ (очередь мёртвых сообщений) — это специальная очередь, куда попадают необработанные или ошибочные сообщения, например:
Цель:
Используется в Kafka, RabbitMQ, AWS SQS и других брокерах.
Eventual consistency (временная согласованность) — это модель, при которой данные становятся согласованными не мгновенно, а со временем, при условии отсутствия новых обновлений.
Пример:
Пользователь оформил заказ → заказ сразу появляется в OrderService
, а в AnalyticsService
он появится через Kafka-событие через пару секунд.
Как с этим жить:
status: processing / confirmed
)Кэш консистентность — это вопрос синхронизации данных в кэше и в "истинном" источнике (обычно — БД).
Классическая проблема:
Виды консистентности кэша
Подход | Принцип | Плюсы | Минусы |
---|---|---|---|
No consistency | Кэш не инвалидируется | Просто | Могут быть баги, неактуальные данные |
Write-through | При UPDATE : сначала записываем в кэш, затем в БД |
Стабильный кэш | Нужно синхронизировать ошибки |
Write-behind | Записываем в кэш, а БД обновляется асинхронно (через очередь) | Быстро, удобно | Сложно с потерей данных при падении |
Cache-aside (lazy) | Кэшируем только при чтении; при обновлении — инвалидация | Гибко, руками управляем | Требует дисциплины, можно забыть |
Read-through | Все чтения идут через кэш-обёртку, которая сама обновляет кэш | Удобно и безопасно | Потенциально сложнее в реализации |
Критерий | In-Memory (MemoryCache / IMemoryCache) | Redis (StackExchange.Redis) |
---|---|---|
Масштабируемость | Только внутри одного инстанса | Распределённый: работает между всеми сервисами |
Объём кэша | Ограничен ОЗУ текущего процесса | Redis может использовать ГБ-памяти, LRU eviction |
Изоляция данных | Кэш изолирован, быстро | Redis — общий кэш, данные доступны всем |
Инвалидация по событию | Нужно синхронизировать вручную | Можно использовать Pub/Sub, списки, TTL |
Скорость доступа | Быстрее (из RAM, без сетевого запроса) | Быстрее, чем БД, но сетевой вызов |
Устойчивость | При падении сервиса кэш теряется | Redis можно настроить с репликами и сохранением |
В проде на Kubernetes | Только для узкоспециализированных задач | Лучший выбор для продакшена |
Когда использовать | - Одно-узловой сервис - Локальный кеш - Например, частые вычисления |
- Распределённые сервисы - Shared session - Rate limiting - Background worker sharing |
Аутентификация | Проверка кто ты — удостоверение личности (логин, токен, сертификат) |
Авторизация | Проверка что тебе разрешено — доступ к конкретным ресурсам или действиям |
Плюсы: просто, кроссплатформенно и не требует дополнительного сервиса
Минусы: Сложно масштабировать
Алгоритм такой:
Пользователь отправляет логин и пароль, сервис с использованием внутреннего секрета шифрует и закладывает в accessToken информацию о том когда он истекает и что это за пользователь, а также генерирует рефреш токен и сохранет его в бд. После возвращает оба токена пользователю.
OpenID предназначен для аутентификации — то есть для того, чтобы понять, что этот конкретный пользователь является тем, кем представляется. Например, с помощью OpenID некий сервис Ололо может понять, что зашедший туда пользователь, это именно Рома Новиков с Mail.Ru. При следующей аутентификации Ололо сможет его опять узнать и понять, что, это тот же Рома, что и в прошлый раз.
OAuth же является протоколом авторизации, то есть позволяет выдать права на действия, которые сам Ололо сможет производить в Mail.Ru от лица Ромы. При этом Рома после авторизации может вообще не участвовать в процессе выполнения действий, например, Ололо сможет самостоятельно заливать фотографии на Ромин аккаунт.