Устойчивость к отказу

Moleculer имеет несколько встроенных механизмов, обеспечивающих отказоустойчивость. Они могут быть включены или отключены в настройках брокера.

Защита от зацикливания

Молекулер имеет встроенный механизм защиты от зацикливания. Это реализация на основе пороговых значений. Для проверки частоты неудачного запроса используется временное окно. При достижении порогового значения активирует механизм защиты от зацикливания.

What is the circuit breaker?

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

Подробнее о защите от зацикливания можной узнать на Martin Fowler blog или Microsoft Azure Docs.

Если вы включите его, то все сервисные вызовы будут защищены от зацикливания.

Включить можно в параметрах брокера

const broker = new ServiceBroker({
circuitBreaker: {
enabled: true,
threshold: 0.5,
minRequestCount: 20,
windowTime: 60, // в секундах
halfOpenTime: 5 * 1000, // в миллисекундах
check: err => err && err.code >= 500
}
});

Настройки

Название Тип По умолчанию Описание
enabled Boolean false Включить функцию
threshold Number 0.5 Значение порога. 0.5 означает, что 50% не могут быть доставлены для передачи.
minRequestCount Number 20 Минимальное количество запросов. Ниже этого значения, CB не передаётся.
windowTime Number 60 Количество секунд за окно времени.
halfOpenTime Number 10000 Количество миллисекунд для переключения с открытого на полуоткрытое состояние
check Function err && err.code >= 500 Функция для проверки неудачных запросов.

Если состояние защиты от зацикливания изменено, ServiceBroker отправит внутренние события.

Эти глобальные параметры также могут быть переопределены в определении действий.

// users.service.js
module.export = {
name: "users",
actions: {
create: {
circuitBreaker: {
// Все параметры CB могут быть переопределены параметров брокера.
threshold: 0.3,
windowTime: 30
},
handler(ctx) {}
}
}
};

Повтор

Для выполнения повторных попыток применяется решение на базе экспоненциального отката. It can recall failed requests with response MoleculerRetryableError.

Включить можно в параметрах брокера

const broker = new ServiceBroker({
retryPolicy: {
enabled: true,
retries: 5,
delay: 100,
maxDelay: 2000,
factor: 2,
check: err => err && !!err.retryable
}
});

Настройки

Название Тип Значение по умолчанию Описание
enabled Boolean false Включить функцию.
retries Number 5 Количество попыток.
delay Number 100 Первая задержка в миллисекундах.
maxDelay Number 2000 Максимальная задержка в миллисекундах.
factor Number 2 Отключение фактора задержки. 2 означает экспоненциальный алгоритм отключения.
check Function err && !!err.retryable Функция для проверки неудачных запросов.

Перезаписать значение повторов в опции вызова

broker.call("posts.find", {}, { retries: 3 });

Перезаписать значения политики ретраев в определении действий

// users.service.js
module.export = {
name: "users",
actions: {
find: {
retryPolicy: {
// Все настройки политики повторов могут быть перезаписаны значениями из настроек брокера.
retries: 3,
delay: 500
},
handler(ctx) {}
},
create: {
retryPolicy: {
// Отключить повторы для этого действия
enabled: false
},
handler(ctx) {}
}
}
};

Таймауты

На вызов сервиса можно установить таймаут. Он может быть установлен глобально в опциях брокера или при вызове параметров. Если тайм-аут определен и запрос превышен, брокер выбрасывает ошибку RequestTimeoutError.

Включить можно в параметрах брокера

const broker = new ServiceBroker({
requestTimeout: 5 * 1000 // в миллисекундах
});

Перезаписать значение тайм-аута в параметрах вызова

broker.call("posts.find", {}, { timeout: 3000 });

Распределённые таймауты

Moleculer uses distributed timeouts. В случае вложенных вызовов значение таймаута определяется с задержкой выполнения. Если значение таймаута меньше или равно 0, следующие вложенные вызовы будут пропущены (RequestSkippedError), потому что первый вызов уже был отклонен с ошибкой RequestTimeoutError.

Ограничение конкурентных запросов (Bulkhead)

Функция Bulkhead реализована в фреймворке Moleculer для управления обработкой конкуретных запросов.

Включить можно в параметрах брокера

const broker = new ServiceBroker({
bulkhead: {
enabled: true,
concurrency: 3,
maxQueueSize: 10,
}
});

Глобальные настройки

Название Тип Значение по умолчанию Описание
enabled Boolean false Включить функцию.
concurrency Number 3 Максимальное количество одновременных выполнений.
maxQueueSize Number 10 Максимальный размер очереди

Значение concurrency ограничивает количество одновременно выполняемых запросов. Если maxQueueSize больше, чем 0, брокер сохраняет дополнительные запросы в очереди, если все слоты заняты. If the queue size reaches the maxQueueSize limit, broker will throw QueueIsFull exception for every addition requests.

Настройки действий

Глобальные настройки могут быть переопределены в определении действий.

Перезаписать значения политики ретраев в определении действий

// users.service.js
module.export = {
name: "users",
actions: {
find: {
bulkhead: {
// отключить bulkhead для этого действия
enabled: false
},
handler(ctx) {}
},
create: {
bulkhead: {
// Увеличить количество конкуретных запросов для действия
concurrency: 10
},
handler(ctx) {}
}
}
};

Настройки событий

Обработчики событий также поддерживают функцию переполнения.

Пример

// my.service.js
module.exports = {
name: "my-service",
events: {
"user.created": {
bulkhead: {
enabled: true,
concurrency: 1
},
async handler(ctx) {
// Обработка.
}
}
}
}

Подстраховка

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

Установка ответа подстраховки в настройках вызова

const result = await broker.call("users.recommendation", { userID: 5 }, {
timeout: 500,
fallbackResponse(ctx, err) {
// Вернуть общий ответ из кэша
return broker.cacher.get("users.fallbackRecommendation:" + ctx.params.userID);
}
});

Установка подстраховки для действий

Ответ подстраховки также может быть определён в действии на стороне получателя.

Обратите внимание, что этот подстраховочный ответ будет использоваться только в том случае, если ошибка возникнет в обработчике действий. Если запрос вызывается с удаленного узла и запрос истекает на удаленном узле, подстраховочный ответ не используется. В этом случае используйте fallbackResponse в настройках вызова.

Подстраховка как функция

module.exports = {
name: "recommends",
actions: {
add: {
fallback: (ctx, err) => "Какой-то результат из кэша",
handler(ctx) {
// Обработка
}
}
}
};

Подстраховка как строковый литерал с названием метода

module.exports = {
name: "recommends",
actions: {
add: {
// Вызвать метод 'getCachedResult' в случае ошибки
fallback: "getCachedResult",
handler(ctx) {
// Обработка
}
}
},

methods: {
getCachedResult(ctx, err) {
return "Некоторый результат из кэша";
}
}
};