Хабрахабр

[Перевод] Как Dark развертывает код за 50 мс

Чем быстрее процесс разработки, тем быстрее развивается технологическая компания.

Развертывание в таких системах становится сложной задачей и требует сложных пайплайнов непрерывной поставки даже в маленьких командах. К сожалению, современные приложения работают против нас — наши системы должны обновляться в режиме реального времени и при этом никому не мешать и не приводить к простоям и перерывам.

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

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

Пятьдесят. В Dark на это уходит 50 мс. Dark — это комплексное решение с языком программирования, редактором и инфраструктурой, созданное специально для непрерывной поставки, и все аспекты Dark, включая сам язык, построены с видом на безопасное моментальное развертывание. Миллисекунд.

Почему конвейеры непрерывной поставки такие медленные?

Для разработчика, который каждый день занят этим проектом, развертывание одного незначительного изменения будет выглядеть примерно так: Допустим, есть у нас веб-приложение Python и мы уже создали замечательный и современный пайплайн непрерывной поставки.

Внесение изменений

  • Создание новой ветки в git
  • Внесение изменений за переключателем функции
  • Модульное тестирование для проверки изменений с переключателем функции и без

Пул-реквест

  • Коммит изменений
  • Отправка изменений в удаленный репозиторий на github
  • Пул-реквест
  • Сборка CI выполняется автоматически в фоновом режиме
  • Ревью кода
  • Еще несколько ревью, если нужно
  • Слияние изменений с мастером git.

CI выполняется на мастере

  • Установка фронтенд-зависимостей через npm
  • Сборка и оптимизация ресурсов HTML+CSS+JS
  • Прогон во фронтенде модульных и функциональных тестов
  • Установка зависимостей Python из PyPI
  • Прогон в бэкенде модульных и функциональных тестов
  • Тестирование интеграции на обоих концах
  • Отправка ресурсов фронтенда в CDN
  • Сборка контейнера для программы Python
  • Отправка контейнера в реестр
  • Обновление манифеста Kubernetes

Замена старого кода новым

  • Kubernetes запускает несколько экземпляров нового контейнера
  • Kubernetes ждет, чтобы экземпляры стали работоспособными
  • Kubernetes добавляет экземпляры в балансировщик нагрузки HTTP
  • Kubernetes ждет, пока старые экземпляры перестанут использоваться
  • Kubernetes останавливает старые экземпляры
  • Kubernetes повторяет эти операции, пока новые экземпляры не заменят все старые

Включение нового переключателя функции

  • Новый код включается только для себя, чтобы убедиться, что все нормально
  • Новый код включается для 10% пользователей, отслеживаются операционные и бизнес-метрики
  • Новый код включается для 50% пользователей, отслеживаются операционные и бизнес-метрики
  • Новый код включается для 100% пользователей, отслеживаются операционные и бизнес-метрики
  • Наконец, вы повторяете всю процедуру, чтобы удалить старый код и переключатель

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

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

У многих бывают дни, когда код невозможно развернуть, потому что в Dockerfile есть проблемы, в одном из десятков сервисов произошел сбой или нужный специалист в отпуске. А раз эти пайплайны почти всегда созданы для особого случая, на них сложно полагаться.

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

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

Реализация непрерывной поставки в Dark

Мы перебрали все шаги пайплайна, чтобы удалить все лишнее, а остальное довели до ума. Непрерывная поставка настолько важна для Dark, что мы с самого начала нацелились на время меньше секунды. Вот как мы удаляли шаги.

Джесси Фразель (Jessie Frazelle) придумала новое слово deployless (не требующий развертывания) на конференции Future of Software Development в Рейкьявике

Deployless означает, что любой код моментально развертывается и готов к употреблению в продакшене. Мы сразу решили, что Dark будет основан на концепции «deployless» (спасибо Джесси Фразель за неологизм). Конечно, мы не пропустим неисправный или неполный код (принципы безопасности я опишу ниже).

Странный вопрос. На демонстрации Dark нас часто спрашивали, как мы ухитрились так ускорить развертывание. Вряд ли это возможно. Люди, наверное, думают, что мы придумали какую-то супертехнологию, которая сравнивает код, компилирует его, упаковывает в контейнер, запускает виртуальную машину, на холодную запускает контейнер и все в таком духе, — и все это за 50 мс. Но мы создали специальный движок развертывания, которому все это и не нужно.

Допустим, вы пишете код в функции или обработчике HTTP или событий. Dark запускает интерпретаторы в облаке. Так что развертывание выглядит просто как скромная запись в базу данных — моментальная и элементарная. Мы отправляем diff в абстрактное синтаксическое дерево (реализацию кода, которую внутренне использует наш редактор и серверы) на наши серверы, а затем запускаем этот код, когда поступают запросы. Развертывание происходит так быстро, потому что включает самый минимум.

Моментальное развертывание, конечно, никуда не денется. В будущем мы планируем сделать из Dark компилятор инфраструктуры, который будет создавать и запускать идеальную инфраструктуру для высокой производительности и надежности приложений.

Безопасное развертывание

