TGStat
TGStat
Qidiruv uchun matnni kiriting
Ilg‘or kanal qidiruvi
  • flag Uzbek
    Sayt tili
    flag Russian flag English flag Uzbek
  • Saytga kirish
  • Katalog
    Kanal va guruhlar katalogi Hududiy to‘plamlar Tematik to‘plamlar Платные каналы Kanallar qidiruvi
    Kanal/guruh qo‘shish
  • Reytinglar
    Kanallar reytingi Guruhlar reytingi Postlar reytingi
    Brendlar va shaxslar reytingi
  • Analitika
  • Postlarda qidiruv
  • Telegram'ni kuzatish
  • Targ‘ibot
    Yandex Business orqali reklama TGStat Agency orqali kanallarda reklama TGStat.ru saytida reklama
Женя Янченко

30 Sep, 09:42

Telegram'da ochish Ulashish Shikoyat qilish

Представьте ситуацию.

Дисклеймер: пример вымышленный, проблема реально встречающаяся 🐤

Вы разрабатываете сервис приема заказов order-service. В зависимости от состава заказа и истории покупателя вы можете предлагать разные виды оплаты: предоплату, частичную предоплату, постоплату. Логика анализа состава заказа реализована в order-service, а за информацией по покупателю он обращается в client-service другой команды.

Фронт вызывает:

POST /orders

{
"clientUid": "some-uuid",
"products": [{...}, {...}]
}

Ответ:

{
"orderUid": "some-uid",
"orderStatus": "WAITING_FOR_CONFIRMATION", //ожидает подтверждения
"paymentType": "ON_DELIVERY" //оплата при получении
}

На основании ответа фронт показывает страницу подтверждения заказа с типом оплаты.

Обычно client-service отвечал order-service за 500 мс. Но что-то пошло не так, и теперь он отвечает по 20 секунд
Таймаут между фронтом и order-service 30 секунд, сам order-service отрабатывает не более 500 мс, но часть запросов от фронта стала падать по таймауту.

Почему так происходит, ведь 20 cек client-service + 500 мс order-service < 30 сек таймаута?

Потому что эти 20,5 сек - это время выполнения запроса, только если он сразу получил все необходимые ресурсы, то есть "чистое" время выполнения. А при нагрузке запрос может сначала ждать свободный поток, соединение с БД или другой ограниченный ресурс и только потом начать свои 20 секунд ожидания client-service.

Допустим, код order-service работает так:

1️⃣открывается транзакция с БД
2️⃣сохраняются данные заказа
3️⃣вызывается по REST client-service
4️⃣после его ответа сохраняются еще данные в БД
5️⃣транзакция закрывается
6️⃣идет ответ фронту

Если приложение держит транзакцию, пока ждет ответ client-service, то все это время соединение с БД остается занятым, а размер пула соединений ограничен.

Например, в пуле 10 соединений.
Первые 10 запросов заняли все соединения и на 20 секунд ушли ждать client-service.

11-й запрос уже не может начать работу с БД и ждет свободное соединение.
Через ~20 секунд оно освобождается, 11-й запрос сохраняет заказ, но теперь ему предстоит еще 20 секунд ждать ответ client-service.

Итого около 40 секунд end-to-end: 20 сек ждал в очереди к БД + 20 сек ждал ответ от client-service.

Для фронта 11-й запрос упадет по таймауту, хотя сам client-service для каждого отдельного вызова отвечает за 20 секунд.


✅ Поэтому первым делом стоит проверить, не держим ли мы долгую транзакцию во время ожидания внешнего сервиса. И если вдруг держим, то позволяет ли бизнес-логика изменить границы транзакции так, чтобы вынести из нее внешний вызов.

У долгих транзакций есть и другие минусы. Когда в PostgreSQL мы делаем UPDATE строки, создается новая версия строки, а старая сразу не удаляется. Очисткой устаревших строк занимается фоновый процесс VACUUM. Он очищает версии, которые больше не нужны активным транзакциям. Долгоживущие транзакции могут мешать очистке старых версий строк, их накопление ведет к разрастанию таблиц и индексов и ухудшению производительности запросов.

А если долгих транзакций нет или БД вообще не используется, что тогда?

✅ Если погуглить, в таких ситуациях обычно предлагается использовать паттерн Circuit breaker: если внешний сервис деградировал, временно перестать отправлять в него новые запросы, чтобы не допустить каскадного отказа.

Это поможет сохранить доступность order-service, но возникает бизнес-вопрос: что делать с самим заказом, если без client-service мы не можем определить paymentType?

Варианты:

✅ Возвращать ошибку пользователю, но делать это быстро, не удерживая ресурсы десятки секунд

✅ Кэшировать ответы client-service - подойдет, если много заказов от одних и тех же клиентов, но надо уточнять, как инвалидировать кэш, как часто обновляется ответ по клиенту (может он исчерпает лимит на постоплату, а мы из-за кэша не заметим)

✅ Договориться с бизнесом, что при недоступности client-service paymentType определять только по локальной логике

🐼 И конечно разговаривать с командой client-service, почему сервис вместо 500 мс стал отвечать 20 секунд 😅

1.1k 0 12 5 38
Katalog
Kanal va guruhlar katalogi Kanallar to‘plamlari Kanallar qidiruvi Kanal/guruh qo‘shish
Reytinglar
Telegram-kanallar reytingi Telegram-guruhlar reytingi Postlar reytingi Brendlar va shaxslar reytingi
API
Statistika API'si Postlar qidiruvi API'si API Callback
Kanallarimiz
@TGStat @TGStat_Chat @telepulse @TGStatAPI
O‘qish
Академия TGStat Telegram tadqiqoti 2019 Telegram tadqiqoti 2021 Telegram tadqiqoti 2023
Kontaktlar
Справочный центр Qo‘llab-quvvatlash Email Vakansiyalar
Har xil narsalar
Foydalanuvchi shartnomasi Maxfiylik siyosati Ommaviy oferta
Botlarimiz
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot