Разработка устойчивых приложений без сервера с шаблонами прерывателя схемы

Введение: вызов устойчивости в бессерверных вычислениях

Бессерверные вычисления изменили то, как разработчики создают и развертывают приложения, абстрагируя управление инфраструктурой и предлагая автоматическое масштабирование. Платформы, такие как AWS Lambda, Azure Functions и Google Cloud Functions, позволяют командам сосредоточиться на бизнес-логике, платя только за фактическое использование. Однако эта модель вводит уникальные проблемы устойчивости. Функции являются безгосударственными, эфемерными и часто общаются между распределенными службами - одна неисправная зависимость может вызвать каскад тайм-аутов, повторных запросов и выпадов затрат. Холодные запуски, дросселирование и переходные сетевые сбои являются общими. Для поддержания надежности, не жертвуя преимуществами безсерверных, разработчики должны принять проверенные шаблоны для отказоустойчивости. Один из самых эффективных - шаблон прерывателя схемы.

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

Понимание шаблона разрушителя цепи в глубине

Модель выключателя схемы была популяризирована Майклом Найгардом в его книге Выпустить его! и позже формализована в облачных шаблонах. Она ведет себя как электрический выключатель: когда схема обнаруживает неисправность (например, короткая), она открывает и останавливает поток тока. В программном обеспечении состояния цепи:

Без этого кратковременное отключение может привести к тому, что все клиенты будут перезапускать одновременно, создавая громоотводное стадо, которое расширяет отключение. Модель Circuit Breaker также обеспечивает раннюю обратную связь с отказом клиентам, что позволяет изящно ухудшать работу - например, возвращать кэшированные данные или дружественное сообщение об ошибке вместо тайм-аута.

Основополагающая статья Мартина Фаулера о разрушителе цепи остается основополагающей ссылкой. Он объясняет, как шаблон интегрируется с другими моделями устойчивости, такими как Retry и Bulkhead.

Ключевые параметры для настройки

Каждая реализация выключателя выдает настраиваемые параметры, которые должны быть скорректированы в соответствии с поведением вашего приложения:

Безсерверные приложения добавляют сложности: поскольку функции эфемерны, вы не можете полагаться на состояние в памяти для схемы. Если экземпляр Lambda выходит из строя, состояние цепи может быть потеряно. Таким образом, часто необходимо внешнее хранилище состояния (DynamoDB, Redis или управляемая служба).

Внедрение прерывателей цепи в безсерверных средах

Внедрение выключателя в архитектуре без сервера требует адаптации шаблона к ограничениям платформы. Мы рассмотрим три основных подхода: использование управляемых функций API, использование сторонних библиотек в вашем функциональном коде и использование служб оркестровки, таких как AWS Step Functions.

Подход 1: API Gateway-Level Throttling и Circuit Breaking

AWS API Gateway может выступать в качестве рудиментарного выключателя, препятствуя запросам на бэкэнд-функцию Lambda. Когда функция возвращает слишком много ошибок 5xx или превышает ограничения параллелизма, API Gateway может быть сконфигурирован для возврата обратного ответа (например, статического сообщения от пользовательского авторизатора или ответа интеграции). Однако это не настоящий государственный выключатель - он полагается на ограничение скорости, а не на мониторинг частоты отказов. Для простых сценариев этого может быть достаточно.

Пример: Установите план использования API Gateway с пределом лопастей и лимитом скорости, который отражает емкость вашего бэкэнда. Когда функция Lambda перегружена, API Gateway немедленно реагирует с , действуя как односторонний выключатель. Но это не различает дросселирование и фактические сбои в обслуживании.

Подход 2: Внеклассные разбивки по схемам с библиотеками

Наиболее гибкий подход заключается в встраивании библиотеки выключателей в ваши функции Lambda. Поскольку функции Lambda не имеют состояния и горизонтально масштабируются, состояние выключателя должно храниться внешне, чтобы каждое вызов могло проверить текущее состояние. Общий шаблон использует Amazon DynamoDB (или Redis с ElastiCache), чтобы сохранить состояние цепи через вызовы функций.

Для Node.js библиотека Opossum является широко используемым выключателем. Она поддерживает функции резервного копирования, тайм-аута и порога громкости. Вот упрощенная реализация, адаптированная для AWS Lambda:

const CircuitBreaker = require('opossum');
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();

const circuitBreakerState = {
 state: 'CLOSED',
 failureCount: 0,
 lastFailureTime: null
};

// Persist state in DynamoDB after each transition
async function persistState(newState) {
 await dynamo.put({
 TableName: 'CircuitBreakerState',
 Item: { serviceId: 'payment-service', ...newState }
 }).promise();
}

async function loadState() {
 const data = await dynamo.get({
 TableName: 'CircuitBreakerState',
 Key: { serviceId: 'payment-service' }
 }).promise();
 return data.Item || circuitBreakerState;
}

// The actual downstream call
async function callPaymentService(payload) {
 const http = require('axios');
 const response = await http.post('https://payment.example.com/charge', payload);
 return response.data;
}

// Circuit breaker options
const options = {
 errorThresholdPercentage: 50,
 resetTimeout: 30000,
 volumeThreshold: 10
};

// Create breaker with external state integration (simplified)
const breaker = new CircuitBreaker(callPaymentService, options);

breaker.fallback(() => ({ error: 'Payment service unavailable, order processed in offline mode' }));

