Написали 100 микросервисов и не сошли с ума: как мы в Lamoda шарим знания и технологии

    Привет, Хабр! Меня зовут Даниил Зиненко, руководитель направления разработки Online Shop в Lamoda.

    Online Shop – это одно из IT-подразделений в Lamoda, которое отвечает за сайт и за мобильное приложение. Всего у нас 121 сервис, 67 из которых мы написали на Go за последние 4 года.  При этом мы активно продолжаем создавать и внедрять новые. 


    Эта статья — расшифровка моего мини-доклада с Golang Live 2020. Под катом я расскажу о том, как мы упрощаем задачу написания новых сервисов и облегчаем поддержку существующих. Какие инструменты для этого мы нашли или написали, какие процессы нам в этом помогают.

    Обмен экспертизой и опытом


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

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

    • Tech Talks – встреча, где команда в течение часа обсуждает проблемы и решения, идеи, новые технологии, которые хочется привнести в проект.  
    • IT Fest– подобный формат в более крупном масштабе. Он дает возможность  рассказать коллегам из других команд о проблемах и как удалось с ними справиться. Так весь IT в компании может узнать о том, какие проблемы мы уже умеем решать и как, что помогает избавляться от «велосипедов». 
    • Архитектурный комитет – еще одна важная активность в компании. Его задача – это валидация будущих изменений архитектуры наших систем. По формату это часовая встреча, на которую обязательно собираются техлиды, тимлиды и представители DevOpsа. А также могут присоединиться все желающие.

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

    Первая цель этой встречи — найти вопросы, которые помогут разработчику сделать архитектуру проекта лучше. Вторая — рассказать техлидам, тимлидам, DevOps-инженерам о том, какие изменения в архитектуре систем следует ожидать в будущем. Это важно и помогает избегать проблем, когда команды одновременно берутся за решение похожих задач, не зная друг о друге. Архитектурный комитет помогает им встретиться и сделать единое хорошее решение. 

    Кроме того, есть приятный сайд-эффект – мы понимаем, какие общие практики есть в компании и влияем на их формирование. Это уменьшает зоопарк решений в системах. 

    Замораживаем разработку старых сервисов


    Нам важно не только уметь писать новые сервисы, но и еще уметь НЕ писать старые. Мы называем такой процесс холдированием или заморозкой разработки. У нас в Online Shop есть старые сервисы, написанные на РНР или на Python, и иногда поддержка таких старых систем немного болит. 

    В какой-то момент мы перестаем развивать тот или иной сервис. Разработка там прекращается и максимум, что туда можно коммитить – это критичные фиксы. Если команде нужен новый функционал, за который отвечает устаревший сервис, ребята пишут похожий сервис на Go. Там же реализуют все функции, которые нужны для их проекта. В дальнейшем задачи со старого сервиса плавно перетекают в новый. И однажды мы просто выключаем “пенсионера”. Так мы идем к тому, чтобы уменьшить количество сервисов, которые неудобно поддерживать.

    Технологии и инфраструктура нам в помощь


    • Мы исповедуем подход specification first. Разработка нового сервиса начинается с того, что мы пишем спецификацию на его API. Затем используем специальные утилиты, которые по этой спецификации генерируют обвязку для сервиса, которая решает много задач: мониторинг, логирование, роутинг, трейсинг и много чего другого. По сути, нам не нужно каждый раз решать одни и те же технические задачи при написании нового сервиса. Вместо этого мы генерируем код и начинаем писать бизнес-логику. 
    • Мы активно используем Docker-compose, поскольку хотим обеспечить низкий порог вхождения разработчика в новый для него сервис. У нас есть простой способ понять все зависимости: как минимум, база данных, как максимум – другие сервисы, если без них тестирование функционала сервиса не очень удобно. Все они обернуты в Docker-compose. Благодаря этому, разработчик может быстро проверить работу сервиса до и после изменений. 
    • Мы используем линтеры – особенно в сервисах, которые развиваются и поддерживаются несколькими командами. У нас есть golangci-lint, который помогает уменьшить время code review, улучшить качество кода и его чистоту.
    • Фреймворк функционального тестирования Gonkey, который мы написали сами. Его прелесть в том, что он декларативный. То есть мы не программируем тесты, а описываем их в YAML и запускаем. С помощью Gonkey мы довольно просто ушли  от ручного тестирования в пользу автоматизированного во многих сервисах. 
    • Все наши сервисы работают в Kubernetes. Разработчики пишут и редактируют  helm-чарты. Этот подход позволяет инженерам лучше понимать, в какой конфигурации будет работать их сервис на продакшн. При этом экспертиза по Kubernetes не в полной мере находится на стороне разработки, поэтому подключаем DevOps-инженеров. Они делают code review helm-чартов и настраивают деплой в продакшн. 

    Когда новый сотрудник выкладывает свой первый сервис в Kubernetes, то у него не будет никаких доступов к зависимостям или к ресурсам по умолчанию. Новичок даже не сможет подключиться к базе данных. Это сделано для того, чтобы избежать ошибок, когда, например, сервис в продакшне ходит в базу данных, лежащую в тесте. Вместо этого мы специально настраиваем доступы: заводим тикеты с описаниями зависимостей и ресурсов, к которым необходим доступ нашему сервису. Затем инженер по безопасности валидирует,  должен ли сервис иметь доступ к указанным ресурсам. 

    Подведём итоги


    • Мы получаем эволюционный набор общих подходов к разработке, которые получаются благодаря активному обмену опытом и знаниями. Мы совместно обсуждаем свои решения. 
    • Мы стараемся не делать руками всё, что возможно: генерируем обвязку для сервисов, автоматизируем проверку кода с помощью линтеров и автоматизируем тестирование. 
    • И мы понимаем, что не вся экспертиза должна быть именно на стороне разработки.  В частности, экспертиза Kubernetes или экспертиза по безопасности должна находиться на стороне DevOps-инженеров и инженеров по безопасности. Мы процессно подключаем соответствующие команды, чтобы валидировать те решения, которые принимает разработка.
    Lamoda
    Russian Fashion Tech

    Комментарии 6

      0
      Go становится все более востребованным языком программирования, почитал тут про него разные статейки:
      ИМХО, самым серьезным плюсом Go является то, что он «поддерживается и развивается Google». Похоже, что в недалеком будущем придется изучать…
        0
        Вебсервисы на Go — нишевая история, так как куда быстрее их лабать на PHP/Node/Python. Гуглом много, чего поддерживается и периодически закапывается, это не показатель.
        0

        Ха, так вот это кто email в личном кабинете не валидирует, мне тут ваша покупательница задолбала своими покупками уже, а тех поддержка ваша болт положила

          0

          Меня интересует вопрос использования go сервисов в кубе: по всей видимости go-сервисы используют gRPC, но как быть с сервис-дискавери при подключении к другому сервису/сам и как быть с балансировкой запросов когда сервис должен общаться с несколькими инстансами другого сервиса — gRPC подключается по IP и жестко привязывается к конкретному инстансу:


          • если этот инстанс умрет — умрет и инстанс потребляющий его
          • возможны перекосы в нагрузке — все инстансы сервиса потребителя подключаться к одному инстансу сервиса=источника
          • масштабирование сервиса-источника становится бесполезным т.к. сервис-потребитель подключается к сервису-источнику 1:1

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


          возможно я не прав?

            0
            Привет, это правда, что стандартный балансировщик k8s не подходит для работы с gRPC. Точнее даже будет сказать с http/2. Но наши сервисы общаются между собой иначе. Мы используем протокол JSON-RPC, который работает поверх http/1.1 и отлично ложится на стандартные механизмы балансировки кубера.
              0

              спасибо за ответ — мы тоже к этому пришли

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое