
Проектирование устойчивых систем: что должен знать каждый инженерный менеджер
6 июня 2025 г.Если вы когда -либо запускали основную функцию, только чтобы посмотреть, как она впечатляюще ломается под давлением, вы точно знаете, почему устойчивость имеет значение. Как менеджер по разработке программного обеспечения (SDM) в Amazon, я был на переднем крае создания систем, которые изящно обрабатывают реальные хаосы.
Давайте поговорим о устойчивости - фокусировавшись на критических архитектурных закономерностях на простом языке:Повторные переписки, автоматические выключатели и переборкиПолем
Образцы устойчивости объяснены
1Повторите логику: дайте вашему коду второй шанс
Подумайте о логике повторения как о попытке снова позвонить своему другу, если они не отвечают в первый раз. Это простой, мощный способ обработки временных сбоев - например, переходных сетевых икот или кратких отключений.
Ключевые моменты:
- Экспоненциальный откат:Увеличьте время ожидания между поисками, чтобы избежать перегрузки услуг.
- Ограничение повторения:Завершите свои попытки повторения (обычно 3–5 попыток).
- Idempotency:Убедитесь, что операции могут безопасно повторно повторить без побочных эффектов.
Иллюстративный пример Java:(Отказ от ответственности: этот упрощенный фрагмент иллюстрирует общую концепцию. Реализации реального мира значительно более сложны.)
public DeliveryPromise fetchDeliveryPromiseWithRetry(Cart cart, Address address) {
int maxRetries = 3;
int waitTimeMs = 1000;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
DeliveryPromise promise = deliveryService.getPromise(cart, address);
if (promise.isValid()) {
return promise;
}
Thread.sleep(waitTimeMs);
waitTimeMs *= 2; // Exponential backoff
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
// Graceful fallback
return DeliveryPromise.unavailable("Cannot deliver to selected address.");
}
2Автоматические выключатели: зная, когда перестать пытаться
Пропагандиры, не позволяющие системам неоднократно пытаться - и терпеть неудачу - чтобы вызвать не отвечающие услугам, так же, как электрические выключатели в вашем доме, которые защищают от перегрузки.
Как они работают:
Мониторинг частоты ошибок.
Временно останавливают вызовы, когда пороговые значения ошибки пересекаются.
Постепенно возобновите трафик после восстановления системы.
*Source: Martin Fowler*
3Переборки: содержащий урон
Наборные переборки разделяют критические части системы. Если один сервис вылетает, переборки ограничивают воздействие - поддерживая всю вашу систему на плаву.
Лучшие практики:
Отдельные критические от некритических путей.
Предоставить выделенные ресурсы и изолировать сбои.
Реальная история: незначительная ошибка с серьезным влиянием
Позвольте мне проиллюстрировать это с помощью реального сценария, с которым я столкнулся на Amazon. (Примечание. Ниже приведен преднамеренно упрощенный и обобщенный пример. Наш фактический сценарий включал сложные взаимодействия между несколькими службами и командами.)
Проблема:
Неизвестный, устаревший путь кода вновь появился после обычной миграции платформы. Клиенты, просматривающие адрес доставки по умолчанию, иногда попадают в редкий, но катастрофический сценарий:
- Клиент выбирает продукты на основе обещаний, рассчитанных по их адресу по умолчанию.
- При оформлении заказа они переключаются на другой адрес доставки.
- Обещание доставки больше не является действительным для недавно выбранного адреса.
- Вместо изящного обращения с этим краем наша система превратилась в ненужные повторения - в результате загадочного сообщения об ошибке.
Представьте, что вы покупаете подарок на день рождения своего друга. Вы доверяете обещанию, действуете уверенно, но в последний момент вы попали в запутанную, зацикленную ошибку. Даже если только 1% покупателей испытывают это, совокупное воздействие, особенно по шкале тысяч ежедневных порядков, огромно. Этот, казалось бы, небольшой контроль стоил потенциальных продаж и нанесения вреда клиентам.
Технический виновник: неправильная логика повторения (иллюстрация)
Пример неверного кода Java (высокопрофессиональный):
int retries = 5;
while (retries-- > 0) {
DeliveryPromise promise = legacyService.getPromise(cart, address);
if (promise.isValid()) return promise;
// No backoff, no break, repetitive calls
}
// Cryptic error message after long delay
throw new DeliveryException("Delivery unavailable");
Этот цикл неоднократно пытался бы сделать тот же призыв без значимых задержек или изящных выходов, вызывая длительную путаницу.
Быстрое разрешение: изящные запасы и автоматические выключатели
Мы быстро исправили эту проблему, введя правильную логику повторения и изящные запасные отступления, поддерживаемые выключателями цепи:
Обновленный пример Java (упрощен для иллюстрации):
public DeliveryPromise safeFetchPromise(Cart cart, Address address) {
int retries = 3;
int waitMs = 500;
while (retries-- > 0) {
DeliveryPromise promise = deliveryService.getPromise(cart, address);
if (promise.isValid()) return promise;
try {
Thread.sleep(waitMs);
waitMs *= 2; // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
}
// Immediate and clear user feedback
return DeliveryPromise.unavailable("Sorry, this item can't be delivered to the selected address.");
}
Интеграция выключателя цепи (концептуальный пример):
Выключатели схемы помогли мгновенно обнаружить сбои вниз по течению услуг и уменьшить потраченные впустую повторения:
if (circuitBreaker.isOpen()) {
return DeliveryPromise.unavailable("Delivery estimates temporarily unavailable.");
}
Основные архитектурные шаблоны суммировали:
- Понимает:Простой способ справиться с временными сбоями; Используйте с осторожностью и надлежащей конфигурацией.
- Выключатели цепи:Неудачный механизм, предотвращая каскадные неудачи.
- Переборки:Расположите вашу архитектуру, чтобы ограничить сбое.
Ключевые выводы для каждого SDM:
- Ожидайте неудачи:Это неизбежно; Построить устойчивость в.
- Разумно реализовать повторения:Полезно, но избегайте подавляющей свои системы.
- Реализуйте выключатели с цепи рано:Основное в распределенных системах для поддержания стабильности.
- Дизайн с переборками:Предотвратить общий сбой системы путем изоляции критических услуг.
- Всегда расставляйте приоритеты в пользовательском опыте:Ясно информируйте пользователей о системных проблемах и сбоях.
Вывод: устойчивость - это больше, чем просто хороший дизайн
Строительство устойчивых систем означает активную защиту опыта ваших клиентов и здравомыслия вашей команды. Устойчивость - это не просто техническое - это сочувствующее лидерство, критическое предвидение и практическое управление рисками.
Отказ от ответственности по иллюстративным примерам:
Все примеры кода, приведенные здесь, значительно упрощены для иллюстративных целей. Фактический сценарий, столкнутый в Amazon, включал глубоко переплетенные услуги в нескольких пакетах и командах. Я не могу раскрыть точную реализацию или проприетарные детали, но представленные здесь уроки достаточно общие, что многие будут распознавать и относиться к этим моделям и решениям.
Вы столкнулись с подобными проблемами устойчивости? Я хотел бы услышать ваши истории и решения!
Оригинал