Что такое автоматические выключатели?

Шаблон проектирования программного обеспечения, используемый для определения доступности восходящей службы (API, базы данных и т. д.).

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

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

Зачем вам нужны автоматические выключатели?

Автоматические выключатели особенно важны, когда многие службы зависят друг от друга. Если одна служба выйдет из строя, вся архитектура может выйти из строя.

Как они работают?

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

Прокси может быть построен со следующими состояниями, такими как функциональность автоматического выключателя.

CLOSED — Ресурс еще не опробован или опробован и доступен.

OPEN — ресурс был опробован, но был недоступен.

HALF-OPEN — повторная попытка ожидания ресурса с пороговым значением.

Когда использовать этот шаблон

  1. Когда маршрут приложения пытается вызвать сторонний маршрут
  2. В случае сбоя маршрута из-за проблемы со сторонним маршрутом используйте запасной вариант для отправки статического ответа в течение заданного интервала.
  3. Создание отказоустойчивого приложения, в котором сбой одного или нескольких сервисов не приводит к остановке всей программы.

Когда не следует использовать этот шаблон

  1. Не используйте в качестве замены для управления исключениями в маршруте приложения
  2. Не используйте для доступа к локальным частным ресурсам в приложении.

Реализация на бэкенде Express JS

Давайте возьмем простой микросервис node js и реализуем шаблон прерывателя цепи для маршрутов.

У нас есть три лучших модуля npm для работы с автоматическими выключателями.

  1. Моллиция
  2. Корелла
  3. Узел Опоссум

Лично я предпочитаю Mollitia, который прост и удобен в использовании, и из которого мы можем разрабатывать модули и создавать повторно используемую логику.

Давайте посмотрим, как мы можем включить автоматический выключатель с помощью модуля Mollitia в приведенном ниже примере.

Это приложение разделено на два раздела. Для автоматического выключателя была введена сторонняя служба для получения сведений о заказе из службы заказов
Во-первых, давайте настроим автоматический выключатель, как показано ниже, чтобы определить, когда он должен размыкаться и замыкаться.

const MollitiaPrometheus = require('@mollitia/prometheus')
const Mollitia = require('mollitia')
const { Circuit, Fallback, SlidingCountBreaker, BreakerState } = Mollitia
const config = {
  name: 'appCounter',
  slidingWindowSize: 6, // Failure Rate Calculation 
  minimumNumberOfCalls: 3, // 3 iterations are needed to start
  failureRateThreshold: 60, 
  slowCallDurationThreshold: 500, 
  slowCallRateThreshold: 50, 
  permittedNumberOfCallsInHalfOpenState: 2, 
  openStateDelay: 10000,
  halfOpenStateMaxDelay: 30000,
}
// Sliding counter
const slidingCountBreaker = new SlidingCountBreaker(config)
  
// Create fallback
 const fallback = new Fallback({
  callback(err) {
    // Every time the method rejects, You can filter here
    if (err) {
      return err.message
    }
  },
})
  
// Creates a circuit
const orderCircuit = new Circuit({
  name: 'Order Operations',
  options: {
    prometheus: {
      name: 'orderCircuit',
    },
    modules: [slidingCountBreaker, fallback],
  },
})

Чтобы узнать о дополнительных параметрах конфигурации, проверьте подробности здесь

Давайте заменим вызов контроллера маршрута схемой, которая будет принимать параметры функции и позволит нам вызывать стороннюю или удаленную службу. В приведенном ниже фрагменте кода orderController.getOrders(req.query.category) — это функция, которая обрабатывает операцию для удаленных вызовов.

Чтобы получить текущее состояние цепи, используйте переменную slidingCountBreaker, проверьте состояние и обработайте необходимое действие, которое должно быть возвращено.

app.get('/orders', (req, res) => {
  orderCircuit
    .fn(() => orderController.getOrders(req.query.category))
    .execute()
    .then((result) => {
      console.log('Circuit State -->', slidingCountBreaker.state)
      res.send(result)
    })
    .catch((error) => {
      console.log('Circuit State -->', slidingCountBreaker.state)
      if (slidingCountBreaker.state === BreakerState.CLOSED) {
        res.send({
          status: false,
          message: "Order service is down",
        })
      } else {
        // Fallback Order response
        
      }
    })
})

Код ниже вызывает службу заказа для получения данных; как видите, для этого мы использовали модуль httpRequest. Если ответ будет удовлетворительным, мы вернемся; в противном случае мы будем отвергать. После вызова отклонения поток поступает в блок захвата автоматического выключателя, где вызывается откат на основе конфигурации и состояния выключателя.

const orderController = {
  getOrders: (category) => {
    return new Promise((resolve, reject) => {
      httpRequest(
        {
          uri: `http://localhost:9191/orders?category=${category}`,
          method: 'GET',
        },
        (error, response, body) => {
          if (error) {
            reject(error)
          } else if (response) {
            if (response.statusCode === 200) {
              resolve(JSON.parse(body))
            } else {
              resolve(response.body)
            }
          }
        }
      )
    })
  },
}

Запускаем сервер и сервис заказов, также можно клонировать репозиторий кода отсюда. запуск запуска npmи заказы запуска npm

Теперь вызовите конечную точку http://localhost:3000/orders?category=electronics, которая была включена автоматическим выключателем; если поток успешен, приложение возвращает ответ, полученный от службы заказа.

Теперь остановите службу заказа. Итак, когда мы остановим idel case, служба должна быть отключена.

Ответ будет возвращен из резервного варианта после 3 раз, как указано в конфигурации схемы.

Вы также можете видеть, что цепь разомкнута и наполовину разомкнута. Это показывает, что поток проходит через автоматический выключатель

Давайте перезапустим службу заказов, снова запустив заказы npm. Теперь свернем к http://localhost:3000/orders?category=electronics. Цепь была закрыта, и нормальный поток возобновился.

Мы также можем генерировать метрические информационные панели из вышеуказанных состояний. Для этого добавьте в автоматический выключатель плагин mollitia-prometheus.

const MollitiaPrometheus = require('@mollitia/prometheus')
const Mollitia = require('mollitia')
const app = express()
const { Circuit, Fallback, SlidingCountBreaker, BreakerState } = Mollitia
app.use(express.json({ urlencoded: true }))
// PrometheusAddon
Mollitia.use(new MollitiaPrometheus.PrometheusAddon())

Чтобы получить статистику, создайте конечную точку, как показано ниже, и подключитесь к инструментам мониторинга.

app.get('/stats', (req, res) => res.send(MollitiaPrometheus.metrics()))

Вы получите ответ метрик, как показано ниже

Репозиторий кода:

https://github.com/ganny26/ Circuit-breaker-nodejs