exports.handler = async (event) => {
 // Load state from DynamoDB and update breaker
 const savedState = await loadState();
 // Opossum doesn't natively restore state; you'd need to implement a wrapper.
 // For brevity, assume the breaker is fresh per function invocation but uses external checks.

 // In production, use a shared cache with TTL instead of per-invocation state load.
 return breaker.fire(event.body);
};

Этот пример не полностью интегрирован для ясности. На практике вам нужно будет синхронизировать состояние выключателя во многих одновременных вызовах функций с использованием условных записей в DynamoDB (оптимистическая блокировка), чтобы избежать условий гонки. Для сценариев с высокой пропускной способностью экземпляр Redis (например, с использованием ElastiCache Serverless) часто более эффективен.

Подход 3: Функции шагов AWS - разбивка цепи на уровне оркестровки

Для многоступенчатых рабочих процессов (например, проверка электронной коммерции) AWS Step Functions может моделировать выключатель схемы как машину состояния. Состояние может проверять счетчик или флаг, хранящийся в таблице DynamoDB. Если количество отказов превышает порог, рабочий процесс перенаправляет на обратный путь (например, на электронную почту администратора, очередь для ручной обработки). Это обеспечивает выключатель более высокого уровня, который охватывает несколько вызовов службы.

Пример: Функция шага, которая вызывает две службы нисходящего потока. После сбоя она увеличивает счетчик DynamoDB. Перед каждым последующим вызовом Функция шага читает счетчик. Если он превышает 5, рабочий процесс сразу же принимает обратный путь. Это фактически выключатель на уровне рабочего процесса.

Бессерверные задачи и решения

Преимущества использования Circuit Breakers

Преимущества выходят далеко за рамки основ. Давайте рассмотрим каждое преимущество в безсерверном контексте:

Улучшенная устойчивость – предотвращение каскадных сбоев

Безсерверные цепи хрупки. Если служба А вызывает В, а В вызывает С, и С выходит из строя, сбой распространяется. Выключатель на вызове В к С заставит В открыть свою цепь после нескольких сбоев. Теперь запросы от А к В сразу же отклоняются с запасом, не позволяя В исчерпать свой предел параллелизма и стать узким местом. Это изолирует ошибку от ее происхождения.

Быстрое восстановление – самоисцеление без вмешательства

Когда цепь открыта, неисправная служба получает период отдыха. Никаких запросов не отправляется, что позволяет ей восстановиться (например, перезапустить, очистить утечку памяти или перенастроить). Полуоткрытое состояние периодически проверяет службу. Как только она успешно реагирует, цепь закрывается автоматически. Это самоисцеление жизненно важно для бессерверных, где отладка живых функций затруднена.

Улучшенный пользовательский опыт — благодатная деградация

Вместо того, чтобы показывать общую страницу «Ошибка сервера» или вращающийся загрузчик, вы можете вернуть устаревшие данные, упрощенную версию функции или дружественное сообщение. Например, служба рекомендаций продукта может использовать выключатель: при открытии страница продукта показывает «Рекомендации временно недоступны», а не полностью выходит из строя.

Экономия средств – избегание ненужных вызовов

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

Лучшие практики для развертывания разрушителей цепи

Внедрение выключателя не является универсальной деятельностью. Используйте эти методы для максимизации эффективности в среде без сервера.

Установите соответствующие пороги отказа и тайм-ауты

Например, если ваша служба нисходящего потока нацелена на 99,9% времени безотказной работы, порог 5 сбоев в минуту может быть слишком чувствительным (он может открываться во время незначительных всплесков). Начните с более высокого порога (например, 20% частоты ошибок в течение 1-минутного окна) и настройте с использованием данных мониторинга. Тайм-ауты должны быть немного длиннее, чем обычное время отклика службы нисходящего потока, но короче, чем общее время ожидания вашей функции.

Реализация механизмов Fallback

Каждый запрос с открытым замыканием должен иметь обратный эффект.

Откаты должны быть идемпотентными, где это возможно, особенно для записей.

Мониторинг и состояние лог-схемы

Приборы выключателя для регистрации каждого состояния изменения и метрики отказа. Используйте CloudWatch Metrics (например, пользовательские метрики для открытого счета схемы, полуоткрытые испытания, использование запасных частей). Установите тревогу: если цепь остается открытой в течение длительного периода, уведомите операции. Также регистрируйте причину отказа - тайм-аут, код ошибки и т. Д. - чтобы помочь отладке.

Совместите с другими моделями устойчивости

Испытайте свой выключатель на неудачу

Инженерия хаоса - ваш друг. Используйте такие инструменты, как AWS Fault Injection Simulator (FIS), чтобы вводить сбои в ваши службы нисходящего потока и наблюдать за поведением выключателя.

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

Используйте внешний государственный магазин с TTL

В бессерверной системе нельзя полагаться на локальную память при вызовах. Используйте DynamoDB, ElastiCache для Redis или сделанную службу, такую как Eureka. Установите Time-to-Live (TTL) в государственной записи, чтобы, если ваша функция неактивна в течение длительного периода, схема автоматически сбрасывалась на закрытую. Это предотвращает застойное открытое состояние от блокировки трафика после восстановления службы.

Заключение

Поскольку бессерверная система становится основой современных приложений, такие модели устойчивости, как Circuit Breaker, больше не являются обязательными — они необходимы для контроля затрат, времени безотказной работы и удовлетворенности пользователей.Понимая государственную машину, правильно реализуя ее в рамках ограничений вашей бессерверной платформы (API Gateway, функциональный код или функции шагов) и следуя лучшим практикам мониторинга и тестирования, вы можете создавать системы, которые изящно ухудшаются при сбое и восстанавливаются без ручного вмешательства.

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