Несколько лет назад Microsoft приняла решение начать долгий процесс по восстановлению системы разработки во всей компании. Мы большая компания, с множеством коллективов — у каждого собственные продукты, приоритеты, процессы и инструменты. Есть некоторые «общие» инструменты, но их много разных — и ОЧЕНЬ БОЛЬШОЕ количество разработанных внутри компании инструментов одноразового использования (под коллективами я имею в виду подразделения — тысячи инженеров).
У этого есть отрицательные стороны:
- Множество избыточных инвестиций в коллективы, которые разрабатывают похожие инструменты.
- Невозможность финансировать какой-либо инструментарий до «критической массы».
- Затруднения для сотрудников в перемещении по компании из-за разных инструментов и процесса.
- Сложность в обмене кодом между организациями.
- Разногласия с новичками в начале работы из-за чрезмерного изобилия инструментов «только для MS».
- И так далее...
Мы выступили с инициативой, которую называем «Одна Инженерная Система» (One Engineering System) или сокращённо 1ES. Как раз вчера у нас был день 1ES, где тысячи инженеров собрались, чтобы отметить достигнутый прогресс, узнать о текущем состоянии дел и обсудить планы. Это было на удивление хорошее мероприятие.
Отступим немного от темы… Вы можете задать вопрос — эй, ты же годами говорил нам, что Microsoft использует Team Foundation Server, ты что нам врал? Нет, я не врал. Более 50 тыс. человек регулярно используют TFS, но они необязательно применяют его для всей своей работы. Некоторые применяют для всего. Некоторые только для отслеживания рабочих тем. Некоторые только для контроля версий. Некоторые для сборок… У нас есть внутренние версии (и во многих случаях больше, чем одна) практически всего, что делает TFS, и кто-то где-то использует их все. Здесь есть немного хаоса, абсолютно честно. Но если объединить и взвесить, то можно с уверенностью сказать, что у TFS больше пользователей, чем у любого другого набора инструментов.
Я также хочу заметить, что говоря «инженерная система», я использую термин ОЧЕНЬ широко. Он включается в себя, но не ограничен следующим:
- Управление исходным кодом
- Рабочий менеджмент
- Сборка
- Релизы
- Тестирование
- Управление пакетами
- Телеметрия
- Управление происшествиями
- Локализация
- Сканирование безопасности
- Доступность
- Управление соблюдением правовых норм
- Подпись кода
- Статический анализ
- и многое, многое другое
Итак, вернёмся к истории. Когда мы встали на этот путь, то было несколько ожесточённых дебатов о том, куда мы идём, что должно быть главным и т. д. Вы же знаете, у разработчиков никогда нет мнения. :) Не было никакого способа решить всё сразу, не потерпев неудачу, поэтому мы согласились начать с трёх проблем:
- Планирование работы
- Контроль исходного кода
- Сборка
Не хочу подробно вдаваться в причины, кроме того, что это фундаментальные основы, а многое другое интегрируется с ними, строится на них, так что имеет смысл выбрать для начала именно три эти проблемы. Замечу также, что у нас были ОГРОМНЫЕ неприятности с временем сборки и надёжностью из-за размера наших продуктов — некоторые программы состоят из сотен миллионов строк кода.
Со временем эти три главные темы разрослись, так что инициатива 1ES в различной степени затронула почти все аспекты нашего процесса разработки.
Мы сделали несколько интересных ставок. Среди них:
За облаком будущее — Большая часть нашей инфраструктуры и инструментов размещаются локально (в том числе TFS). Мы согласились, что будущее за облаком — мобильность, управление, эволюция, эластичность, все причины, которые могут прийти на ум. Несколько лет назад это было очень спорным. Как Microsoft может перенести всю свою интеллектуальную собственность в облако? Что насчёт производительности? Что насчёт безопасности? Надёжности? Соблюдения правовых норм и управления? Что насчёт… Понадобилось время, но в конце концов набралась критическая масса согласных с идеей. Спустя годы это решение становилось более и более понятным, и сейчас все в восторге от переезда в облако.
Первое лицо == третье лицо — Такое выражение (1st party == 3rd party) мы используем внутри компании. Оно означает, что мы в максимальной степени стремимся использовать свои коммерческие продукты — и наоборот, продавать продукты, которые сами используем. Не всегда получается на 100% и это не всегда параллельный процесс, но таково направление движения — предположение по умолчанию, пока не появится хорошая причина поступать иначе.
Visual Studio Team Services лежат в основе — Мы сделали ставку на Team Services как основу. Нам нужна ткань, объединяющая воедино всю нашу систему разработки — центральный хаб, откуда вы всё узнаете и всего достигаете. Хаб должен быть современным, обильным, расширяемым и т. д. Каждая группа должна иметь возможность вносить свой вклад и делиться своими особенными вкладами в систему разработки. Team Services отлично подходят на эту роль. За последний год аудитория этих сервисов в Microsoft выросло с пары тысяч человек до более 50 000 преданных пользователей. Как и с TFS, не каждая группа использует их для всего возможного, но импульс в этом направлении наблюдается сильный.
Планирование работы Team Services — Выбрав Team Services, было довольно естественным выбрать соответствующие возможности по планированию работы. Мы загрузили группы вроде группы Windows, с многими тысячами пользователей и многими миллионами рабочих элементов, в единый аккаунт Team Services. Чтобы всё заработало, по ходу дела пришлось произвести немалую работу по производительности и масштабированию. В данный момент практически каждая группа в Microsoft осуществила этот переход и вся наша разработка управляется через Team Services.
Оркестровка Team Services Build и CloudBuild — Не буду слишком глубоко копать эту тему, потому что она гигантская сама по себе. Скажу только о результате, что мы выбрали сервис Team Services Build в качестве нашей системы оркестровки операций сборки, а управление Team Services Build в качестве нашего пользовательского интерфейса. Мы также разработали новый “make-движок” (который пока не выпустили) для некоторых из самых больших кодовых баз, он поддерживает тонко настроенное кэширование в большом масштабе, параллельное выполнение и инкрементальность, то есть поэтапное выполнение. Мы видели, как многочасовая сборка иногда сокращалась до минут. Подробнее об этом как-нибудь расскажем в будущей статье.
После большой предыстории — к самому главному.
Git для управления исходным кодом
Наверное, самое спорное решение мы приняли по поводу системы управления исходным кодом. У нас была внутренняя система под названием Source Depot, которую абсолютно все использовали в начале 2000-х. Со временем TFS и её решение Team Foundation Version Control получили популярность в компании, но так и не смогли проникнуть в самые крупные группы разработки — такие как Windows и Office. Думаю, здесь много причин. Одна из них в том, что для таких больших коллективов цена перехода оказалась чрезвычайно высокой, а две системы (Source Depot и TFS) не настолько сильно отличались, чтобы оправдать её.
Но системы контроля версий порождают интенсивную лояльность — больше, чем любой другой инструмент разработчика. Так что схватка между сторонниками TFVC, Source Depot, Git, Mercurial и других была жестокой, и если честно, мы сделали выбор, так и не придя к консенсусу — это просто должно было случиться. Мы решили сделать стандартом в компании Git по многим причинам. Со временем это решение получало всё больше и больше сторонников.
Против выбора Git тоже было много аргументов, но самым железобетонным было масштабирование. Существует не так много компаний с кодовой базой нашего размера. В частности, Windows и Office (есть и другие) имеют массивный размер. Тысячи разработчиков, миллионы файлов, тысячи машин для сборки, которые постоянно работают. Честно говоря, это поражает воображение. Чтобы внести ясность, когда я упоминаю здесь Windows, я имею в виду все версии — это Windows для PC, Mobile, Server, HoloLens, Xbox, IOT и так далее. А Git — распределённая система контроля версий (DVCS). Она копирует весь репозиторий и всю его историю на вашу локальную машину. Сделать это с проектом Windows было бы смешно (и мы очень смеялись в первое время). Как TFVC, так и Source Depot тщательно настраивались и оптимизировались для больших кодовых баз и конкретных групп разработчиков. Git никогда не применяли для такой задачи (или даже в пределах одного порядка от неё), и многие утверждали, что система никогда не заработает.
Первый большой спор был — сколько репозиториев заводить, один для всей компании или по одному для каждого маленького компонента? Большой диапазон. Git доказал свою исключительно хорошую работу для очень большого количества скромных репозиториев, так что мы потратили немало времени, думая над разбиением наших объёмных кодовых баз на большое количество репозиториев умеренного размера. Хм-м-м. Когда-нибудь работали с огромной кодовой базой в течение 20 лет? Когда-нибудь пробовали впоследствии вернуться назад и разбить её на маленькие репозитории? Можете догадаться, к какому ответу мы пришли. Этот код очень сложно разобрать на части. Цена будет слишком велика. Риски от такого уровня смешения станут чудовищными. И у нас действительно есть сценарии, когда единственному инженеру требуется произвести радикальные изменения в очень большом объёме кода. Координировать это между сотнями репозиториев будет очень проблематично.
После длительного выкручивания рук мы решили, что наша стратегия должна быть «Правильное количество репозиториев, в зависимости от природы кода». Некоторый код можно выделить (как микросервисы) и он идеально подходит для изолированных рпепозиториев. Некоторый код нельзя разделить на части (как ядро Windows) и его нужно воспринимать как единый репозиторий. И я хочу подчеркнуть, что дело не только в сложности разбиения кода на части. Иногда в больших связанных друг с другом кодовых базах действительно лучше воспринимать эту кодовую базу как единое целое. Может быть когда-нибудь я расскажу историю о попытках группы Bing выделить компоненты ключевой платформы Bing в отдельные пакеты — и о проблемах версионности, с которыми они столкнулись. Сейчас они уходят от этой стратегии.
Таким образом, нам пришлось приступать к масштабированию Git для работы на кодовых базах с миллионами файлов в сотни гигабайт и используемых тысячами разработчиков. Кстати говоря, даже Source Depot никогда не масштабировали на всю кодовую базу Windows. Её разбили более чем на 40 репозиториев, чтобы иметь возможность масштабировать. Но сверху надстроили слой, так что в большинстве случаев кодовую базу можно было воспринимать как единое целое. Такая абстракция не была идеальной и определённо вызвала некоторые разногласия.
Мы неудачно начинали масштабировать Git по крайней мере двумя способами. Вероятно, самой значительной стала попытка использовать подмодули Git, чтобы сшить воедино множество репозиториев в единый «супер-репозиторий». Не буду вдаваться в детали, но после 6 месяцев работы над проектом мы поняли, что он не будет функционировать — слишком много граничных ситуаций, высока сложность, проект слишком хрупкий. Нам нужно было проверенное надёжное решение, которое бы хорошо поддерживалось почти всеми инструментами Git.
Почти год назад мы вернулись к началу и сконцентрировались на вопросе, как в реальности масштабировать Git до единого репозитория, вмещающего целую кодовую базу Windows (в том числе оценки для роста и историю), и как поддерживать всех разработчиков и машины для сборки.
Мы попробовали «виртуализацию» Git. Обычно Git скачивает всё при клонировании. Но что если нет? Что если мы сделаем виртуализацию хранения, чтобы он скачивал только нужные части. Таким образом клонирование объёмного репозитория в 300 ГБ становится очень быстрым. По мере того как я у себя ввожу команды на чтение/запись, система незаметно подгружает контент из облака (а затем хранит его локально, так что в будущем доступ к данным осуществляется локально). Единственная отрицательная сторона здесь в потере поддержки офлайновой работы. Для этого нужно «прикоснуться» ко всему, чтобы оставить манифест для локальной работы, в остальном ничего не меняется — вы по-прежнему получаете на 100% верный опыт работы с Git. И для наших огромных кодовых баз такой вариант с виртуализацией был приемлемым.
Это был перспективный подход, и мы начали разрабатывать прототип. Мы назвали проект Git Virtual File System или GVFS. Мы поставили цель совершить минимум изменений в git.exe. Конечно, мы не хотели форкать Git — это было бы катастрофой. И не хотели изменять его настолько, чтобы сообщество никогда не приняло эти изменения. Так что мы выбрали промежуточный путь, в котором максимальное количество изменений производится «под» Git — в драйвере виртуальной файловой системы.
Драйвер виртуальной файловой системы в основном виртуализирует две вещи:
- Папку .git, где хранятся все пакетные файлы, история и т. д. Это папка для всего по умолчанию. Мы виртуализировали её, чтобы вытягивать только нужные файлы и только когда нужно.
- «Рабочую директорию» — место, куда вы идёте, чтобы реально отредактировать исходный код, собрать его и т. д. GVFS отслеживает рабочую директорию и автоматически «проверяет» каждый файл, к которому вы прикасаетесь, создавая впечатление, что все файлы реально находятся там, но не требуя ресурсов, пока вы на самом деле не запросите доступ к конкретному файлу.
По мере продвижения нашей работы, как вы можете представить, мы многое узнали. Среди прочего, мы узнали, что сервер Git должен быть умным. Он должен паковать файлы Git наиболее оптимальным образом, чтобы не отправлять клиенту больше, чем ему действительно необходимо — представьте это как оптимизацию локальности ссылок. Так что мы сделали много улучшений в Git-сервере Team Services/TFS. Мы также обнаружили, что у Git много сценариев, когда он трогает файлы, которых не должен трогать. Раньше это никогда не имело значения, потому что всё хранилось локально, а Git использовали в репозиториях среднего размера, так что он работал очень быстро — но если трогать всё, то придётся скачивать с сервера или сканировать 6 000 000 файлов, это не шутка. Так что мы потратили много времени на оптимизацию производительности Git. Многие из сделанных нами оптимизаций принесут выгоду «нормальным» репозиториям в какой-то степени, но эти оптимизации являются критическими для мега-репозиториев. Мы отправили многие из этих улучшений в проект Git OSS и получили удовольствие от хорошего сотрудничества с ними.
Итак, быстро перенесёмся в наши дни. Всё работает! Мы вместили весь код с более чем 40 серверов Windows Source Depot в рамках единого репозитория Git, размещённого в VS Team Services — и он хорошо себя проявляет. Вы можете зайти (enlist) за пару минут и проделать все свои обычные операции в Git в течение секунд. И во всех смыслах это прозрачный сервис. Просто Git. Ваши разработчики продолжат работать как работали, используя те инструменты, которые использовали. Ваши сборки просто работают, и т. д. Это просто удивительно. Магия!
В качестве сопутствующего эффекта, такой подход хорошо отразился на больших бинарных файлах. Он не расширяет Git с помощью нового механизма, как делает LFS, никаких «выделений» и тому подобного. Вы можете работать с большими бинарными файлами как с любыми другими файлами, но при этом скачиваются только те блобы, которые вы затронули.
Git Merge
На конференции Git Merge в Брюсселе Саид Нурсалехи (Saeed Noursalehi) поделился с миром тем, что мы делаем — в том числе мучительными деталями сделанной работы и того, что мы поняли. Одновременно мы выложили всю нашу работу в open source. Мы также включили несколько дополнительных серверных протоколов, которые нужно было представить. Можете найти проект GVFS и все изменения, сделанные в Git.exe, в репозиториях Microsoft GitHub. GVFS полагается на новый драйвер фильтра Windows (моральный эквивалент драйвера FUSE в Linux), и мы поработали с группой Windows, выпустив этот драйвер пораньше, чтобы вы могли попробовать GVFS. Дополнительную информацию и ссылки на дополнительные ресурсы см. в посте Саида. Можете изучить их. Можете даже установить GVFS и опробовать её.
В то время как я отмечаю работоспособность GVFS, хочу подчеркнуть, что ещё многое предстоит сделать. Мы не всё закончили. Думаем, что доказали концепцию, но всё ещё предстоит большая работа, чтобы воплотить её в жизнь. Мы делаем официальный анонс и публикуем исходный код, чтобы привлечь сообщество к совместной работе. Все вместе мы сможем масштабировать Git для самых больших кодовых баз.
Извините за длинный пост, надеюсь, он был интересным. Я в восторге от проделанной работы — как в рамках инициативы 1ES в Microsoft, так и над масштабированием Git.
Комментарии (26)
Crandel
29.03.2017 12:50-7Мы выступили с инициативой, которую называем «Одна Инженерная Система» (One Engineering System) или сокращённо 1ES
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind themheleo
30.03.2017 12:57-2Кхе кхе… это вы ещё не самый худший вариант поговорки со словом «Один» для данной ситуации вспомнили, а уже досталось.
LoadRunner
29.03.2017 13:01+71ES
У меня какое-то предвзятое отношение к названиям, которые произносятся как «один эс».
Lamaster
29.03.2017 14:16-12Фу-фу-фу, MS, прочь руки от Git!
develop7
29.03.2017 15:13-7по мне так идеальный союз
Lamaster
29.03.2017 15:22-1Это фаза Embrace https://en.wikipedia.org/wiki/Embrace,_extend_and_extinguish
NickKolok
29.03.2017 18:13-1Подавятся. За гитом Торвальдс и FSF. Тут ещё кто кого ЕЕЕ. Де-факто MS подписал приговор своим системам контроля версий и сборки в угоду открытому Git.
mayorovp
30.03.2017 06:04+1Поправка: своим системам контроля версий MS подписали приговор еще несколько лет назад, когда TFS на git перешел.
michael_vostrikov
29.03.2017 18:15+2О, может вы подскажете. В принципе для меня уже не актуально, просто интересно.
Есть баг: https://github.com/git-for-windows/git/issues/741
Он не в самом Git for Windows, а в экзешниках MinGW, которые он использует.
Там при запуске секции делаются writable через VirtualQuery() + VirtualProtect().
В исходниках предполагается, что VirtualQuery() всегда возвращает размер секции.
На некоторых компьютерах VirtualQuery() для секции ".text" возвращает не размер секции, а круглое число чуть меньшего размера. Как будто Windows при запуске программы разделяет секцию на 2 региона.
Проявлялось на нескольких машинах с Windows 7 с очень урезанными правами.
Разработчики исправлять не собираются, хотя это несложно. В принципе баг редкий, особо и не надо. Но было бы интересно узнать, из-за чего в Windows может быть такое поведение.
sebres
29.03.2017 19:21+2because it's the bug of mingw, вернее ее реализация вокруг
mark_section_writable
.
Поэтому и не собираются, ибо нефиг плодить воркараунды.
Т.е. баг делегирован дальше, имхо абсолютно правилно, см. MinGW-w64 — for 32 and 64 bit Windows / Bugs / #537 pseudo_reloc fails to mark pages writablemichael_vostrikov
29.03.2017 20:54+1Под разработчиками я имел в виду разработчиков mingw, хотя и первых тоже. Одни используют программу других и не хотят напоминать им о баге, другие просто не хотят исправлять. Делегирован он другим пользователем, который и написал эту ссылку в комментах к багу на гитхабе. Вопрос у меня не в том как исправить, а почему у Windows может быть такое поведение относительно секций.
sebres
30.03.2017 19:28Я могу конечно ошибаться, но думается мне почему-то, что это ASLR (и-или DEP).
Если на машинках, где обоих можно выключить, баг не воспроизводится — оно говорит за-то...
Ну и если да, решения два (кроме как не юзать винду):
- не использовать абсолютных указателей (только относительные, не думаю что вариант для mingw)
- или бороться как я например тут для nginx делал, т.е. грубо говоря переалоцировать base, пока не выравняем блок у всех caller по одному адресу (good luck with its implementation;).
Ну или тот-же воркараунд на секции .text (MEM_WRITE как сделал Jason Bell), хотя не сукьюрно оно как-то.
michael_vostrikov
30.03.2017 21:10Нет, я когда отлаживал, заметил что перебазируется, тогда и узнал про ASLR, сначала тоже думал из-за этого. Но баг проявляется независимо от базы и с отключенным ASLR. Насчет DEP тоже не уверен, секция .text явно не data.
akzhan
30.03.2017 01:11Не совсем понял. Если почитать MSDN, там VirtualQuery
а) меняет искомый адрес для соответствия границе страницы.
б) дает информацию только о наборе страниц, начиная с указанной, которые выделены одним вызовом, имеют одинаковые атрибуты доступа и состояние.
То есть однозначно гарантируется, что число опрошенных страниц не всегда равно выделенному числу страниц.
The function determines the attributes of the first page in the region and then scans subsequent pages until it scans the entire range of pages or until it encounters a page with a nonmatching set of attributes. The function returns the attributes and the size of the region of pages with matching attributes, in bytes. For example, if there is a 40 megabyte (MB) region of free memory, and VirtualQuery is called on a page that is 10 MB into the region, the function will obtain a state of MEM_FREE and a size of 30 MB.
michael_vostrikov
30.03.2017 07:39Да, вот при запуске, когда выделяется память под секции, почему-то или делается 2 вызова или появляются страницы с другими атрибутами. Хотя вроде в заголовке атрибуты задаются на всю секцию, да и выделять память логично одним куском. Может конечно антивирус балуется, но все равно немного странно.
develop7
30.03.2017 11:52+1Git никогда не применяли для такой задачи (или даже в пределах одного порядка от неё)
в фейсбуке применяли, но сдались и взяли Mercurial (такой же комментарий есть под исходным постом)
sborisov
30.03.2017 15:17Там сплошной C#…
Если уж Линус на С++ ругался, страшно представить что он microsoft тут покажет, nvidia отделалась лёгким испугом… :)mayorovp
30.03.2017 15:21-1Он ругался не на С++, а на загрузку рантайма плюсов в ядро
sborisov
30.03.2017 15:33+1mayorovp
30.03.2017 15:46+1Хм, про случай с GIT я не слышал.
В любом случае, между "добавить новый язык в единственную реализацию" и "сделать полностью совместимую обертку" есть огромная разница.
От GVFS, если что-то пойдет не так, легко отказаться. Просто понадобится больше локальных ресурсов на хранение репозитория целиком.
k12th
TFS умрет, счастье-то какое.