Проектирование устойчивых систем: что должен знать каждый инженерный менеджер

Проектирование устойчивых систем: что должен знать каждый инженерный менеджер

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Автоматические выключатели: зная, когда перестать пытаться

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

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

  • Мониторинг частоты ошибок.

  • Временно останавливают вызовы, когда пороговые значения ошибки пересекаются.

  • Постепенно возобновите трафик после восстановления системы.

    Circuit breaker illustration

                                                                                         *Source: Martin Fowler*
    

3Переборки: содержащий урон

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

Лучшие практики:

  • Отдельные критические от некритических путей.

  • Предоставить выделенные ресурсы и изолировать сбои.

    Bulkhead illustration


Реальная история: незначительная ошибка с серьезным влиянием

Позвольте мне проиллюстрировать это с помощью реального сценария, с которым я столкнулся на 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, включал глубоко переплетенные услуги в нескольких пакетах и ​​командах. Я не могу раскрыть точную реализацию или проприетарные детали, но представленные здесь уроки достаточно общие, что многие будут распознавать и относиться к этим моделям и решениям.


Вы столкнулись с подобными проблемами устойчивости? Я хотел бы услышать ваши истории и решения!


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE