Это часть серии статей, посвященных принципам сетевой автоматизации.

Каждый инженер задается целью построить «правильную систему» ​​с первого раза, но возможно ли это вообще? Вы вообще знаете свои требования? Вы действительно знаете свои требования? Нет, серьезно, вы действительно знаете, каковы ваши требования? Введите ЯГНИ и преждевременную оптимизацию.

ЯГНИ: «Вам это не понадобится» — это принцип экстремального программирования, который гласит, что программист не должен добавлять функциональные возможности до тех пор, пока он не будет сочтен необходимым, и «делать простейшие вещи, которые могут сработать». (DTSTTCPW) — Википедия

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

Книга «Искусство программирования» была написана в 60-х годах и актуальна до сих пор.

Теория информатики

Год назад у меня был дизайнерский разговор с коллегой, где он напомнил мне, что нотация Big-O не учитывает константы.

Нотация Big-O не заботится о константах, потому что нотация Big-O описывает только долгосрочную скорость роста функций, а не их абсолютные величины.

Это хорошее правило, которое следует учитывать при предоставлении двух почти одинаково взвешенных вариантов, таких как сравнение поиска по хешу / словарю и поиска по списку, который сравнивает O (1) и O (n), и оба они хорошо понятны / легко выполняются. Однако введение оптимизаций, таких как многопоточность или многопроцессорность, до того, как вам понадобится, по сути, затрудняет поддержку кода. Это значительно увеличивает возможности проектирования, вероятность возникновения условий гонки и возможность устранения неполадок.

Понятно, почему константы не имеют значения в нотации Big-O, но в практическом применении это определенно имеет значение. Возьмите временную сложность Big-O с наихудшей скоростью O (n!) (O-факториал), где вы никогда не сможете достичь числа выше «2» в качестве значения «N». Кроме того, оптимизация процесса, который занимает всего 0,1% вашего реального времени, мало что дает. Однако трудно увидеть, где будет происходить оптимизация, пока вы не доберетесь до нее. Наконец, оптимизация вашего процесса может не привести к дополнительной экономии, например, когда фактическая неправильная оптимизация процесса ожидает одобрения со стороны человека.

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

Мое личное путешествие

Ошибки — я совершил несколько ошибок и, вероятно, буду делать еще несколько. Я попал в кроличью нору, слишком рано вводя нефункциональные требования (такие как аутентификация и ведение журнала), добавляя функции до того, как они понадобятся, и делая программное обеспечение «фреймворком». Я был счастлив, что смог использовать код оптимизации, но ни разу не увидел, что программа покидает фазу проверки концепции. Другими словами, я потратил много времени на код, который не использовался каким-либо значимым образом из-за добровольных требований и оптимизаций.

Пример использования сетевой автоматизации

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

  • Небольшие инкрементальные изменения, подключаемые к 1-5 устройствам за раз в течение окна изменений.
  • Ежедневные задачи, такие как резервное копирование конфигураций, соответствие конфигурации и сбор рабочих данных, не зависящие от времени.
  • Редкие глобальные изменения, такие как обновление списков контроля доступа SNMP или обновление IP-адресов сервера NTP.

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

Пример из реальной жизни

Я работал с клиентом над ежедневным процессом резервного копирования и обеспечения соответствия конфигурации для 8000+ устройств. Некоторые участники сообщества явно задокументировали, что Ansible работает медленнее, чем, скажем, Nornir 2. Однако места, где оптимизация принесла наибольшую пользу, не были, вероятно, теми местами, которые вы ожидали, и решения также были неочевидными.

Требования

Требования, относящиеся к этому сообщению в блоге, включают:

  • Выполните все задания менее чем за 24 часа, в том числе:
    • Резервное копирование конфигураций сетевых устройств.
    • Предполагаемая генерация конфигурации, интеграция с внешним Источником Истины (SoT).
    • Сравнение соответствия конфигурации по функциям (BGP, NTP, SNMP и т. Д.) На каждом устройстве.
    • Сверните отчеты о вышеперечисленном.
  • Возможность запускать задания для отдельных устройств

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

Многопоточность

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

Широкое масштабирование

Хотя были очевидные проблемы со слишком широким масштабированием и слишком быстрым, это не значит, что мы не могли использовать масштабирование более широко. Использование ресурсов, связанное с управлением большим количеством устройств в Ansible, замедляло процесс. Причины неэффективности менее важны, поскольку решение было довольно простым. Решения включают создание нескольких рабочих процессов в Ansible AWX / Tower и распределение нагрузки по типам ОС для устройств NXOS и EOS и по регионам для устройств IOS. Эту оптимизацию было относительно легко произвести, и она практически не повлекла за собой изменений конструкции.

Генерация конфигурации

Мы заметили, что создание конфигурации занимает много времени. У нас было две основные гипотезы, почему:

  • Неэффективность в том, как Ansible использует Jinja.
  • Неэффективность в том, как Ansible идемпотентно проверяет изменения конфигурации файлов.

Заменить Jinja было бы сложно, однако, поменять способ реализации идемпотентности — простое изменение. Нам просто нужно было заменить модуль шаблона Ansible для поиска по шаблону Ansible и сохранить файл с настраиваемым фильтром.

Исходное задание:

- name: "GENERATE FILES FROM JINJA TEMPLATES"
  template:
    src: "{{ src_file }}"
    dest: "{{ dst_file }}"

Новое задание:

- name: "GENERATE FILES FROM JINJA TEMPLATES"
  set_fact:
    save_to_file: "{{ lookup('template', src_file) | save_output_to_file(dst_file) }}"

Плагин фильтра:

def save_output_to_file(content, destination):
    """Save content to file."""
    with open(destination, "w") as fh:
        fh.write(content)
    return destination

class FilterModule(object):
    """Ansible filter class."""

    def filters(self):
        """List of filters."""
        return {
            "save_output_to_file": save_output_to_file,
        }

Оказывается, мы увеличили эффективность в 7 раз при этом изменении и уменьшили примерно с 5 часов обработки до примерно 40 минут. Более того, мы ничего не добились от идемпотентности в этом варианте использования, поскольку намеревались отслеживать через GitHub. На сотнях устройств знание того, изменилась ли задача, не помогло в долгосрочной перспективе, но было полезно при использовании контроля версий.

Уроки выучены

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

Но мой вариант использования уникален!

Большой!! Затем сделайте это, введите правильную степень сложности, необходимую для решения вашей проблемы. Эти принципы не меняют этого, они просто заставляют каждого инженера по-настоящему рассмотреть варианты. По любой причине, чтобы не вводить функцию, будут причины для ее внедрения, некоторые даже могут сказать: «Это зависит».

Личный опыт говорит о том, что, к большому разочарованию автоматизатора, сетевые инженеры стараются изо всех сил объединяться в стандартных конфигурациях и проектах сетевых устройств. Инженеры по автоматизации борются за объединение наборов решений и инструментов по схожим причинам. Иначе говоря, «сетевые снежинки» — Плохо, «снежинки автоматизации» оправданы. Имея это в виду, я бы призвал автоматизаторов не внедрять новые инструменты, технологии или сложности.

Заключение

В конце концов, это сложная тема без однозначного ответа. Для каждого примера, который у меня есть, когда я хотел бы не потратить время на создание чего-либо, у меня есть другой пример, в котором я хотел бы «сделать это правильно с первого раза». Учитывая, что целевая аудитория — это те, кто создает решения для автоматизации сетей в корпоративном пространстве, важно учитывать контекст.

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