Структурированный редактор

Структурированный редактор не допускает синтаксических ошибок. Код в Dark пишется в редакторе Dark. Пока вы вводите текст, мы напрямую работаем с абстрактным синтаксическим деревом (AST), как Paredit, Sketch-n-Sketch, Tofu, Prune и MPS. По сути, в Dark даже анализатора нет.

Например, если вы меняете вызов функции, мы храним старую функцию, пока новая не станет пригодной. У любого незавершенного кода в Dark есть допустимая семантика выполнения, примерно как typed holes в Hazel.

У каждой программы в Dark есть свой смысл, поэтому незавершенный код не мешает завершенному работать.

Режимы редактирования

Первый: вы пишете новый код и являетесь единственным пользователем. Вы пишете код в Dark в двух случаях. Тут можно работать без всяких мер предосторожности, и сейчас вы примерно так и работаете в среде разработки. Например, он в REPL, и другие пользователи никогда не получат к нему доступ, или это новый маршрут HTTP, на который вы нигде не ссылаетесь.

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

Переключатели функций

Переключатели функций выполняют много разных задач: замена локальной среды разработки, ветки git, развертывание кода и, конечно, традиционный медленный и контролируемый выпуск нового кода. Один из способов убрать лишнюю сложность в Dark — устранить несколько проблем одним решением.

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

Переключатели функций встроены в язык Dark, и даже незавершенные переключатели выполняют свою задачу — если условие в переключателе не выполнено, будет выполняться старый заблокированный код.

Среда разработки

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

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

Ветки и развертывания

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

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

Мы сгладили многие недостатки git. Git сложно использовать, особенно новичкам, и это здорово его ограничивает, но зато у него есть удобные ветки. Dark редактируется в реальном времени и обеспечивает возможность совместной работы в стиле Google Документов, чтобы не приходилось отправлять код и можно было реже выполнять перебазирование и слияние.

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

Версионирование

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

О нашей системе типов мы подробно рассказывали в предыдущем посте. По этим же причинам мы версионируем типы.

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

Это гораздо безопаснее, чем полное развертывание всего сразу, как это происходит сейчас.

Новые версии пакетов и стандартная библиотека

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

Dict::get_v0 возвращал тип Any (от которого мы отказываемся), а Dict::get_v1 возвращает тип Option.
Скриншот части автоматического процесса в Dark, показывающий две версии функции Dict::get.

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

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

Новые версии Dark

Раз мы создаем Dark для непрерывной поставки, нужно учитывать эти изменения языка. Переход с Python 2 на Python 3 растянулся на десятилетие и до сих пор остается проблемой.

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

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

Миграции баз данных

Для безопасной миграции базы данных существует стандартная формула:

  • Переписать код для поддержки нового и старого форматов
  • Преобразовать все данные в новый формат
  • Удалить старый доступ к данным

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

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

Например, хранилище данных Users изначально будет называться Users-v0. Доступ к хранилищам данных в Dark осуществляется через версионированные имена переменных. Если данные сохранены через Users-v0, а вы обращаетесь к ним через Users-v1, применяется функция наката. Когда создается новая версия с другим типом, имя меняется на Users-v1. Если данные сохранены через Users-v1, а вы обращаетесь к ним через Users-v0, применяется функция отката.


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

Это можно делать по одному обработчику HTTP за раз, чтобы снизить риски, а еще переключатели работают для отдельных пользователей, чтобы вы могли проверить, что все работает, как ожидалось. Используйте переключатели функций, чтобы направить вызовы к Users-v0 в версию Users-v1. Вы этого даже не заметите. Когда пользователей Users-v0 не останется, Dark преобразует все оставшиеся данные в фоновом режиме из старого формата в новый.

Тестирование

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

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

От чего мы избавились

Нам не нужны ветки git или пул-реквесты, сборка бэкенд-ресурсов и контейнеров, отправка ресурсов и контейнеров в реестры или шаги развертывания в Kubernetes. Раз у нас нет развертывания, но есть переключатели функций, около 60% пайплайна развертывания остается за бортом.

В Dark поставка состоит из 6 шагов и одного цикла, а традиционная версия включает 35 шагов и 3 цикла.
Сравнение стандартного пайплайна непрерывной поставки (слева) и непрерывная поставка Dark (справа).

В Dark тесты запускаются автоматически, и вы этого даже не видите; зависимости устанавливаются автоматически; все, что связано с git или Github, больше не нужно; собирать, тестировать и отправлять контейнеры Docker не нужно; развертывание в Kubernetes больше не нужно. В Dark в развертывании всего 6 шагов и 1 цикл (шаги, которые повторяются несколько раз), в то время как современный пайплайн непрерывной поставки состоит из 35 шагов и 3 циклов.

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

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

Я отвечаю на вопросы об этом на HackerNews.

Если едете на StrangeLoop в сентябре, приходите к нам на запуск. Чтобы узнать больше об устройстве Dark, прочтите статью о Dark, подпишитесь на нас в Twitter (или на меня) или запишитесь на бета-версию и получайте уведомления о следующих постах.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть