Я вернулся из отпуска, отдохнул и с новыми силами планирую дочитать "Микросервисы" Ричардсона. Параллельно (до отпуска) уже пару недель у меня был в работе небольшой пет-проект на go, в рамках которого удалось заюзать много интересных вещей, которые в ближайшее время начну описывать. Но главное - проект будет на микросервисах, где мы на практике попробуем концепции этой книги. А сейчас небольшой конспект главы 3.2.3 - "Работа в условиях частичного отказа с применением шаблона 'Предохранитель'".
Каждый раз, когда сервис в распределённой системе делает синхронный запрос к другому сервису - возникает риск частичного отказа. Поскольку сервис является отдельным процессом, он может не ответить вовремя на запрос клиента (сбой, тех. обслуживание, перегрузка).
Клиент блокируется в ожидании ответа, и появляется опасность блокировки всей системы по цепочке. Тут нам помогает шаблон "Предохранитель": RPI-прокси, который в случае достижения определённого лимита последовательных отказов начинает отклонять все вызовы, пока не истечет определённое время.
Разберём на примере: сервис Order перестаёт отвечать (этот сервис я выделял и описывал в постах выше): мобильный клиент делает REST-запрос к API-шлюзу, тот проксирует запрос к недоступному сервису Order. OrderServiceProxy (сервис, проксирующий запросы к микросервису Order) будет блокироваться до бесконечности в ожидании ответа, что плохо скажется на удобстве использования и, что ещё хуже, на потреблении ресурсов. Рано или поздно ресурсы закончатся, и весь API станет недоступен.
Чтобы частичный отказ не распространился по всему приложению, при проектировании сервисов нам нужно:
* Использовать RPI-прокси, наподобие OrderServiceProxy, чтобы справляться с недоступными сервисами
* Решить, как восстанавливаться после отказа удалённого сервиса.
Для начала рассмотрим, как написать надежный RPT-прокси.
Каждый раз, когда сервис вызывает другой сервис, он должен защитить себя следующими механизмами:
* Сетевое время ожидания (корректно выставить таймаут)
* Ограничение количества неудачных запросов от клиента к сервису
* Шаблон "Предохранитель": отслеживание количества успешных и битых запросов. Если часоста ошибок привысит некоторый порог, предохранитель размыкается, и все дальнейшие попытки на некоторое время сразу завершаются с некоторым ошибочным кодом. Если через некоторое время сервис успешно отвечает, предохранитель смыкается, и появляется возможность обработать все битые запросы, которые можно хранить в какой-либо очереди, и корректно обрабатывать новые.
Восстановление после отказа
Самый простой способ - вернуть ошибку клиенту, если такой подход имеет место быть и данные, не полученные от сервиса, не критичны.
В ином случае можно вернуть резервное значение (например, значение по умолчанию), либо закэшированный ранее ответ.
Post #204
1.23K
- 👍 1