Русский
Русский
English
Статистика
Реклама

Микросервисы

Backend United 6 Табаско разработчики о безопасности

16.06.2020 12:17:10 | Автор: admin

Привет! 25июня в18:00 поМоскве пройдёт шестой митап всерии Backend United подкодовым названием Табаско. Вещаем вонлайн-формате. Тема митапа безопасность. Будем говорить обобнаружении и предотвращении ошибок принаписании и эксплуатации кода, которые могут привести кпроблемам ссекьюрностью.


Традиционно дляBackend United речь пойдёт отехнологиях и подходах, не завязанных наконкретный язык программирования. Под катом тезисы выступлений и ссылка натрансляцию.



Доклады


Как мы (и нас) сами себя взламываем: безопасность глазами разработчика Денис Юрьев, Skyeng


image


Проблемы взлома и уязвимости сайтов никуда не делись в2020-м. Напримере текущих и прошлых проектов я покажу многие вещи, которые вы можете обнаружить и, надеюсь, успеть поправить отнеправильной настройки заголовков NGINX и XSS доDDoS и перебора паролей.

Заодно вы узнаете:
  • Решают ли фреймворки проблему безопасности? Спойлер: нет.
  • Как не доверять фронтенду.
  • Как прокачаться ввопросах безопасности.


О спикере: Я тимлид, а ранее бэкенд-разработчик в Skyeng Math. Работаю удаленно изНовосибирска. Вразработке с2012 года. Интересуюсь лучшими практиками CI/CD, тестирования и безопасности.



Single quote injection tofind them all Александр Трифанов, Авито


image


Скажите, а вы пишете логи обошибках? А как часто их потом читаете? Рассказываем онашем опыте обнаружения атак набазы данных вреальном времени поошибкам вSentry. Спойлер: всех убил апостроф.

О спикере: Замкадыш изНовосибирска. Занимаюсь тестированием напроникновение и разработкой решений попоиску уязвимостей. Неравнодушен креверс-инжинирингу и эксплуатации бинарных уязвимостей.



Security Training & Awareness вТинькофф Елена Клочкова, Тинькофф


image


Доклад отом, как мы вТинькофф cнуля развивали культуру безопасного программирования вкомандах, и какими способами смогли вовлечь самих разработчиков впоиск уязвимостей.

Расскажу, какие процессы безопасности устоялись, какие оказались неэффективными, и как их внедрение повлияло наметрики команды Application Security.



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


Пароли и явки


Трансляция нанашем ютуб-канале стартует вчетверг 25июня в18:00. Закончим примерно в20:40. На трансляции можно сразу нажать кнопку напомнить, чтобы ничего не пропустить. Если хочется получить напоминание соссылкой наэфир наэлектронную почту, можно зарегистрироваться натаймпаде.


До встречи вонлайне!

Подробнее..

Перевод Конференция QCon. Овладение хаосом руководство Netflix для микросервисов. Часть 1

21.06.2020 00:16:48 | Автор: admin
Джош Эванс рассказывает о хаотичном и ярком мире микросервисов Netflix, начиная с самых основ анатомии микросервисов, проблем, связанных с распределенными системами и их преимуществ. Опираясь на этот фундамент, он исследует культурные, архитектурные и операционные методы, которые ведут к овладению микросервисами.

Около 15 лет назад моя мачеха, назовем ее Фрэнсис, стала чувствовать боль и слабость во всем теле, ей стало трудно стоять, и когда врачи в больнице немного привели ее в себя, у нее обнаружился паралич рук и ног. Это было ужасное испытание для нее и для нас, как оказалось, диагнозом стал синдром Гийона-Барре. Мне просто любопытно, кто-нибудь из вас слышал о такой болезни? О, довольно много людей! Надеюсь, вы получили эту информацию не из первых рук. Это аутоиммунное заболевание, острый полирадикулоневрит, при котором иммунная система человека поражает собственные периферические нервы.



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

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

Вы можете спросить: Какое отношение этот рассказ имеет к теме микросервисов? Так вот, трафик в архитектуре микросервисов являет собой такой же подвиг, как и человеческое дыхание. У вас могут возникать всплески трафика, иметь место враждебная DDoS атака, хакер может внести изменения в вашу рабочую среду, отрезав клиентам доступ. Вот почему сегодня мы собираемся поговорить об архитектуре микросервисов, об их огромных преимуществах, проблема и решениях, которые Netflix обнаружил в течение последних 7 лет борьбы с большим количеством сбоев разного рода.

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

Я Джош Эванс, который начал работу в Netflix в 1999 году, перед этим сделав карьеру в схожей области. Я пришел в проект за месяц до запуска DVD-сервиса, работал инженером, менеджером и был участником интеграции коммерческого продукта и стриминга в существующий DVD-бизнес. В 2009 я попал прямо в сердце потокового мультимедиа, возглавив команду Playback Service службу, которая занимается доставкой DRM, манифестов и записью телеметрии, возвращающейся из устройств пользователей. Я также управлял этой командой во время международного внедрения Netflix, когда наш сервис заработал практически на всех устройствах, воспроизводящих потоковое видео, и участвовал в переносе проекта с дата-центров в облачный сервис. Можно сказать, что последние 3 года были самыми захватывающими. Я возглавлял команду инженеров Operations Engineering, которая фокусируется на высокопрофессиональных операциях контроля скорости, мониторинге и предупреждении сбоев, доставке потокового мультимедиа и широком спектре функций, поиогающих инженерам Netflix успешно эксплуатировать свои собственные облачные сервисы.

Примерно месяц назад я ушел из Netflix и сегодня наверстываю упущенное с книгой Арианны Хаффингтон The Sleep Revolution: Transforming Your Life, One Night at a Time. Впервые за довольно долгое время я взял отпуск и провожу его с семьей, пытаясь выяснить, как создать баланс между работой и личной жизнью.

Как известно, Netflix является лидером в области абонентского интернет-телевидения, предоставляющим пользователям голливудскую кинопродукцию, инди, локальные передачи, растущий пласт оригинального контента. У нас 86 млн. пользователей в 190 странах, стриминг на 10 языках и поддержка более 1000 типов устройств. Все это работает на основе микросервисов AWS.



Давайте поговорим о микросервисах с абстрактной точки зрения. Начнем с того, какими они не должны быть. Дата-центр Netflix DVD образца 2000 года имел достаточно простую инфраструктуру: аппаратный балансировщик нагрузки, кстати, достаточно дорогой, хост Linux стандартной конфигурации с Apache Reverse Proxy и Tomcat, и всего одно приложение, названное нами Javaweb.



Хост напрямую соединялся через JDBC с базой данных Oracle, которая, в свою очередь, соединялась с другой, биллинговой базой данных Oracle через DB link. Первой проблемой данной архитектуры была монолитность кодовой базы Javaweb, то есть все вкладывалось в одну единственную программную базу, обновляемую еженедельно или раз в 2 недели. Любое внеочередное изменение становилось проблемой, которую было достаточно трудно диагностировать. Например, мы потратили почти неделю, разбираясь с медленной памятью. Мы вытягивали куски кода, запускали его, смотрели, что при этом происходит и так далее, поэтому внесение любых изменений занимало много времени. База данных представляла собой еще более строгий монолит это был один сегмент оборудования, работающй с одной большой базой данных Oracle, которую мы называли Базой данных магазина. Если она выходила из строя, то из строя выходило абсолютно все. Каждый год с началом периода отпусков мы наращивали аппаратные мощности, чтобы вертикально масштабировать наше приложение.

Наиболее болезненным был недостаток оперативности мы не могли вносить изменения достаточно быстро, поскольку все компоненты архитектуры были жестко связаны друг с другом. У нас были прямые обращения к базе данных, множество приложений, обращавшихся к табличным схемам, поэтому даже добавление столбца в таблицу становилось большой проблемой для кросс-функционального проекта. Это хороший пример того, как сегодня не нужно создавать сервисы, хотя подобная картина была типичной для конца 90-х начала 2000 годов.

Так что же такое микросервис? Кто-нибудь хочет дать ему определение? Мне нравится, что вы сказали: привязка к контексту и владение данными. Я приведу вам определение Мартина Фаулера: Архитектурный стиль микросервисов представляет собой подход к разработке одного приложения как совокупности мелких сервисов, каждый из которых имеет собственный рабочий процесс и осуществляет коммуникацию с помощью легких механизмов, преимущественно в виде API на основе HTTP-ресурсов.

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

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

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

Давайте рассмотрим архитектуру Netflix и то, как она мапируется.

Слева вы видите клиентский сервис конечный уровень ELB-прокси под названием Zuul, который осуществляет динамическую маршрутизацию. Здесь же расположен NCCP (Netflix Content Control Plane), который поддерживает предыдущие поколения наших устройств и обеспечивает воспроизводящую способность контента. API-шлюз, являющийся ядром нашей современной архитектуры, обращается ко всем другим сервисам для выполнения запросов клиентов.



Справа расположена подсистема среднего уровня Middle Tier и платформа сервиса. Это среда, состоящая из множества компонентов, таких как A/B тестирование, сообщающее результаты пользовательских проверок. Абонентский сервис Subscriber предоставляет развернутую информацию о клиентах, система рекомендаций Recommendations обеспечивает информацию, необходимую для создания списка фильмов, которые будут представлены каждому клиенту.

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

Эти виды объектов формируют экосистему Netflix. Хочу подчеркнуть, что так как микросервисы являются абстракцией, мы склонны думать о них очень упрощенно. На этом слайде показан мой любимый горизонтально масштабируемый микросервис. Прекрасно, что микросервисы кажутся простыми, однако в реальности почти никогда таковыми не являются. В какой-то момент вам потребуются данные, которые нужно вытянуть из базы данных. Это может быть абонентская информация Subscriber или рекомендации Recommendations. Обычно эти данные находятся на уровне хранения Persistence. На схеме показан обычный подход к получению пользовательских данных, который использует не только сервис Netflix.

Service Client начинает предоставлять клиентские библиотеки на основе Java, которые обеспечивают доступ к базовым данным. Наступает момент, когда вам потребуется масштабировать сервис, привлекая к этому EVCashe Client, потому что сервис с разросшейся базой данных недостаточно хорошо справляется с клиентской нагрузкой. EVCache это распределенное решение для кэширования в памяти, основанное на memcached & spymemcached, интегрированное с инфраструктурой Netflix OSS и AWS EC2. После подключения клиента EVCashe вы должны будете заняться оркестровкой, чтобы, если это хранилище выйдет из строя, вы смогли бы обратиться к Service Client, который вызовет базу данных и вернет ответ обратно. При этом вы должны убедиться в том, что произошло наполнение EVCashe так, что при следующем обращении к нему спустя несколько миллисекунд все будет в порядке.



Эта клиентская библиотека встраивается в клиентское приложение, которое использует микросервис, представляющий собой цельный набор технологий и комплекс конфигураций. Это не простая stateless-структура, которой легко управлять, а сложная комплексная структура.
Итак, рассмотрев основы архитектуры микросервисов, перейдем к проблемам, с которыми мы сталкивались на протяжении последних 7 лет, и их решениям. Я люблю нездоровую пищу и мне нравится эта картинка, потому что я думаю, что во многих случаях проблемы и их решения должны быть связаны с нашими привычками, в нашем случае с тем, как мы подходим к микросервисам. Поэтому во многих случаях нашей целью является организовать здоровое питание и потреблять как можно больше овощей.

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



Первый случай это внутренние запросы на обслуживание Intra-service requests, например, запросы микросервиса А микросервису В. По аналогии с нервными клетками и нервной проводимостью все идет прекрасно, пока нам не приходится перепрыгивать через бездну в случае, когда один сервис вызывает другой, существует огромный риск сбоя.



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

Продолжение будет совсем скоро


Немного рекламы


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?
Подробнее..

Перевод Конференция QCon. Овладение хаосом руководство Netflix для микросервисов. Часть 2

22.06.2020 00:17:16 | Автор: admin
Джош Эванс рассказывает о хаотичном и ярком мире микросервисов Netflix, начиная с самых основ анатомии микросервисов, проблем, связанных с распределенными системами и их преимуществ. Опираясь на этот фундамент, он исследует культурные, архитектурные и операционные методы, которые ведут к овладению микросервисами.

Конференция QCon. Овладение хаосом: руководство Netflix для микросервисов. Часть 1

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



HYSTRIX представляет собой библиотеку отказоустойчивости, которая будет терпеть сбои до порогового значения, оставляя цепь открытой. Это означает, что HYSTRIX будет перенаправлять все последующие вызовы в резерв, чтобы предотвратить будущие сбои, и создаст временной буфер для соответствующего сервиса, который можно будет восстановить после сбоя. Это что-то вроде запасного варианта: если сервис А не может вызвать сервис В, он все равно отправит клиенту резервный ответ, который позволит ему продолжить использование сервиса вместо того, чтобы просто получить сообщение об ошибке.

Таким образом, преимущество HYSTRIX это изолированные пулы потоков и понятие цепи. Если несколько вызовов сервиса В безуспешны, сервис А перестанет их совершать и будет ждать восстановления. В свое время HYSTRIX был инновационным решением, но при его использовании возникал вопрос: у меня есть вся история настроек, я уверен, что все сделано правильно, но как узнать, что он действительно работает?

Лучший способ узнать это (вспомним наши биологические аналогии) вакцинация, когда вы берете мертвый вирус и вводите его в организм, чтобы стимулировать борьбу антител с живым вирусом. В продакшене роль прививки играет фреймворк Fault Injection Testing (FIT) тестирование, которое позволяет находить проблемы микросервисов путем создания искусственных сбоев. С его помощью выполняются синтетические транзакции на уровне устройств или аккаунтов, либо увеличивается объем живого трафика вплоть до 100%. Таким образом проверяется надежность микросервисов под стрессовой нагрузкой.



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

Это хорошо, если рассматривать соединения точка-точка. Но представьте, что ваша система состоит из сотни микросервисов, и каждый из них зависит от других. Как проверить такую систему, не проводя миллионов тестов, во время которых сервисы вызывают друг друга?
Допустим, у вас имеется 10 сервисов в цельной структуре микросервиса, и каждый из них обладает 99,99% доступностью. Это означает, что на протяжение года каждый сервис может быть не доступным 53 минуты.



Если бы сервисы работали независимо, в этом не было бы ничего критичного, но когда они зависят друг от друга, суммарное время отказа всего микросервиса может достигать 8-9 часов в год, а это уже большая разница.

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



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

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

Представьте, что у меня есть общая логика и общие шаблоны доступа для вызова моего сервиса и есть 20 или 30 разных зависимостей. Действительно ли я захочу, чтобы каждая отдельная команда разработчиков писала один и тот же или немного отличающийся код снова и снова, или же захочу объединить все в общую бизнес-логику и общие шаблоны доступа? Это было настолько очевидно, что мы внедрили именно такое решение.

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

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



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

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



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

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

На слайде показан сетевой сервис А, который записывает в 3 базы данных копии одинаковых данных. Каждая из баз работает с одной из 3 сетей, обеспечивая доступность. Вопрос в том, что делать, если вы потеряете связь с одной из БД у вас возникнет сбой и сообщение об ошибке, либо вы продолжите работу с двумя остальными БД, пока неполадка не будет устранена.



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



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

Теперь поговорим об инфраструктуре, потому что это отдельная важная тема. Когда-нибудь ваша инфраструктура, будь то AWS, Google или ваша собственная разработка, может отказать, потому что отказать может все что угодно. Вы видите заголовок статьи Forbes о том, что Amazon AWS обвалил Netflix в канун Рождества 2012 года.



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



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



Ранее в этом году я уже выступал на QСon London с докладом о глобальной архитектуре Netflix, так что вы можете просмотреть это выступление, если хотите вникнуть в тему достаточно глубоко.
Перейдем к масштабированию и рассмотрим три его составляющих: stateless-сервисы, stateful-сервисы и гибридные сервисы. Что же такое stateless-сервис? Кто-нибудь из присутствующих может дать определение? Начну с того, что это не кеш или база данных, где вы храните массивный объем информации. Вместо этого у вас есть часто используемые метаданные, кэшируемые в энергонезависимой памяти.

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

26:30 мин

Продолжение будет совсем скоро


Немного рекламы


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?
Подробнее..

Перевод Конференция QCon. Овладение хаосом руководство Netflix для микросервисов. Часть 3

24.06.2020 00:13:58 | Автор: admin
Джош Эванс рассказывает о хаотичном и ярком мире микросервисов Netflix, начиная с самых основ анатомии микросервисов, проблем, связанных с распределенными системами и их преимуществ. Опираясь на этот фундамент, он исследует культурные, архитектурные и операционные методы, которые ведут к овладению микросервисами.

Конференция QCon. Овладение хаосом: руководство Netflix для микросервисов. Часть 1
Конференция QCon. Овладение хаосом: руководство Netflix для микросервисов. Часть 2

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



У вас есть минимум и максимум, есть метрики, которыми вы пользуетесь, когда увеличиваете свою группу. Если нужен новый экземпляр, вы просто вытягиваете и раскручиваете любой образ из S3. В этом есть ряд преимуществ. Во-первых, это эффективное использование компьютерных мощностей, поскольку вы изменяете их по требованию. Вышедшие из строя узлы легко замещаются новыми. Но самое важное то, что при всплесках трафика, например, во время DDoS-атак или вследствие ошибок производительности, автомасштабирование позволяет сохранять работоспособность системы в то время как вы разбираетесь с причинами и устраняете неполадки. Я настоятельно рекомендую использовать это масштабирование, потому что оно неоднократно спасало нас от серьезных сбоев.

И конечно же, вы хотите убедиться в его постоянной работе с помощью Chaos. Обезьянка Хаоса Chaos Monkey это наш инструмент, который случайным образом уничтожает экземпляры AWS или процессы на серверах, которые обслуживают сервис Netflix. Этот инструмент подтверждает, что если один из узлов узел умирает, то все остальное продолжает работать без проблем. После внедрения Chaos Monkey мы получили возможность круглосуточно убеждаться в том, что все ноды имеют избыточное дублирование, падение одного узла не приводит ни к каким последствиям, а каждая неполадка документируется для того, чтобы впоследствии для ее устранения можно было применить готовое решение.



Давайте рассмотрим, что же представляют собой Stateful-сервисы. Это базы данных, кэши и пользовательские приложения, использующие внутренние кэши с большим объемом данных. Когда мы внедряли мультирегиональную архитектуру и пытались использовать общие стратегии репликации данных, такие приложения создали большую проблему. Поэтому я настоятельно рекомендую по возможности избегать хранения вашей бизнес-логики и состояний внутри одного приложения. Stateful-сервисы характеризуются тем, что потеря одного узла является значимым для системы событием. Замена этого узла новым может занять несколько часов.

Существует два различных подхода к кэшированию. Как я уже говорил, в наш коллектив влились бывшие сотрудники Yahoo, имевшие большой опыт работы с кэшами ha-proxy. Они использовали шаблон из выделенных серверов для пользователей. То есть пользователь всегда попадал на один и тот же узел, где располагался кеш с единственной копией данных. Проблема заключалась в том, что при поломке этого узла пользователь терял доступ ко всему сервису. На ранней стадии существования сервиса, еще до внедрения HYSTRIX, возникали ситуации, когда выход из строя одного узла обрушивал весь сервис Netflix. Устранение неполадки занимало 3,5 часа, в течение которых мы ждали, пока кеш сам себя наполнит, чтобы можно было выполнить запрос.

На следующем слайде показана схема выделенных сегментов Dedicated Shards, представляющая собой отказ от использования шаблона пользовательского dedicated-сервера.



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

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



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



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



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

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



Решение этой проблемы носит комплексный характер:

  • прекратить долбежку одного и того же кластера системы оффлайн-запросами и вызовами в режиме реального времени, разделив рабочую нагрузку на онлайн и оффлайн сегменты;
  • организовать Request-level cashing, то есть всегда привязывать жизненный цикл записи к текущей области запроса, чтобы стало невозможно вызывать один и тот же сервис снова и снова;
  • встраивание в устройства пользователей токенов безопасности Fallback.

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



Рассмотрим вариации различные варианты архитектуры сервиса. Чем больше таких вариантов, тем больше можно решить проблем, возникающих при увеличении масштаба системы, операционных отклонениях Operational drift, при которых эксплуатационные показатели отличаются от базовых показателей работы сервиса, или при внедрении новых языков или контейнеров.

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

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

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



В течение нескольких лет мы аккумулировали лучшие практики и сформулировали общие принципы, которые назвали Production Ready, или Готовый продукт. Это чеклист, или программа действий Netflix. Каждый из принципов основан на автоматизации и постоянном улучшении модели взаимодействия с сервисом:

  • Оповещения Alerts
  • Apache & Tomcat
  • Автоматический canary-анализ
  • Автоматическое масштабирование
  • Модель хаоса
  • Согласованные, непротиворечивые наименования
  • ELB config
  • Проверка работоспособности Healthchek
  • Неизменяемые образы машин
  • Squeeze тестирование. Оно состоит в запуске определенных тестов или бенчмарков для того, чтобы увидеть изменения в производительности и вычислить критическую точку приложения. Затем проверяется, было ли это последнее изменение неэффективным, или же оно определяет рекомендуемые параметры автоматического масштабирования перед развертыванием.
  • Red/Black развертывания, заключающиеся в релизе, который сокращает время простоя и риски за счет запуска двух идентичных производственных сред, Red и Black. В любой момент времени только одна из сред является живой, причем она обслуживает весь трафик.
  • Тайм-ауты, повторные попытки, fallback.


Продолжение будет совсем скоро


Немного рекламы


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?
Подробнее..

Перевод Конференция QCon. Овладение хаосом руководство Netflix для микросервисов. Часть 4

26.06.2020 00:04:47 | Автор: admin
Джош Эванс рассказывает о хаотичном и ярком мире микросервисов Netflix, начиная с самых основ анатомии микросервисов, проблем, связанных с распределенными системами и их преимуществ. Опираясь на этот фундамент, он исследует культурные, архитектурные и операционные методы, которые ведут к овладению микросервисами.

Конференция QCon. Овладение хаосом: руководство Netflix для микросервисов. Часть 1
Конференция QCon. Овладение хаосом: руководство Netflix для микросервисов. Часть 2
Конференция QCon. Овладение хаосом: руководство Netflix для микросервисов. Часть 3

В отличии от operational drift, внедрение новых языков для интернационализации сервиса и новых технологий, таких как контейнеры, это сознательные решения добавить новую сложность в окружающую среду. Моя группа операционистов стандартизировала асфальтированную дорогу лучших технологий для Netflix, которые запекались в заранее определенных наилучших практиках, основанных на Java и EC2, однако по мере развития бизнеса разработчики стали добавлять новые компоненты, такие как Python, Ruby, Node-JS и Docker.



Я очень горжусь тем, что мы первыми сами выступали за то, чтобы наш продукт отлично работал, не дожидаясь жалоб клиентов. Все начиналось достаточно просто у нас были операционные программы на Python и несколько бэк-офисных приложений на Ruby, но все стало намного интересней, когда наши веб-разработчики заявили, что намерены отказаться от JVM и собираются перевести веб-приложение на программную платформу Node.js. После внедрения Docker вещи стали намного сложнее. Мы руководствовались логикой, и придуманные нами технологии стали реальностью, когда мы внедрили их для клиентов, потому что они имели большой смысл. Расскажу вам, почему это так.

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

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

Логично было взять эти endpoints и вытянуть их из API-сервиса. Для этого мы создали компоненты Node.js, которые запускались как небольшие приложения в контейнерах Docker. Это позволило изолировать любые неполадки и сбои, вызванные этими node-приложениями.

Стоимость этих изменений достаточно велика и складывается из следующих факторов:

  • Инструменты повышения производительности. Управление новыми технологиями требовало новых инструментов, потому что UI-команда, использующая очень удачные скрипты для создания эффективной модели, не должна была тратить много времени на управление инфраструктурой, она должна была заниматься только написанием скриптов и проверкой их работоспособности.
    Инсайт и сортировка возможностей ключевым примером являются новые инструменты, необходимые для выявления информации о факторах производительности. Нужно было знать, на сколько % занят процессор, как используется память, и сбор этой информации требовал разных инструментов.
  • Фрагментация базовых образов простая базовая AMI стала более фрагментированной и специализированной.
  • Управление узлами. Не существует доступной готовой архитектуры или технологий, которые позволяют управлять узлами в облаке, поэтому мы создали Titus платформу управления контейнерами, которая обеспечивает масштабируемое и надежное развертывание контейнеров и облачную интеграцию с Amazon AWS.
  • Дублирование библиотеки или платформы. Предоставление новым технологиям одних и тех же основных функций платформы потребовало ее дублирования в облачные инструменты разработчиков Node.js.
  • Кривая обучения и производственный опыт. Внедрение новых технологий неизбежно создает новые проблемы, которые необходимо преодолеть и извлечь из них уроки.

Таким образом, мы не могли ограничиться одной асфальтированной дорогой и должны были постоянно строить новые пути для продвижения своих технологий. Для снижения стоимости мы ограничивали централизованную поддержку и фокусировались на JVM, новых узлах и Docker. Мы расставляли приоритеты по степени эффективного воздействия, информировали команды о стоимости принятых ими решений и стимулировали их искать возможность многократного использования уже разработанных эффективных решений. Мы использовали этот подход при переводе сервиса на иностранные языки для доставки продукта интернациональным клиентам. Примерам могут служить относительно простые клиентские библиотеки, которые могут генерироваться автоматически, так что достаточно легко создавать Python-версию, Ruby-версию, Java-версию и т.д.

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

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



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



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



Нам удалось использовать в конвейере доставки две технологии, которые мы высоко ценим: автоматизированный canary-анализ и поэтапное развертывание. Canary-анализ означает, что мы направляем ручеек трафика в новую версию кода, а остальной продакшн-трафик пропускаем через старую версию. Затем мы проверяем, как справляется с задачей новый код лучше или хуже существующего.

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



В конце выступления я коротко расскажу об организации и архитектуре Netflix. В самом начале у нас была схема под названием Electronic Delivery электронная доставка, представлявшая собой первую версию потоковой передачи медиаконтента NRDP 1.x. Здесь можно использовать термин обратный поток, потому что изначально пользователь мог только скачивать контент для последующего воспроизведения на устройстве. Самая первая платформа электронной доставки Netflix образца 2009 года выглядела примерно так.



Пользовательское устройство содержало в себе приложение Netflix, которое состояло из интерфейса UI, модулей безопасности, активации сервиса и воспроизведения, базирующихся на платформе NRDP Netflix Ready Device Platform.

В то время пользовательский интерфейс был очень прост. Он содержал так называемый Queque Reader, и пользователь заходил на сайт, чтобы добавить что-то в Queque, а затем просматривал добавленный контент на своем устройстве. Положительным было то, что клиентская команда и серверная команда принадлежали одной организации Electronic Delivery и имели тесные рабочие взаимоотношения. Полезная нагрузка была создана на основе XML. Параллельно был создан API Netflix для DVD бизнеса, который стимулировал сторонние приложения направлять трафик в наш сервис.

Однако Netflix API был хорошо подготовлен к тому, чтобы помочь нам с инновационным пользовательским интерфейсом, в нем содержались метаданные всего контента, сведения о том, какие фильмы доступны, что создавало возможность генерировать списки просмотра. У него был общий REST API, базирующийся на схеме JSON, HTTP Response Code, такой же, что используется в современной архитектуре, и модель безопасности OAuth то, что требовалось в то время для внешнего приложения. Это позволило перейти от публичной модели доставки потокового контента к приватной.



Проблема перехода заключалась во фрагментации, так как теперь в нашей системе функционировали два сервиса, основанные на совершенно разных принципах работы один на Rest, JSON и OAuth, другой на RPC, XML и механизме безопасности пользователей на основе системы токенов NTBA. Это была первая гибридная архитектура.

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



В связи с этим у меня был разговор с одним из старших инженеров компании, которому я задал вопрос: Что должна представлять собой правильная долгосрочная архитектура?, и он задал встречный вопрос: Вероятно, тебя больше волнуют организационные последствия что произойдет, если мы интегрируем эти вещи, а они сломают то, что мы хорошо научились делать?. Этот подход очень актуален для закона Конвея: Организации, проектирующие системы, ограничены дизайном, который копирует структуру коммуникации в этой организации. Это очень абстрактное определение, поэтому я предпочитаю более конкретное: Любая часть программного обеспечения отражает организационную структуру, которая его создала. Приведу вам мое любимое высказывание, принадлежащее Эрику Реймонду: Если над компилятором работают четыре команды разработчиков, то в итоге вы получите четырехпроходный компилятор. Что же, Netflix имеет четырехпроходный компилятор, и это то, как мы работаем.

Можно сказать, что в этом случае хвост машет собакой. У нас на первом месте не решение, а организация, именно она является драйвером архитектуры, которую мы имеем. Постепенно от мешанины сервисов мы перешли к архитектуре, которую назвали Blade Runner Бегущий по лезвию, потому что здесь речь идет о граничных сервисах и возможностях NCCP разделяться и интегрироваться напрямую в Zuul-прокси, API-шлюз, причем соответствующие функциональные куски были превращены в новые микросервисы с более продвинутыми функциями безопасности, воспроизведения, сортировки данных и т.д.

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


Немного рекламы


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?
Подробнее..

Перевод Kонференция NDС London. Предотвращение катастрофы микросервисов. Часть 1

27.06.2020 16:12:41 | Автор: admin
Вы потратили месяцы, переделывая свой монолит в микросервисы, и наконец, все собрались, чтобы щелкнуть выключателем. Вы переходите на первую веб-страницу и ничего не происходит. Перезагружаете ее и снова ничего хорошего, сайт работает так медленно, что не отвечает в течение нескольких минут. Что же случилось?

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



Приветствую всех, я Джимми, и сегодня вы услышите, как можно избежать мегакатастроф при создании микросервисов. Эта история компании, в которой я проработал около полутора лет, чтобы помочь предотвратить столкновение их корабля с айсбергом. Чтобы рассказать эту историю должным образом, придется вернуться в прошлое и поговорить о том, с чего начиналась эта компания и как со временем росла ее ИТ-инфраструктура. Чтобы защитить имена невиновных в этой катастрофе, я изменил название этой компании на Bell Computers. На следующем слайде показано, как выглядела IT инфраструктура таких компаний в середине 90-х. Это типичная архитектура большого универсального отказоустойчивого сервера HP Tandem Mainframe для функционирования магазина компьютерной техники.



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

Со временем система становилась все больше и больше, в ней накапливалось огромное количество мусора. Кроме того, COBOL не самый выразительный язык в мире, так что в конечном итоге система превратилась в большой монолитный ком мусора. К 2000 году они увидели, что множество компаний имеют сайты, с помощью которых ведут абсолютно весь бизнес, и решили построить свой первый коммерческий дотком-сайт.

Первоначальный дизайн выглядел довольно симпатично и состоял из сайта верхнего уровня bell.com и ряда поддоменов для отдельных приложений: каталога catalog.bell.com, аккаунтов account.bell.com, заказов orders.bell.com, поиска товаров search.bell.com. Каждый поддомен использовал фреймворк ASP.Net 1.0 и собственные базы данных, и все они общались с бэкендом системы. Однако все заказы продолжали обрабатываться и выполняться внутри единственного огромного мейнфрейма, в котором оставался весь мусор, зато фронтенд представлял собой отдельные веб-сайты с индивидуальными приложениями и отдельными базами данных.



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



Все элементы адресовали вызовы друг другу, обращались к API, встраивали сторонние библиотеки dll и тому подобное. Часто случалось, что системы управления версиями хватали чужой код, запихивали его внутрь проекта, и затем все ломалось. MS SQL Server 2005 использовал концепцию линк-серверов, и хотя я не показал стрелками на слайде, каждая из баз данных также общалась друг с другом, потому что как бы нет ничего плохого в том, чтобы строить таблицы на основании данных, полученных из нескольких БД.

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



Самое смешное было то, что этот мейнфрейм был построен конкурентами Bell Сomputers и до сих пор обслуживался их техническими консультантами. Убедившись в неудовлетворительной работе своих приложений, компания решила от них избавиться и сделать редизайн системы.

Существующее приложение было в продакшене на протяжении 15 лет, что является рекордным для приложений на базе ASP.Net. Сервис принимал заказы со всего мира, и ежегодная прибыль от этого единственного приложения достигала миллиарда долларов. Значительную часть прибыли формировал именно веб-сайт bell.com. По черным пятницам число заказов, сделанных через сайт, достигало несколько миллионов. Однако существующая архитектура не позволяла никакого развития, поскольку жесткие взаимосвязи элементов системы практически не позволяли вносить в сервис никаких изменений.

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

Они поступили разумно, изучив опыт других компаний, чтобы посмотреть, как те решили аналогичную проблему. Одним из таких решений была архитектура сервиса Netflix, представляющая собой микросервисы, соединенные через API, и внешнюю базу данных.

Руководство Bell Сomputers приняло решение построить именно такую архитектуру, придерживаясь неких основных принципов. Во-первых, они отказались от дублирования данных, используя подход общего доступа к БД. Никакие данные не пересылались, напротив, все, кто в них нуждался, должны были обращаться к централизованному источнику. Далее следовали изолированность и автономность каждый сервис был независим от других. Они решили использовать Web API абсолютно для всего если вы хотели получить данные или внести изменения в другую систему, все это делалось через Web API. Последней важной вещью был новый главный мейнфрейм под названием Bell on Bell в отличие от мейнфрейма Bell, основанного на железе конкурентов.

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

Они поступили разумно, кинув все деньги на решение этой проблемы. Они установили самые современные серверные стойки со свитчами, использовали гигабитное оптоволокно, самое мощное серверное железо с сумаcшедшим объемом RAM, соединили все это, настроили и снова ничего! Тогда они начали подозревать, что причина может быть в таймаутах, поэтому зашли во все веб-настройки, все настройки API и обновили всю конфигурацию таймаутов до максимальных значений, так что оставалось только сидеть и ждать, когда с сайтом что-то произойдет. Они ждали, ждали и ждали в течение 9 с половиной минут, пока веб-сайт наконец-то загрузился.

После этого до них дошло, что сложившаяся ситуация нуждается в тщательном разборе, и они пригласили нас. Первое, что мы выяснили в течение всех 18 месяцев разработки так и не было создано ни одного реального микро все становилось только еще больше. После этого мы приступили к написанию post-mortem, известного также как regretrospective, или печальная ретроспектива, она же blame storm обвинительный штурм по аналогии с мозговым штурмом brain storm, чтобы разобраться в причине катастрофы.

У нас было несколько улик, одной из которых являлось полное насыщение трафиком в момент вызова API. Когда вы используете монолитную архитектуру сервиса, то сразу можете понять, что именно пошло не так, потому что у вас имеется трассировка к единственному стеку, которая сообщает обо всем, что могло вызвать сбой. В случае, когда куча сервисов одновременно обращаются к одному API, нет никакой возможности отследить трассировку, кроме как использовать дополнительные инструменты сетевого мониторинга типа WireShark, благодаря которым можно рассмотреть отдельный запрос и выяснить, что произошло при его реализации. Поэтому мы взяли одну веб-страницу и на протяжение почти 2-х недель складывали кусочки мозаики, совершая к ней самые различные вызовы и анализируя, к чему приводит каждый из них.
Посмотрите на эту картинку. Она показывает, что один внешний запрос побуждает сервис совершать множество внутренних вызовов, которые возвращаются обратно. Получается, что каждый внутренний вызов совершает дополнительные хопы, чтобы быть способным самостоятельно обслужить этот запрос, потому что не может больше никуда обратиться за получением нужной информации. Эта картинка выглядит бессмысленным каскадом вызовов, поскольку внешний запрос вызывает дополнительные сервисы, которые вызывают другие дополнительные сервисы, и так практически до бесконечности.



Зеленым цветом на этой схеме показан полукруг, в котором сервисы вызывают друг друга сервис А вызывает сервис В, сервис В вызывает сервис С, а тот снова вызывает сервис А. В результате мы получаем распределенный тупик. Единственный запрос создавал тысячу сетевых вызовов API, и поскольку система не обладала встроенной отказоустойчивостью и защитой от зацикливания, то запрос оканчивался неудачей, если хотя бы один из этих API-вызовов давал сбой.

Мы сделали некоторые математические вычисления. Каждый API-вызов имел SLA не более 150 мс и 99,9% аптайм. Один запрос вызывал 200 различных вызовов, и в наилучшем случае страница могла быть показана через 200 х 150 мс = 30 секунд. Естественно, это никуда не годилось. Перемножив 99,9% аптайм на 200, мы получали 0% доступность. Получается, что эта архитектура была обречена на провал с самого начала.

Мы обратились к разработчикам с вопросом, как же они не сумели разглядеть эту проблему на протяжение 18 месяцев работы? Оказалось, что они подчитывали SLA только для запущенного ими кода, но если их сервис вызывал другой сервис, они не считали это время в своих SLA. Все, что запускалось в пределах одного процесса, придерживалось значения 150 мс, но обращение к другим сервисным процессам многократно увеличивало суммарную задержку. Первый извлеченный из этого урок формулировался так: Распоряжаетесь ли вы своим SLA или же SLA распоряжается вами? В нашем случае выходило второе.

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



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



Эта картинка из блога MS на тему Как строить микросервисы. Здесь показано простое веб-приложение, блок бизнес-логики и база данных. Запрос поступает напрямую, вероятно, здесь имеется один сервер для веб, один сервер для бизнеса и один для БД. Если увеличить трафик, картинка немного поменяется.



Здесь появляется балансировщик нагрузки для распределения трафика между двумя веб-серверами, кэш, расположенный между веб-сервисом и бизнес-логикой и еще один кэш между бизнес-логикой и базой данных. Именно такую архитектуру использовала компания Bell для своего приложения балансировку нагрузки и blue/green развертывание, выполненное в середине 2000-х. До некоторого времени все работало хорошо, поскольку данная схема предназначалась для монолитной структуры.

На следующей картинке показано, как MS рекомендует осуществлять переход от монолита к микросервисам просто разделить каждый из основных сервисов на отдельные микросервисы. Именно при внедрении этой схемы Bell и совершили ошибку.



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

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

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



Она складывается из 4 уровней: уровень пользовательского интерфейса UI, уровень бизнес-логики, уровень доступа к данным и база данных. Более прогрессивна DDD (Domain-Driven Design), или программно-ориентированная архитектура, где два средних уровня представляют собой доменные объекты и репозиторий.



Я попытался рассмотреть в этой архитектуре различные области изменений, различные области ответственности. В обычном N-tier приложении классифицируются различные области изменений, которые пронизывают структуру вертикально сверху вниз. Это Catalog, настройки Config, выполняемые на индивидуальных компьютерах и проверки Checkout, которыми занималась моя команда.



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

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

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

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

Теперь рассмотрим определение микросервисов:

  • микросервис имеет малый размер и предназначен для решения одной конкретной задачи;
  • микросервис автономен;
  • при создании архитектуры микросервиса используется метафора городской планировки town planning metaphor. Это определение из книги Сэма Ньюмана Создание микросервисов.

Определение Bounded Context взято из книги Эрика Эванса Domain-Driven Design. Это основной паттерн в DDD, центр проектирования архитектуры, который работает с объемными архитектурными моделями, разделяя их на разные Bounded Context и явно определяя взаимодействие между ними.



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

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

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



Итак, мы сказали ребятам из Bell Computers: Мы не сможем исправить ничего в созданном вами хаосе, потому что у вас просто не хватит для этого денег, но мы исправим всего один сервис, чтобы придать всему этому смысл. С этого места я начну рассказ о том, как мы исправили единственный сервис, чтобы он стал отвечать на запросы быстрее, чем через 9 с половиной минут.

22:30 мин

Продолжение будет совсем скоро


Немного рекламы


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?
Подробнее..

Из песочницы Микросервисы шаг назад

01.07.2020 16:06:10 | Автор: admin
На дворе 2020 год, эпоха технологических стартапов и сурового энтерпрайза. На первый взгляд, ничего общего у них нет, кроме моды на построение IT систем в стиле микросервисов. Ранее для энтерпрайза считалось стандартом использовать монолитные системы. Теперь в листингах вакансий крупных компаний чаще указывают обязанности типа распилить на микросервисы.

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

Призрачная масштабируемость


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

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

Проблемы взаимодействия сервисов


Полученные сервисы раскидываются из монорепы по отдельным репозиториям. Сами сервисы становится тяжелее связать между собой. В таком случае версия API микросервиса может начать расходится с версией этого же API в микросервисах-клиентах. Тогда старый добрый JSON заменяется на Protobuf, а HTTP на gRPC с целью получить производительность, типизацию и удобное версионирование API.

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

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

Старые ограничения и привычки


При всем этом привычные для монолита ограничения кочуют в микросервисы. Яркие примеры: один язык программирования и одна БД на все микросервисы. В первом случае это бывшее ограничение монолита, во втором наследие, стремящееся стать бутылочным горлышком всей системы. Из-за непринятия разработчиками и менеджментом возможности существования гетерогенной системы, построенной на разных языках программирования, теряется возможность выбора подходящих инструментов для решения актуальных задач.

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

Инфраструктурная бюрократия


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

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

Будущее


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

Конечно, классический монолит ничем не лучше. Он медленный, хранит у себя состояние, тяжело перерабатываем, не покрыт ни модульными, ни интеграционными тестами и т.д. Но мы можем лучше! Благодаря моде на микросервисы среди множества других плюсов мы увидели подъем CI/CD и поработали над тестированием. Теперь мы можем применять их и к другим подходам, а не только к микросервисам.

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

Может, не строить ракету, а построить простой самокат, ведь добраться надо только до конца улицы?
Подробнее..

Разбиваем монолит на микросервисы

30.06.2020 08:17:02 | Автор: admin

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



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


Итак, ваша организация решила разбить старый, добрый монолит на микросервисы. Почему? Ясного ответа никто дать как правило не может, но в целом все начинают описывать как им плохо живется с монолитом. Да, релизные циклы действительно очень зацеплены за разные команды. А почему вы думаете, что в МСА по-другому? Кто-то говорит, что микросервисы гораздо лучше масштабируются. Ну можно сделать и так, а вам зачем это? Нет, может и надо, но вы понимаете зачем или просто подсмотренную фразу используете? Говорят, каждый микросервис гораздо менее требователен к ресурсам: памяти, базе данных и т.д. Ну и что? У вас деньги на сервера иссякли? Бизнес ценность-то в чем?
Коллеги, я не хочу сказать, что у МСА нет преимуществ. Эти преимущества есть. Но я хочу сказать, что какие бы цели вы ни ставили при старте проекта разбивки, вы их скорее всего ставите неправильно и никогда не достигните. Не достигните просто потому, что реализацией проекта у вас будут заниматься те люди, которые довели до состояния бездарно написанного кода ваш монолитный проект. При этом все подходы при реализации МСА настолько отличаются от монолитной, насколько телефонная лапша 20-го века отличается от сетевых технологий нынешнего 21-го века. И аналогия здесь действительно очень удачная. ТФоП доставляет в квартиру одну телефонную линию. Обрыв на любом участке линии приводит к выходу ее из строя. Сетевые технологии динамичны и позволяют строить альтернативные маршруты. Даже выход из строя 60% всей сетевой инфраструктуры страны в результате ядерной войны, не приведет к отказу оставшихся сетей.


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


А сейчас разберем повсеместно встречающиеся ошибки при развитии микросервисной системы предприятия.


  1. Отказ от изменений бизнес-процессов
    Говорят, что любой бизнес реализует в коде свои бизнес-процессы. И, если вы 20 лет до этого строили свои бизнес-процессы на базе вашей монолитной архитектуры, то любая ваша попытка внедрить МСА будет заведомо обречена на провал. Просто потому, что для этого требуется менять бизнес-процессы.Пример? Сколько стадий согласования вопроса у вас существует в организации? Так вот, в микросервисной команде число таких стадий приближается к нулю. Подавляющее большинство вопросов решается внутри команды, реализующей микросервис. Команда не обязана выносить на корпоративный уровень вопросы о языке, на котором будет написан микросервис. Одни могут выбрать Java, а другие Python. Вы может быть даже сейчас не поверите, но этот вопрос является полностью в компетенции команды. И это потому, что в случае каких-то проблем, микросервис проще ПЕРЕПИСАТЬ, чем ПОДДЕРЖИВАТЬ.
    По моему опыту, разработка простейшего микросервиса при нормально поставленном производстве занимает неделю работы двух джунов, включая бюрократию по выводу его в пром, т.е. обходится компании, включая различные накладные расходы, примерно в 50-100 тыс. руб. Если у вас только аналитика занимает месяц работы 3 команд, то у вас нет никакой МСА в организации, вы опять скатываетесь в лютую монолитчину.
  2. Поручить руководство проектам опытным монолитчикам
    После того как вы отказались от модернизации своих бизнес-процессов, совершенно логичным является то, что вы поручаете новый проект очень опытному человеку, который показал себя с лучшей стороны и вообще знает все ваши бизнес-процессы. Возможно кто-то вам и нудел, что на старые проблемы должен взглянуть новый опытный человек, но вы отмахнулись от него как от глупой назойливой мухи. И вот он. Ваш новый/старый руководитель разработки на проекте. Не удивляйтесь, что результат будет тем же, что и раньше и даже хуже. Когда в МСА начинают применяться монолитные решения, ни к чему хорошему это не приведет. Именно в этот самый момент вы подписали смертный приговор вашему пилоту. Возможно, вы даже наберете опытных людей, которые уже сожрали стаю собак на микросервисных проектах, но это вас не спасет, просто потому что их начальник слушать не будет. Просто потому что у него мозги не заточены под МСА, а советы других он будет воспринимать как чудовищную глупость.
  3. Архитектура разрабатывается архитекторами без опыта разработки
    Вот сидит такой архитектор, который за свою жизнь не написал ни строчки кода и выдает распоряжения разработчикам. Очень часто, разработчики оказываются более квалифицированными чем он сам, но он как наполеончик отдает распоряжения. Распоряжения конечно же глупые. Примеры этих распоряжений смотрите дальше.
  4. Повторить функционал монолитной системы.
    Ну это же логично: надо сначала полностью воспроизвести то, что уже есть, а потом двигаться дальше. Воспроизвести все баги и костыли, все то дерьмо, от которого годами плюются разработчики.
    Мне одно не понятно: с чего эти архитекторы взяли, что потом кто-то даст денег на рефакторинг? Т.е. вы копируете вашу морально устаревшую систему, не привносите ничего положительного с точки зрения функционала и с этим 20 летним старьем вы будете жить еще как минимум 10 лет до следующего рефакторинга.
  5. Переиспользование кода
    Любой монолитчик знает, что код надо переиспользовать. Если сделал функцию User::toString, то в рамках МСА ее сейчас нужно выделить в отдельный микросервис и все 1000 других микросервисов будут ломиться к ней для сериализации каждого юзера. То, что первый же сбой в микросервисе положит всю систему в монолитах же такого не было.

Впервые с боевой микросервисной архитектурой я столкнулся в 2017 году. К тому времени система уже работала 7 лет и за это время произошла полная смена команды.
Сотни микросервисов. Документации никакой нет. Нет даже простого описания назначения каждого микросервиса. И вообще не понятен каков статус микросервиса: функционирует, деактивирован, экспериментальный и пр. В случае возникновения проблемы, трассировка микросервисов превращалась в сплошной кошмар. В итоге, в команде просто никто долго не держался. Текучка стала бичом команды. За 3 месяца команда могла просто обновиться полностью.
Это реальная история неудачно спроектированной микросервисной системы. Такой финал ждет подавляющее большинство пилотов, которые сейчас стартовали. А все из-за ошибок, которые я перечислил выше.


А сейчас я хочу рассказать как надо разрабатывать микросервисную систему.


  1. Проанализируйте свой предыдущий опыт, составьте список того, что считаете удачным, а что вам следует пересмотреть. Проведите опрос клиентов, пускай они запросят необходимые изменения в функционале. Ваша цель путем одного мелкого и ювелирно точного рефакторинга достичь нескольких бизнесовых целей. Ваша цель не переписывать одно и то же 10 раз, а создавать бизнес-продукт, который будет приносить деньги. Вы не просто должны сделать копию легаси-системы, а должны построить новейшую систему, которая выведет вас на передовой край ИТ отрасли. Зачем вам эти старые костыли?
  2. Пересмотрите свои бизнес-процессы. Если у вас любой agile всегда скатывается к жесткому водопаду, если согласования и аналитика занимают месяцы, то ваше производство ПО требует кардинальной модернизации. А для этого нужно ...
  3. найти специалиста с большим опытом разработки микросервисных систем. Пускай он не посвящен в ваши бизнес-процессы, но этот новый человек посмотрит на ваши застарелые проблемы свежим взглядом и даст действительно ценные рекомендации. Кроме того, только человек с реальным опытом микросервисной разработки способен предусмотреть те подводные камни, которые вам встретятся. Ваш опытный монолитчик только все запорет.
  4. Легаси-разработчики это ваш резерв, который в новой разработке сможет выступить ценным экспертным звеном. Но люди, которые пилили монолит в виде костылей, ни в коем случае не должны стать костяком разработки микросервисной системы и определять ее архитектуру. Монолитчиков должна ждать стажировка под руководством людей с опытом построения микросервисных систем. И главное что ждет монолитчиков это жесткий слом мозга и полная перестройка мышления.
  5. Каждый микросервис это не просто мелкая функция бэкенда. Это полный цикл разработки бизнес-функции. Одна команда полностью должна нести ответственность за всю разработку этой бизнес-функции как на фронтенде, так и в базе данных. Как только вы начинаете делегировать часть разработки другим командам, вы тут же начинаете погрязать в интеграциях. Интеграции в МСА это еще более дорого, ненадежно и неэффективно чем в монолите. Необходимо снижать их количество. В качестве микросервиса вполне нормально выбрать CRUD для какой-то сущности, например, сущности клиентского договора. Это нормально, если команда предоставит как бэкенд, так и фронтенд-микросервис (или библиотеку) для работы с договорами: список, создать, обновить, удалить. Главное это чтоб команда несла полную ответственность за то как эта функция будет работать на сайте и в мобилах.
  6. Не нужно заниматься фанатизмом при внедрении микросервисной архитектуры. При правильной микроархитектуре сервисов, вы сами решаете в какой форме выпустить приложение: в монолитной, микросервисной или бессерверной архитектуре. Ожидайте, что ваша бизнес-постановка может измениться в любой момент и вы должны с легкостью реализовать изменения. Гибкая разработка это то что просто без лишней болтовни должно реально применяться на всех уровнях.
  7. С недоверием относитесь к переиспользованию функционала. Наоборот, любой функционал должен дублироваться. Ваш выигрыш 10 гигабайт дисковой памяти никого не впечатлит, если справочник, который используют 30 микросервисов будет остановлен из-за сбоя, приведя к каскадному отключению всей микросервисной системы. Микросервисы должны КУПИРОВАТЬ сбои сторонних сервисов, а не усиливать их. И этот принцип это главная проблема для монолитчиков. После 20 лет работы с реляционными БД, после десятилетий опыта нормализации таблиц и структур данных в приложениях, очень сложно приучить себя к мысли, что дублирование, репликация, шардирование, денормализация это нормально и полезно для проекта, а переиспользование и нормализация это потенциально сбойные места, готовые положить всю систему.
  8. И вообще, что произойдет после сбоя одного из модулей? Вы просто должны моделировать все такие сбои и штатно обрабатывать их. Каскадное отключение всей системы это лишь один из сценариев. Неприятностей может быть много. Это в монолите все компоненты находятся в одном Jar-нике. В МСА каждый микросервис отделен ненадежными и компроментируемыми сетевыми коммуникациями. Это не плохо и не страшно. Это надо просто держать в голове при разработке и предусматривать сценарии разрыва этих коммуникаций.
  9. Если вы очень любите Spring, Hibernate и OracleDB, то скорее всего вы никогда не сможете построить надежную и быструю микросервисную систему. Spring был изобретен в годы становления монолитной архитектуры. Это огромный монстр, который даже в функции простого Hello World превратится в jar-файл размером в сотни мегабайт. Просто старт такого приложения растягивается на минуты. И эти гигабайты бессмысленного цифрового мусора будут пожирать ваши серверные ресурсы 24x7x365. Oracle, Postgres, MySQL это все жуткое старье, которое было построено из расчета, что база данных должна крутиться на одном сервере. Да, время идет и все эти базы данных обзавелись средствами масштабирования, но до сих пор они в этом вопросе совершенно неуклюжи и ненадежны. Существуют целые классы баз данных (NoSQL, NewSQL), которые создавались в парадигме Big Data, High Availability, распределенное хранение и т.д. И эти ораклы с постгресами с ними просто не способны конкурировать по надежности и скорости работы. Все эти крутые спринги, ораклы и хайбернейты это наследие уходящей эпохи монолита. Эпоха микросервисов и облачных функций это быстрый старт приложений при возникновении нагрузки, отсутствие состояний для высокой масштабируемости и безжалостная выгрузка всех приложений и ресурсов, которые в данный момент не нужны и лишь бессмысленно расходуют оперативную память.

Заключение.


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


Подробнее..

Что находится между идеей и кодом? Обзор 14 диаграмм UML

29.06.2020 12:20:00 | Автор: admin


Аве Кодер!

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


UML это сокращение от Unified Modeling Language, и, как мы знаем, он является стандартизированным языком моделирования, состоящим из интегрированного набора диаграмм, разработанных, чтобы помочь разработчикам систем и программного обеспечения в определении, визуализации, конструировании и документировании артефактов программных систем, а также, к примеру, для бизнес-моделирования.

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

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

UML не возник на пустом месте, ему предшествовали несколько значимых событий, личностей и методологий. Например:
  • Техника объектного моделирования OMT [James Rumbaugh 1991], которая была лучшей для анализа информационных систем с большим объемом данных.
  • Booch [Grady Booch 1994] отлично подходит для разработки и реализации. Грэди Буч много работал с языком Ада и был крупным игроком в разработке объектно-ориентированных методов для языка. Хотя метод Буча был сильным, нотация была воспринята менее хорошо, например, в его моделях преобладали формы облаков, что выглядело не очень аккуратно.
  • OOSE (объектно-ориентированная программная инженерия [Ivar Jacobson 1992]) модель, известная как модель прецедентов это мощная методология для понимания поведения всей системы, область, где ООП традиционно была слабой.

В 1994 году Джим Рамбо, не путать с Джоном Рэмбо, хотя Джим тоже был крут, потому что был, на секундочку, создателем вышеупомянутой техники объектного моделирования, ошеломил мир программного обеспечения, когда он покинул General Electric и присоединился к Грэди Бучу в Rational Corp. Цель партнерства состояла в том, чтобы объединить их идеи в единый унифицированный метод (рабочее название для метода действительно было Единый метод).

К 1995 году создатель OOSE, Ивар Якобсон, также присоединился к Rational, и его идеи (в частности, концепция прецедентов) были включены в новый унифицированный метод, который теперь называется Unified Modeling Language.
В противовес всем известной Банде Четырех, Команда Румбо, Буча и Якобсона известна как Три Амигоса.

На UML также повлияли другие объектно-ориентированные нотации:
  • Меллор и Шлаер [1998]
  • Coad и Yourdon [1995]
  • Вирфс-Брок [1990]
  • Мартин и Оделл [1992]


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

Почему UML?
По мере того как стратегическая ценность программного обеспечения возрастала для многих компаний, отрасль искала методы для автоматизации производства программного обеспечения, а также для повышения качества и сокращения затрат и времени выхода на рынок.
Эти методы включают технологию компонентов, визуальное программирование, шаблоны и структуры.
Компании также ищут методы для управления сложностью систем по мере увеличения их масштаба.
В частности, они признают необходимость решения повторяющихся архитектурных проблем, таких как физическое распределение, параллелизм, репликация, безопасность, балансировка нагрузки и отказоустойчивость.
Кроме того, разработка под Web хоть и упрощает некоторые вещи, в целом, она усугубляет эти архитектурные проблемы.
Унифицированный язык моделирования (UML) был разработан для удовлетворения этих потребностей.

Основные цели дизайна UML:
  • Предоставить пользователям готовый, выразительный язык визуального моделирования, чтобы они могли разрабатывать и обмениваться осмысленными моделями.
  • Обеспечить механизмы расширяемости и специализации для расширения основных понятий.
  • Быть независимым от конкретных языков программирования и процессов разработки.
  • Обеспечить формальную основу для понимания языка моделирования.
  • Поощрять рост рынка объектно-ориентированных инструментов.
  • Поддержка высокоуровневых концепций разработки, таких как совместная работа, структуры, шаблоны и компоненты.
  • Интегрировать лучшие практики.


Диаграммы UML подразделяют на два типа это структурные диаграммы и диаграммы поведения.



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

  • Диаграмма составной структуры
  • Диаграмма развертывания
  • Диаграмма пакетов
  • Диаграмма профилей
  • Диаграмма классов
  • Диаграмма объектов
  • Диаграмма компонентов


Диаграммы поведения показывают динамическое поведение объектов в системе, которое можно описать, как серию изменений в системе с течением времени. А к диаграммам поведения относятся:

  • Диаграмма деятельности
  • Диаграмма прецедентов
  • Диаграмма состояний
  • Диаграмма последовательности
  • Диаграмма коммуникаций
  • Диаграмма обзора взаимодействия
  • Временная диаграмма


Теперь пару слов о каждой из них

Диаграмма классов

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

Три наиболее важных типа отношений в диаграммах классов (на самом деле их больше), это:

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



Диаграмма компонентов

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



Диаграмма развертывания

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



Диаграмма объектов

Статическая диаграмма объектов является экземпляром диаграммы класса; она показывает снимок подробного состояния системы в определенный момент времени. Разница в том, что диаграмма классов представляет собой абстрактную модель, состоящую из классов и их отношений.
Тем не менее, диаграмма объекта представляет собой экземпляр в конкретный момент, который имеет конкретный характер.Использование диаграмм объектов довольно ограничено, а именно чтобы показать примеры структуры данных.



Диаграмма пакетов

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



Диаграмма составной структуры

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

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



Диаграмма профилей

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



Диаграмма прецедентов

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



Диаграмма деятельности

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



Диаграмма состояний

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



Диаграмма последовательности

Диаграмма последовательности моделирует взаимодействие объектов на основе временной последовательности. Она показывает, как одни объекты взаимодействуют с другими в конкретном прецеденте.



Диаграмма Коммуникации

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



Диаграмма обзора взаимодействия

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



Временная диаграмма

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




Зачем в UML столько диаграмм?

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



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

Для тех, кому лень читать: youtu.be/0I9aIP5gKCg

Аве!
Подробнее..

Горячая летняя пора митапов список из 32 событий на неделе и как получать его обновления

14.06.2020 12:18:17 | Автор: admin

Привет! Собрали события недели в один список, и сами немного удивились количеству митапов про микросервисы и про данные. А еще собрали способы получать обновления, потому что список мероприятий ниже станет неполным уже буквально завтра, когда команда сайта https://meetups-online.ru/ найдет и добавит еще пару ивентов.


Так вот, обновления можно получать из RSS, если есть привычка пользоваться ими.


Перетаскивать события из RSS в телеграм может этот бот: @EventMonkeyBot


Еще один бот, но с другой механикой может присылать мероприятия по выбранным тэгам: @meetup_finder_bot его сделали ребята-подростки, пока учились работать в команде.



Хотим разобраться в этом сами и помочь независимым организаторам ИТ-мероприятий: какие форматы мероприятий в сети больше заходят и вообще хочется ли ходить на онлайны этим летом. Поэтому стартовали опрос: как быть с онлайнами летом 2020.
2 минуты на заполнение, не собирает никаких персональных данных. Результаты будут опубликованы на Хабре.

Бэк


15 июня на Java Developer Toolkit 2020 обсудят какие библиотеки и фреймворки наиболее популярны и c каких лучше начать обучение.


A 16 июня для новичков будет Морской бой на Java тренинг по написанию консольной игры.


16 июня Микросервисная архитектура: приключение на 20 минут. Расскажут про проблемы, с которыми можно столкнуться при разработке микросервисов, методы решения, а также вопрос о размере микросервисов.


16 июня Разговор с tech ninja Spatial.io о том как пройти путь от гипотезы до MVP. Сами посиделки будут в spatial.io. Такая вот рекурсия.


16 июня суровые функциональщики обсуждают 2-ю главу замечательной книги "Domain Modeling Made Functional" Understanding the Domain и F#.


18 июня уже 12 по счету Ruby Meetup с темами: PostgreSQL глазами рубиста, паттерн CQRS, наследование как антипаттерн и оптимизация Ruby кода.


18 июня на SA Webinar рассмотрят применение шаблона оркестрации при проектировании микросервисных решений.


18 июня PiterPy Meetup собирает на два основных доклада, несколько коротких лайтнингов и кофе-брейки.


19 июня Микросервисная архитектура в Облаке. Кейс: как компания перевезла микросервисную инфраструктуру из Google Cloud Platform в Яндекс.Облако


20 июня Воркшоп по созданию навыков Алисы на Node.js можно сделать свой первый навык с нуля за 3 часа.


DevOps


15 июня на Основы Red Hat Openshift для разработчиков. На мероприятии отвечают на вопрос как создать кластер Openshift за несколько минут в IBM Cloud.


16 июня будет трансляция, на которой вы сможете задать вопросы архитектору Яндекс.Облака: Архитектура сервиса IAM, его принципы работы


16 июня традиционный Постгрес-вторник


16 июня Лекция о возможностях Ansible: Быстрая подготовка окружений для хакатонов и геймджемов.


17 июня Вебинар про Rancher: использование Kubernetes в Телеком-секторе.


18 июня представят новый инструмент в DevOps вселенной JFrog Container Registry. Приходите посмотреть и обсудить чем он отличается от стопятсот существущих registries с Барухом Садогурским.


19 июня на INFOSTART MEETUP в Новосибирске. Будут говорить про Highload-оптимизацию, DevOps в 1С, управление командой, обмен данными.


19 июня на Data platform meetup можно поговорить с экспертами команды DWH из Тинькофф.


Data Science


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


18 июня Опыт реализованных проектов с речевыми технологиями. Будет полезно, если ищете как сократить расходы и увеличить конверсии, связанные с общением по телефону.


18 июня на VK lab talks 4 доклада про искусственный интеллект, например 'В чём смысл жизни Долорес, робота из Поддержки?'.


Процессы


(Уже идет) 14 июня Конференция International Womens Day в Ростове-на-Дону Разные темы от рисков на проекте до OpenCV.


16 июня AgilePub LeanCoffee #7 Встреча проходит без заранее сформированной повестки. Все идеи и вопросы участники генерируют во время мероприятия.


19 июня Wrike Pyjamatalks: Vitaly Friedman встречи с разработчиками на английском. Можно подтянуть язык сидя дома в пижаме.


Фронт


17 июня можно познакомиться с фреймворком Vue.JS, узнать его сильные и слабые стороны на тренинге Vue.JS. Быстрый старт.


19 июня занятие для новичков: WebAssembly: что и как. Пробуют использовать WebAssembly с Node.js. Также смотрят дизайн, возможности, семантику, JavaScript API, Modules и изучают примеры использования.


QA


19 июня 2 отличных события: выбрать один или успеть на оба? Разница во времени позволяет.


QA-специалисты Таганрога говорят об актуальных проблемах: мутные требования, одинаковые статьи, плодящие баги процессы.


QA Guild в Новосибирске: Роль и задачи QA Leada. Поговорят про лидов, что они делают, зачем они это делают, что они могут и не могут, и что на самом деле должны и кому. (Время по Нск!)


Mobile


17 июня Android 11 с комментариями экспертов 4 интересных гостя поговорят о новинках.


Безопасность


16 июня Безопасность WEB: Уязвимости SSRF Случаи с подделкой запросов со стороны сервера.


Дизайн продуктов


19 июня Синтаксис в интерфейсе и как его правильно нарушать Подробно о понятии conversational design. А еще, что такое синтаксис интерфейса и какие в нем есть правила.


Хард


19 июня Я.Железо: цифровая обработка сигналов Два часа в прямом эфире разработчик аппаратной части Яндекс.Станции Геннадий Крэйл Круглов будет рассказывать об основах ЦОС и показывать картинки на осциллографе.

Подробнее..

2.07 онлайн-митап про микросервисы и Unit-тесты

24.06.2020 20:23:04 | Автор: admin
В четверг 2 июля собираемся обсудить очередной опыт распила монолита и рассказать, как Unit-тестирование сокращает время разработки. Старт в 16:00 мск, в 17:00 по Ижевску.

Участие бесплатно, нужна регистрация.

Упрощаем себе жизнь с помощью Unit-тестирования


Юнит-тесты повышают скорость разработки согласны?

  • расскажу, почему нетестируемые проекты увеличивают сроки релизов;
  • приведу аргументы в пользу написания юнит-тестов. Рассмотрим, почему хороший дизайн тестируемый, а обратное неверно;
  • плохие юнит-тесты хуже, чем ничего. Поговорим про требования к юнит-тестам. Например, почему важна изолированность или скорость выполнения тестов;
  • расскажу про лучшие практики юнит-тестирования с примерами на NUnit.



Как отпилить часть монолита и не сойти с ума


Я расскажу о нашем опыте отделения части функциональности сервиса в отдельный микросервис:

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


Вход свободный, не забудьте зарегистрироваться, чтобы получить ссылку. Если не хватило вводных welcome в комментарии.

А ещё смотрите там же на сайте анонс митапа по управлению проектами 9 июля.

И приходите, будем рады!
Подробнее..

Recovery mode 2.07 онлайн-митап про микросервисы и Unit-тесты

25.06.2020 00:10:20 | Автор: admin
В четверг 2 июля собираемся обсудить очередной опыт распила монолита и рассказать, как Unit-тестирование сокращает время разработки. Старт в 16:00 мск, в 17:00 по Ижевску.

Участие бесплатно, нужна регистрация.

Упрощаем себе жизнь с помощью Unit-тестирования


Юнит-тесты повышают скорость разработки согласны?

  • расскажу, почему нетестируемые проекты увеличивают сроки релизов;
  • приведу аргументы в пользу написания юнит-тестов. Рассмотрим, почему хороший дизайн тестируемый, а обратное неверно;
  • плохие юнит-тесты хуже, чем ничего. Поговорим про требования к юнит-тестам. Например, почему важна изолированность или скорость выполнения тестов;
  • расскажу про лучшие практики юнит-тестирования с примерами на NUnit.


Как отпилить часть монолита и не сойти с ума


Я расскажу о нашем опыте отделения части функциональности сервиса в отдельный микросервис:

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


Вход свободный, не забудьте зарегистрироваться, чтобы получить ссылку. Если не хватило вводных welcome в комментарии.

А ещё смотрите там же на сайте анонс митапа по управлению проектами 9 июля.

И приходите, будем рады!
Подробнее..

Перевод Что такое Service Mesh?

16.06.2020 16:14:27 | Автор: admin
И снова здравствуйте!.. В преддверии старта курса Архитектор ПО мы подготовили еще один полезный перевод.



Service Mesh это конфигурируемый инфраструктурный уровень с низкой задержкой, который нужен для обработки большого объема сетевых межпроцессных коммуникаций между программными интерфейсами приложения (API). Service Mesh обеспечивает быструю, надёжную и безопасную коммуникацию между контейнеризированными и часто эфемерными сервисами инфраструктуры приложений. Service Mesh предоставляет такие возможности, как обнаружение сервисов, балансировку нагрузки, шифрование, прозрачность, трассируемость, аутентификацию и авторизацию, а также поддержку шаблона автоматического выключения (circuit breaker).
Service Mesh обычно реализуется путем предоставления каждому экземпляру сервиса экземпляра прокси, который называется Sidecar. Sidecar обрабатывают коммуникации между сервисами, производят мониторинг и устраняют проблемы безопасности, то есть все, что может быть абстрагировано от отдельных сервисов. Таким образом, разработчики могут писать, поддерживать и обслуживать код приложения в сервисах, а системные администраторы могут работать с Service Mesh и запускать приложение.

Istio от Google, IBM и Lyft, на данный момент является самый известной Service Mesh-архитектурой. А Kubernetes, который изначально разрабатывался в Google, сейчас является единственным фреймворком для оркестрации контейнеров, который поддерживается Istio. Вендоры пытаются создать коммерческие поддерживаемые версии Istio. Интересно, что нового они смогут привнести в проект с открытым исходным кодом.

Однако Istio это не единственный вариант, поскольку разрабатываются и другие реализации Service Mesh. Паттерн sidecar proxy является наиболее популярной реализацией, как можно судить по проектам Buoyant, HashiCorp, Solo.io и другим. Существуют и альтернативные архитектуры: технологический инструментарий Netflix это один из подходов, где функционал Service Mesh реализуется за счет библиотек Ribbon, Hysterix, Eureka, Archaius, а также таких платформ, как Azure Service Fabric.

Service Mesh также имеет свою собственную терминологию для компонентов-сервисов и функций:

  • Фреймворк оркестрации контейнеров. По мере того, как все больше и больше контейнеров добавляется в инфраструктуру приложения, появляется необходимость в отдельном инструменте для мониторинга и управления контейнерами фреймворке оркестрации контейнеров. Kubernetes плотно занял эту нишу, причем настолько, что даже его основные конкуренты Docker Swarm и Mesosphere DC/OS предлагают в качестве альтернативы интеграцию с Kubernetes.
  • Сервисы и экземпляры (поды Kubernetes). Экземпляр это единственная запущенная копия микросервиса. Иногда один экземпляр это один контейнер. В Kubernetes экземпляр состоит из небольшой группы независимых контейнеров, который называется подом. Клиенты редко обращаются напрямую к экземпляру или поду, чаще они обращаются к сервису, который представляет из себя набор идентичных масштабируемых и отказоустойчивых экземпляров или подов (реплик).
  • Sidecar Proxy. Sidecar Proxy работает с одним экземпляром или подом. Смысл Sidecar Proxy в том, чтобы направлять или проксировать трафик, приходящий от контейнера, с которым он работает, и обратный трафик. Sidecar взаимодействует с другими Sidecar Proxy и управляется фреймворком оркестрации. Многие реализации Service Mesh используют Sidecar Proxy для перехвата и управления всем входящим и исходящим трафиком экземпляра или пода.
  • Обнаружение сервисов. Когда экземпляру нужно взаимодействовать с другим сервисом, ему нужно найти (обнаружить) исправный и доступный экземпляр другого сервиса. Как правило экземпляр выполняет поиск по DNS. Фреймворк оркестрации контейнеров хранит список экземпляров, которые готовы к получению запросов, и предоставляет интерфейс для DNS-запросов.
  • Балансировка нагрузки. Большинство фреймворков оркестрации контейнеров обеспечивают балансировку нагрузки на 4 уровне (транспортном). Service Mesh реализует более сложную балансировку нагрузки на 7 уровне (прикладном), богатую алгоритмами и более эффективную в вопросе управления трафиком. Параметры балансировки нагрузки могут быть изменены с помощью API, что позволяет оркестрировать сине-зеленое или канареечное развертывание.
  • Шифрование. Service Mesh может зашифровывать и расшифровывать запросы и ответы, снимая это бремя с сервисов. Service Mesh также может повысить производительность за счет приоритезации или переиспользования существующих постоянных соединений, что снижает необходимость в дорогих вычислениях для создания новых соединений. Наиболее распространенной реализацией шифрования трафика является mutual TLS (mTLS), где инфраструктура открытых ключей (PKI) генерирует и распространяет сертификаты и ключи для использования их в Sidecar Proxy.
  • Аутентификация и авторизация. Service Mesh может авторизовывать и аутентифицировать запросы сделанные снаружи или изнутри приложения, отправляя экземплярам только валидированные запросы.
  • Поддержка шаблона автоматического выключения. Service Mesh поддерживает шаблон автоматического выключения, который изолирует нездоровые экземпляры, а затем постепенно возвращает их в пул здоровых экземпляров при необходимости.

Та часть приложения Service Mesh, которая управляет сетевым трафиком между экземплярами называется Data Plane. Создание и развертывание конфигурации, которая управляет поведением Data Plane, выполняется с помощью отдельной Control Plane. Control Plane обычно включает в себя или спроектирована таким образом, чтобы подключаться к API, CLI или GUI для управления приложением.


Control Plane в Service Mesh распределяет конфигурацию между Sidecar Proxy и Data Plane.

Часто архитектура Service Mesh применяется для решения сложных операционных задач с использованием контейнеров и микросервисов. Пионерами в области микросервисов являются такие компании как Lyft, Netflix и Twitter, которые предоставляют стабильно работающие сервисы миллионам пользователей по всему миру. (Здесь вы можете познакомиться с подробным описанием некоторых архитектурных задач, с которыми столкнулся Netflix). Для менее требовательных прикладных задач скорее всего будет достаточно более простых архитектур.

Архитектура Service Mesh вряд ли когда-нибудь станет ответом на все вопросы, связанные с работой приложений и их доставкой. Архитекторы и разработчики обладают огромным арсеналом инструментов, и только один из них молоток, который среди множества задач должен решать лишь одну забивать гвозди. Microservices Reference Architecture от NGINX, например, включает в себя несколько различных моделей, которые дают непрерывный спектр подходов к решению задач с помощью микросервисов.

Элементы, которые объединяются в архитектуре Service Mesh, такие как NGINX, контейнеры, Kubernetes и микросервисы в качестве архитектурного подхода, могут быть не менее продуктивно использованы и в реализациях без Service Mesh. Например, Istio был разработан как полноценная архитектура Service Mesh, но модульность говорит о том, что разработчики могут выбирать и применять только необходимые им компоненты технологий. Помня об этом, необходимо сформировать четкое понимание концепции Service Mesh, даже если вы не уверены в том, что сможете когда-нибудь полноценно ее реализовать в приложении.



Модульные монолиты и DDD


Подробнее..

.NET Core Взаимодействие микросервисов через Web api

19.06.2020 12:20:11 | Автор: admin

Введение



Практически все, кто имел дело с микросервисами в .NET Core, наверняка знают книгу Кристиана Хорсдала Микросервисы на платформе .NET. Здесь прекрасно описаны подходы к построению приложения на основе микросервисов, подробно рассмотрены вопросы мониторинга, журналирования, управления доступом. Единственное, чего не хватает это инструмента автоматизации взаимодействия между микросервисами.

При обычном подходе при разработке микросервиса параллельно разрабатывается web-клиент для него. И каждый раз, когда меняется web-интерфейс микросервиса, приходится затрачивать дополнительные усилия для соответствующих изменений web-клиента. Идея генерировать пару web-api/web-клиент с использованием OpenNET тоже достаточно трудоемка, хотелось бы чего-то более прозрачного для разработчика.

Итак, при альтернативном подходе в разработке нашего приложения хотелось бы:
Структуру микросервиса описывать интерфейсом с использованием атрибутов, описывающих тип метода, маршрут и способ передачи параметров, как это делается в MVC.
Функциональность микросервиса разрабатывается исключительно в классе,
реализующим этот интерфейс. Публикация конечных точек микросервиса должна быть автоматической, не требующей сложных настроек.
Web-клиент для микросервиса должен генерироваться автоматически на основе интерфейса и предоставляться через Dependency Injection.
Должен быть механизм организации редиректов на конечные точки микросервисов из главного приложения, взаимодействующего с пользовательским интерфейсом.

В соответствии с этим критериями разработан Nuget-пакет Shed.CoreKit.WebApi. В дополнение к нему создан вспомогательный пакет Shed.CoreKit.WebApi.Abstractions, содержащий атрибуты и классы, которые могут быть использованы при разработке общих проектов-сборок, где не требуется функциональность основного пакета.

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

Здесь и далее мы будем использовать следующую терминологию:
Микросервис приложение (проект) ASP.NET Core, которое может запускаться консольно, под Internet Information Services (IIS) или в Docker-контейнере.
Интерфейс сущность .NET, набор методов и свойств без реализации.
Конечная точка путь к корню приложения микросервиса или реализации интерфейса. Примеры: localhost:5001, localhost:5000/products
Маршрут путь к методу интерфейса от конечной точки. Может определяться по умолчанию так же как в MVC или устанавливаться при помощи атрибута.

Структура приложения MicroCommerce



  1. ProductCatalog микросервис, предоставляющий сведения о продуктах.
  2. ShoppingCart микросервис, предоставляющий сведения о покупках пользователя, а также возможность добавлять/удалять покупки. При изменении состояния корзины пользователя генерируются события для уведомления других микросервисов.
  3. ActivityLogger микросервис, собирающий сведения о событиях других микросервисов. Предоставляет конечную точку для получения логов.
  4. WebUI Пользовательский интерфейс приложения, должен быть реализован в виде Single Page Application.
  5. Interfaces интерфейсы микросервисов и классы-модели.
  6. Middleware общая функциональность для всех микросервисов


Разработка приложения MicroCommerce




Создаем пустое решение .Net Core. Добавляем в него проект WebUI как пустой ASP.NET Core WebApplication. Далее добавляем проекты микросервисов ProductCatalog, ShoppingCart, ActivityLog, также как пустые проекты ASP.NET Core WebApplication. В заключение добавляем две библиотеки классов Interfaces и Middleware.

1. Interfaces интерфейсы микросервисов и классы-модели



Подключаем к проекту Nuget-пакет Shed.CoreKit.WebApi.Abstractions.

Добавляем интерфейс IProductCatalog и модели для него:
//// Interfaces/IProductCatalog.cs//using MicroCommerce.Models;using Shed.CoreKit.WebApi;using System;using System.Collections.Generic;namespace MicroCommerce{    public interface IProductCatalog    {        IEnumerable<Product> Get();        [Route("get/{productId}")]        public Product Get(Guid productId);    }}


//// Interfaces/Models/Product.cs//using System;namespace MicroCommerce.Models{    public class Product    {        public Guid Id { get; set; }        public string Name { get; set; }        public Product Clone()        {            return new Product            {                Id = Id,                Name = Name            };        }    }}

Использование атрибута Route ничем не отличается от аналогичного в ASP.NET Core MVC, но нужно помнить, что этот атрибут должен быть из namespace Shed.CoreKit.WebApi, и никакого другого. То же самое касается атрибутов HttpGet, HttpPut, HttpPost, HttpPatch, HttpDelete, а также FromBody в случае их применения.
Правила применения атрибутов типа Http[Methodname] такие же, как в MVC, то есть если префикс имени метода интерфейса совпадает с именем требуемого Http-метода, то не нужно его дополнительно определять, иначе используем соответствующий атрибут.
Атрибут FromBody применяется к параметру метода, если этот параметр должен извлекаться из тела запроса. Замечу, что как и ASP.NET Core MVC, его нужно указывать всегда, никаких правил по умолчанию нет. И в параметрах метода может быть только один параметр с этим атрибутом.

Добавляем интерфейс IShoppingCart и модели для него
//// Interfaces/IShoppingCart.cs//using MicroCommerce.Models;using Shed.CoreKit.WebApi;using System;using System.Collections.Generic;namespace MicroCommerce{    public interface IShoppingCart    {        Cart Get();        [HttpPut, Route("addorder/{productId}/{qty}")]        Cart AddOrder(Guid productId, int qty);        Cart DeleteOrder(Guid orderId);        [Route("getevents/{timestamp}")]        IEnumerable<CartEvent> GetCartEvents(long timestamp);    }}


//// Interfaces/IProductCatalog/Order.cs//using System;namespace MicroCommerce.Models{    public class Order    {        public Guid Id { get; set; }        public Product Product { get; set; }        public int Quantity { get; set; }        public Order Clone()        {            return new Order            {                Id = Id,                Product = Product.Clone(),                Quantity = Quantity            };        }    }}


//// Interfaces/Models/Cart.cs//using System;namespace MicroCommerce.Models{    public class Cart    {        public IEnumerable<Order> Orders { get; set; }    }}


//// Interfaces/Models/CartEvent.cs//using System;namespace MicroCommerce.Models{    public class CartEvent: EventBase    {        public CartEventTypeEnum Type { get; set; }        public Order Order { get; set; }    }}


//// Interfaces/Models/CartEventTypeEnum.cs//using System;namespace MicroCommerce.Models{    public enum CartEventTypeEnum    {        OrderAdded,        OrderChanged,        OrderRemoved    }}


//// Interfaces/Models/EventBase.cs//using System;namespace MicroCommerce.Models{    public abstract class EventBase    {        private static long TimestampBase;        static EventBase()        {            TimestampBase = new DateTime(2000, 1, 1).Ticks;        }        public long Timestamp { get; set; }                public DateTime Time { get; set; }        public EventBase()        {            Time = DateTime.Now;            Timestamp = Time.Ticks - TimestampBase;        }    }}

Пара слов о базовом типе событий EventBase. При публикации событий используем подход, описанный в книге, т.е. любое событие содержит метку времени создания Timestamp, при опросе источника события слушатель передает последний полученный timestamp. К сожалению, тип long некорректно преобразуется в в тип Number javascript при больших значениях, поэтому мы используем некую хитрость вычитаем timestamp базовой даты (Timestamp = Time.Ticks TimestampBase). Конкретное значение базовой даты абсолютно неважно.

Добавляем интерфейс IActivityLogger и модели для него
//// Interfaces/IActivityLogger.cs//using MicroCommerce.Models;using System.Collections.Generic;namespace MicroCommerce{    public interface IActivityLogger    {        IEnumerable<LogEvent> Get(long timestamp);    }}


//// Interfaces/Models/LogEvent.cs//namespace MicroCommerce.Models{    public class LogEvent: EventBase    {        public string Description { get; set; }    }}


2. Микросервис ProductCatalog


Открываем Properties/launchSettings.json, привязываем проект к порту 5001.
{  "iisSettings": {    "windowsAuthentication": false,    "anonymousAuthentication": true,    "iisExpress": {      "applicationUrl": "http://localhost:60670",      "sslPort": 0    }  },  "profiles": {    "MicroCommerce.ProductCatalog": {      "commandName": "Project",      "environmentVariables": {        "ASPNETCORE_ENVIRONMENT": "Development"      },      "applicationUrl": "http://localhost:5001"    }  }}

Подключаем к проекту Nuget- пакет Shed.CoreKit.WebApi и ссылки на проекты Interfaces и Middleware. О Middleware будет более подробно рассказано ниже.

Добавляем реализацию интерфейса IProductCatalog
//// ProductCatalog/ProductCatalog.cs//using MicroCommerce.Models;using System;using System.Collections.Generic;using System.Linq;namespace MicroCommerce.ProductCatalog{    public class ProductCatalogImpl : IProductCatalog    {        private Product[] _products = new[]        {            new Product{ Id = new Guid("6BF3A1CE-1239-4528-8924-A56FF6527595"), Name = "T-shirt" },            new Product{ Id = new Guid("6BF3A1CE-1239-4528-8924-A56FF6527596"), Name = "Hoodie" },            new Product{ Id = new Guid("6BF3A1CE-1239-4528-8924-A56FF6527597"), Name = "Trousers" }        };        public IEnumerable<Product> Get()        {            return _products;        }        public Product Get(Guid productId)        {            return _products.FirstOrDefault(p => p.Id == productId);        }    }}


Каталог продуктов храним в статическом поле, для упрощения примера. Конечно же, в реальном приложении нужно использовать какое-то другое хранилище, которое можно получить как зависимость через Dependency Injection.

Теперь эту реализацию нужно подключить как конечную точку. Если бы мы использовали традиционный подход, мы должны были бы использовать инфраструктуру MVC, то есть создать контроллер, передать ему нашу реализацию как зависимость, настроить роутинг и т.д. С использованием Nuget-пакета Shed.CoreKit.WebApi это делается гораздо проще. Достаточно зарегистрировать нашу реализацию в Dependency Injection (services.AddTransient<IProductCatalog, ProductCatalogImpl>()), затем объявляем ее как конечную точку (app.UseWebApiEndpoint()) при помощи метода-расширителя UseWebApiEndpoint из пакета Shed.CoreKit.WebApi. Это делается в Setup

//// ProductCatalog/Setup.cs//using MicroCommerce.Middleware;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;using Shed.CoreKit.WebApi;namespace MicroCommerce.ProductCatalog{    public class Startup    {        public void ConfigureServices(IServiceCollection services)        {            services.AddCorrelationToken();            services.AddCors();            // регистрируем реализацию как зависимость в контейнере IoC            services.AddTransient<IProductCatalog, ProductCatalogImpl>();            services.AddLogging(builder => builder.AddConsole());            services.AddRequestLogging();        }        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)        {            if (env.IsDevelopment())            {                app.UseDeveloperExceptionPage();            }            app.UseCorrelationToken();            app.UseRequestLogging();            app.UseCors(builder =>            {                builder                    .AllowAnyOrigin()                    .AllowAnyMethod()                    .AllowAnyHeader();            });            // привязываем реализацию к конечной точке            app.UseWebApiEndpoint<IProductCatalog>();        }    }}


Это приводит к тому, что в микросервисе появляются методы:
localhost:5001/get
localhost:5001/get/Метод UseWebApiEndpoint может принимать необязательный параметр root.
Если мы подключим конечную точку таким образом: app.UseWebApiEndpoint(products)
то конечная точка микросервиса будет выглядеть вот так:
localhost:5001/products/get
Это может быть полезно, если у нас появится необходимость подключить к микросервису несколько интерфейсов.

Это все что нужно сделать. Можно запустить микросервис и протестировать его методы.

Остальной код в Setup настраивает и подключает дополнительные возможности.
Пара services.AddCors() / app.UseCors(...) разрешает использование кросс-доменных запросов в проекте. Это необходимо при редиректах запросов со стороны UI.
Пара services.AddCorrelationToken() / app.UseCorrelationToken() подключает использование токенов корреляции при журналировании запросов, как это описано в книге Кристиана Хорсдала. Мы дополнительно обсудим это позже.
И наконец, пара services.AddRequestLogging() / app.UseRequestLogging() подключает журналирование запросов из проекта Middleware. К этому тоже вернемся позже.

3. Микросервис ShoppingCart


Привязываем проект к порту 5002 аналогично ProductCatalog.

Подключаем к проекту Nuget- пакет Shed.CoreKit.WebApi и ссылки на проекты Interfaces и Middleware.

Добавляем реализацию интерфейса IShoppingCart.
//// ShoppingCart/ShoppingCart.cs//using MicroCommerce.Models;using System;using System.Collections.Generic;using System.Linq;namespace MicroCommerce.ShoppingCart{    public class ShoppingCartImpl : IShoppingCart    {        private static List<Order> _orders = new List<Order>();        private static List<CartEvent> _events = new List<CartEvent>();        private IProductCatalog _catalog;        public ShoppingCartImpl(IProductCatalog catalog)        {            _catalog = catalog;        }        public Cart AddOrder(Guid productId, int qty)        {            var order = _orders.FirstOrDefault(i => i.Product.Id == productId);            if(order != null)            {                order.Quantity += qty;                CreateEvent(CartEventTypeEnum.OrderChanged, order);            }            else            {                var product = _catalog.Get(productId);                if (product != null)                {                    order = new Order                    {                        Id = Guid.NewGuid(),                        Product = product,                        Quantity = qty                    };                    _orders.Add(order);                    CreateEvent(CartEventTypeEnum.OrderAdded, order);                }            }            return Get();        }        public Cart DeleteOrder(Guid orderId)        {            var order = _orders.FirstOrDefault(i => i.Id == orderId);            if(order != null)            {                _orders.Remove(order);                CreateEvent(CartEventTypeEnum.OrderRemoved, order);            }            return Get();        }        public Cart Get()        {            return new Cart            {                Orders = _orders            };        }        public IEnumerable<CartEvent> GetCartEvents(long timestamp)        {            return _events.Where(e => e.Timestamp > timestamp);        }        private void CreateEvent(CartEventTypeEnum type, Order order)        {            _events.Add(new CartEvent            {                Timestamp = DateTime.Now.Ticks,                Time = DateTime.Now,                Order = order.Clone(),                Type = type            });        }    }}

Здесь, как и в ProductCatalog, используем статические поля как хранилища. Но этот микросервис еще использует вызовы к ProductCatalog для получения информации о продукте, поэтому ссылку на IProductCatalog передаем в конструктор как зависимость.
Теперь эту зависимость нужно определить в DI, и мы используем для этого метод-расширитель AddWebApiEndpoints из пакета Shed.CoreKit.WebApi. Этот метод регистрирует в DI фабрику-генератор WebApi-клиентов для интерфейса IProductCatalog.
При генерировании WebApi-клиента фабрика использует зависимость System.Net.Http.HttpClient. Если в приложении требуются какие-то специальные настройки для HttpClient (учетные данные, специальные заголовки/токены), это можно сделать при регистрации HttpClient в DI.

//// ShoppingCart/Settings.cs//using MicroCommerce.Middleware;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;using Shed.CoreKit.WebApi;using System.Net.Http;namespace MicroCommerce.ShoppingCart{    public class Startup    {        public void ConfigureServices(IServiceCollection services)        {            services.AddCorrelationToken();            services.AddCors();            services.AddTransient<IShoppingCart, ShoppingCartImpl>();            services.AddTransient<HttpClient>();            services.AddWebApiEndpoints(new WebApiEndpoint<IProductCatalog>(new System.Uri("http://localhost:5001")));            services.AddLogging(builder => builder.AddConsole());            services.AddRequestLogging();        }        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)        {            if (env.IsDevelopment())            {                app.UseDeveloperExceptionPage();            }            app.UseCorrelationToken();            app.UseRequestLogging("getevents");            app.UseCors(builder =>            {                builder                    .AllowAnyOrigin()                    .AllowAnyMethod()                    .AllowAnyHeader();            });            app.UseWebApiEndpoint<IShoppingCart>();        }    }}

Метод AddWebApiEndpoints может принимать произвольное количество параметров, поэтому возможно настроить все зависимости одним вызовом этого метода.
В остальном все настройки аналогичны ProductCatalog.

4. Микросервис ActivityLogger


Привязываем проект к порту 5003 аналогично ProductCatalog.

Подключаем к проекту Nuget- пакет Shed.CoreKit.WebApi и ссылки на проекты Interfaces и Middleware.

Добавляем реализацию интерфейса IActivityLogger.
//// ActivityLogger/ActivityLogger.cs//using MicroCommerce;using MicroCommerce.Models;using System.Collections.Generic;using System.Linq;namespace ActivityLogger{    public class ActivityLoggerImpl : IActivityLogger    {        private IShoppingCart _shoppingCart;        private static long timestamp;        private static List<LogEvent> _log = new List<LogEvent>();        public ActivityLoggerImpl(IShoppingCart shoppingCart)        {            _shoppingCart = shoppingCart;        }        public IEnumerable<LogEvent> Get(long timestamp)        {            return _log.Where(i => i.Timestamp > timestamp);        }        public void ReceiveEvents()        {            var cartEvents = _shoppingCart.GetCartEvents(timestamp);            if(cartEvents.Count() > 0)            {                timestamp = cartEvents.Max(c => c.Timestamp);                _log.AddRange(cartEvents.Select(e => new LogEvent                {                    Description = $"{GetEventDesc(e.Type)}: '{e.Order.Product.Name} ({e.Order.Quantity})'"                }));            }        }        private string GetEventDesc(CartEventTypeEnum type)        {            switch (type)            {                case CartEventTypeEnum.OrderAdded: return "order added";                case CartEventTypeEnum.OrderChanged: return "order changed";                case CartEventTypeEnum.OrderRemoved: return "order removed";                default: return "unknown operation";            }        }    }}

Здесь также используется зависимость от другого микросервиса (IShoppingCart). Но одна из задач этого сервиса слушать события других сервисов, поэтому добавляем дополнительный метод ReceiveEvents(), который будем вызывать из планировщика. Мы его добавим к проекту дополнительно.
//// ActivityLogger/Scheduler.cs//using Microsoft.Extensions.Hosting;using System;using System.Threading;using System.Threading.Tasks;namespace ActivityLogger{    public class Scheduler : BackgroundService    {        private IServiceProvider ServiceProvider;        public Scheduler(IServiceProvider serviceProvider)        {            ServiceProvider = serviceProvider;        }        protected override Task ExecuteAsync(CancellationToken stoppingToken)        {            Timer timer = new Timer(new TimerCallback(PollEvents), stoppingToken, 2000, 2000);            return Task.CompletedTask;        }        private void PollEvents(object state)        {            try            {                var logger = ServiceProvider.GetService(typeof(MicroCommerce.IActivityLogger)) as ActivityLoggerImpl;                logger.ReceiveEvents();            }            catch            {            }        }    }}

Настройки проекта аналогичны предыдущему пункту.
Дополнительно нужно только подключить добавленный ранее планировщик.

//// ActivityLogger/Setup.cs//using System.Net.Http;using MicroCommerce;using MicroCommerce.Middleware;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;using Shed.CoreKit.WebApi;namespace ActivityLogger{    public class Startup    {        public void ConfigureServices(IServiceCollection services)        {            services.AddCorrelationToken();            services.AddCors();            services.AddTransient<IActivityLogger, ActivityLoggerImpl>();            services.AddTransient<HttpClient>();            services.AddWebApiEndpoints(new WebApiEndpoint<IShoppingCart>(new System.Uri("http://localhost:5002")));            // регистрируем планировщик (запустится при старте приложения, больше ничего делать не нужно)            services.AddHostedService<Scheduler>();            services.AddLogging(builder => builder.AddConsole());            services.AddRequestLogging();        }        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)        {            if (env.IsDevelopment())            {                app.UseDeveloperExceptionPage();            }            app.UseCorrelationToken();            app.UseRequestLogging("get");            app.UseCors(builder =>            {                builder                    .AllowAnyOrigin()                    .AllowAnyMethod()                    .AllowAnyHeader();            });            app.UseWebApiEndpoint<IActivityLogger>();        }    }}


5. WebUI пользовательский интерфейс.


Привязываем проект к порту 5000 аналогично ProductCatalog.

Подключаем к проекту Nuget- пакет Shed.CoreKit.WebApi. Cсылки на проекты Interfaces и Middleware нужно подключать только в том случае, если мы в этом проекте собираемся использовать вызовы к микросервисам

Строго говоря, это обычный ASP.NET проект и в нем возможно использование MVC, т.е. для взаимодействия с UI мы можем создать контроллеры, которые используют наши интерфейсы микросервисов как зависимости. Но интереснее и практичнее оставить за этим проектом только предоставление пользовательского интерфейса, а все обращения со стороны UI перенаправлять непосредственно микросервисам. Для этого используется метод-расширитель UseWebApiRedirect из пакета Shed.CoreKit.WebApi
//// WebUI/Setup.cs//using MicroCommerce.Interfaces;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Shed.CoreKit.WebApi;using System.Net.Http;namespace MicroCommerce.Web{    public class Startup    {        public void ConfigureServices(IServiceCollection services)        {        }        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)        {            if (env.IsDevelopment())            {                app.UseDeveloperExceptionPage();            }            app.Use(async (context, next) =>            {                //  when root calls, the start page will be returned                if(string.IsNullOrEmpty(context.Request.Path.Value.Trim('/')))                {                    context.Request.Path = "/index.html";                }                await next();            });            app.UseStaticFiles();            // редиректы на микросервисы            app.UseWebApiRedirect("api/products", new WebApiEndpoint<IProductCatalog>(new System.Uri("http://localhost:5001")));            app.UseWebApiRedirect("api/orders", new WebApiEndpoint<IShoppingCart>(new System.Uri("http://localhost:5002")));            app.UseWebApiRedirect("api/logs", new WebApiEndpoint<IActivityLogger>(new System.Uri("http://localhost:5003")));        }    }}

Все очень просто. Теперь если со стороны UI придет, например, запрос к http://localhost:5000/api/products/get, он будет автоматически перенаправлен на http://localhost:5001/get. Конечно же, для этого микросервисы должны разрешать кросс-доменные запросы, но мы разрешили это ранее (см. CORS в реализации микросервисов).

Теперь осталось только разработать пользовательский интерфейс, и лучше всего для этого подходит Single Page Application. Можно использовать Angular или React, но мы просто создадим маленькую страничку с использованием готовой темы bootstrap и фреймворка knockoutjs.
<!DOCTYPE html><!-- WebUI/wwwroot/index.html --><html><head>    <meta charset="utf-8" />    <title></title>    <link rel="stylesheet" href="http://personeltest.ru/aways/cdnjs.cloudflare.com/ajax/libs/bootswatch/4.5.0/materia/bootstrap.min.css" />"    <style type="text/css">        body {            background-color: #0094ff;        }        .panel {            background-color: #FFFFFF;            margin-top:20px;            padding:10px;            border-radius: 4px;        }        .table .desc {            vertical-align: middle;            font-weight:bold;        }        .table .actions {            text-align:right;            white-space:nowrap;            width:40px;        }    </style>    <script src="http://personeltest.ru/aways/code.jquery.com/jquery-3.5.1.min.js"            integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="            crossorigin="anonymous"></script>    <script src="http://personeltest.ru/aways/cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.min.js"></script>    <script src="../index.js"></script></head><body>    <div class="container">        <div class="row">            <div class="col-12">                <div class="panel panel-heading">                    <div class="panel-heading">                        <h1>MicroCommerce</h1>                    </div>                </div>            </div>            <div class="col-xs-12 col-md-6">                <div class="panel panel-default">                    <h2>All products</h2>                    <table class="table table-bordered" data-bind="foreach:products">                        <tr>                            <td data-bind="text:name"></td>                            <td class="actions">                                <a class="btn btn-primary" data-bind="click:function(){$parent.addorder(id, 1);}">ADD</a>                            </td>                        </tr>                    </table>                </div>            </div>            <div class="col-xs-12 col-md-6">                <div class="panel panel-default" data-bind="visible:shoppingCart()">                    <h2>Shopping cart</h2>                    <table class="table table-bordered" data-bind="foreach:shoppingCart().orders">                        <tr>                            <td data-bind="text:product.name"></td>                            <td class="actions" data-bind="text:quantity"></td>                            <td class="actions">                                <a class="btn btn-primary" data-bind="click:function(){$parent.delorder(id);}">DELETE</a>                            </td>                        </tr>                    </table>                </div>            </div>            <div class="col-12">                <div class="panel panel-default">                    <h2>Operations history</h2>                    <!-- ko foreach:logs -->                    <div class="log-item">                        <span data-bind="text:time"></span>                        <span data-bind="text:description"></span>                    </div>                    <!-- /ko -->                </div>            </div>        </div>    </div>    <script src="http://personeltest.ru/aways/stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>    <script>        var model = new IndexModel();        ko.applyBindings(model);    </script></body></html>


//// WebUI/wwwroot/index.js//function request(url, method, data) {    return $.ajax({        cache: false,        dataType: 'json',        url: url,        data: data ? JSON.stringify(data) : null,        method: method,        contentType: 'application/json'    });}function IndexModel() {    this.products = ko.observableArray([]);    this.shoppingCart = ko.observableArray(null);    this.logs = ko.observableArray([]);    var _this = this;    this.getproducts = function () {        request('/api/products/get', 'GET')            .done(function (products) {                _this.products(products);                console.log("get products: ", products);            }).fail(function (err) {                console.log("get products error: ", err);            });    };    this.getcart = function () {        request('/api/orders/get', 'GET')            .done(function (cart) {                _this.shoppingCart(cart);                console.log("get cart: ", cart);            }).fail(function (err) {                console.log("get cart error: ", err);            });    };    this.addorder = function (id, qty) {        request(`/api/orders/addorder/${id}/${qty}`, 'PUT')            .done(function (cart) {                _this.shoppingCart(cart);                console.log("add order: ", cart);            }).fail(function (err) {                console.log("add order error: ", err);            });    };    this.delorder = function (id) {        request(`/api/orders/deleteorder?orderId=${id}`, 'DELETE')            .done(function (cart) {                _this.shoppingCart(cart);                console.log("del order: ", cart);            }).fail(function (err) {                console.log("del order error: ", err);            });    };    this.timestamp = Number(0);    this.updateLogsInProgress = false;    this.updatelogs = function () {        if (_this.updateLogsInProgress)            return;        _this.updateLogsInProgress = true;        request(`/api/logs/get?timestamp=${_this.timestamp}`, 'GET')            .done(function (logs) {                if (!logs.length) {                    return;                }                ko.utils.arrayForEach(logs, function (item) {                    _this.logs.push(item);                    _this.timestamp = Math.max(_this.timestamp, Number(item.timestamp));                });                console.log("update logs: ", logs, _this.timestamp);            }).fail(function (err) {                console.log("update logs error: ", err);            }).always(function () { _this.updateLogsInProgress = false; });    };    this.getproducts();    this.getcart();    this.updatelogs();    setInterval(() => _this.updatelogs(), 1000);}

Я не буду подробно объяснять реализацию UI, т.к. это выходит за рамки темы статьи, скажу только, что в javascript-модели определены свойства и коллекции для привязки со стороны HTML-разметки, а также функции, реагирующие на нажатие кнопок для обращения к конечным точкам WebApi, которые незаметно для разработчика перенаправляются к соответствующим микросервисам. Как выглядит пользовательский интерфейс и как он работает мы рассмотрим позднее в разделе Тестирование приложения.

6. Несколько слов об общей функциональности


Мы не затронули в этой статье некоторые другие аспекты разработки приложения, такие как журналирование, мониторинг работоспособности, аутентификация и авторизация. Это все подробно рассмотрено в книге Кристиана Хорсдала и вполне применимо в рамках вышеописанного подхода. Вместе с тем эти аспекты слишком специфичны для для каждого конкретного приложения и не имеет смысла выносить их в Nuget-пакет, лучше просто создать отдельную сборку в рамках приложения. Мы такую сборку создали это Middleware. Для примера просто добавим сюда функциональность для журналирования запросов, которую мы уже подключили при разработке микросервисов (см. пп. 2-4).
//// Middleware/RequestLoggingExt.cs//using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.DependencyInjection;namespace MicroCommerce.Middleware{    public static class RequestLoggingExt    {        private static RequestLoggingOptions Options = new RequestLoggingOptions();        public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder, params string[] exclude)        {            Options.Exclude = exclude;            return builder.UseMiddleware<RequestLoggingMiddleware>();        }        public static IServiceCollection AddRequestLogging(this IServiceCollection services)        {            return services.AddSingleton(Options);        }    }    internal class RequestLoggingMiddleware    {        private readonly RequestDelegate _next;        private readonly ILogger _logger;        private RequestLoggingOptions _options;        public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, RequestLoggingOptions options)        {            _next = next;            _options = options;            _logger = loggerFactory.CreateLogger("LoggingMiddleware");        }        public async Task InvokeAsync(HttpContext context)        {            if(_options.Exclude.Any(i => context.Request.Path.Value.Trim().ToLower().Contains(i)))            {                await _next.Invoke(context);                return;            }            var request = context.Request;            _logger.LogInformation($"Incoming request: {request.Method}, {request.Path}, [{HeadersToString(request.Headers)}]");            await _next.Invoke(context);            var response = context.Response;            _logger.LogInformation($"Outgoing response: {response.StatusCode}, [{HeadersToString(response.Headers)}]");        }        private string HeadersToString(IHeaderDictionary headers)        {            var list = new List<string>();            foreach(var key in headers.Keys)            {                list.Add($"'{key}':[{string.Join(';', headers[key])}]");            }            return string.Join(", ", list);        }    }    internal class RequestLoggingOptions    {        public string[] Exclude = new string[] { };    }}

Пара методов AddRequestLogging() / UseRequestLogging(...) позволяет включить журналирование запросов в микросервисе. Метод UseRequestLogging кроме того может принимать произвольное количество путей-исключений. Мы воспользовались этим в ShoppingCart и в ActivityLogger чтобы исключить из журналирования опросы событий и избежать переполнения логов. Но повторюсь, журналирование, как и любая другай общая функциональность это исключительно зона ответственности разработчиков и реализуется в рамках конкретного проекта.

Тестирование приложения


Запускаем решение, видим слева список продуктов для добавления в корзину, пустую корзину справа и историю операций снизу, тоже пока пустую.


В консолях микросервисов мы видим, что при старте UI уже запросил и получил некоторые данные. Например, для получения списка продуктов был отправлен запрос localhost:5000/api/products/get, который был перенаправлен на localhost:5001/get.





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



Микросервису ShoppingCart отправляется запрос localhost:5002/addorder/

Но поскольку ShoppingCart не хранит список продуктов, сведения о заказанном продукте он получает от ProductCatalog.



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

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

Заключение


Nuget-пакет Shed.CoreKit.WebApi позволяет:
  • полностью сосредоточиться на разработке бизнес-логики приложения, не прилагая дополнительных усилий на вопросы взаимодействия микросервисов;
  • описывать структуру микросервиса интерфейсом .NET и использовать его как при разработке самого микросервиса, так и для генерации Web-клиента (Web-клиент для микросервиса генерируется фабричным методом после регистрации интерфейса в DI и предоставляется как зависимость);
  • регистрировать интерфейсы микросервисов как зависимости в Dependency Injection;
  • организовать перенаправление запросов со стороны Web UI к микросервисам без дополнительных усилий при разработке UI.
Подробнее..

Как быть, когда все советуют растащить проект на микросервисы. А ты не готов

30.06.2020 12:04:28 | Автор: admin
Монолит часто обсуждают в негативном ключе. Но сразу перейти на микросервисы получится не у всех и вот уже не первая команда и компания делятся опытом построения переходного звена: модульной архитектуры. Давайте в деталях посмотрим, как делаются такие проекты.



Недавно я смотрел два доклада на эту тему: от Юлии Николаевой из iSpring и Антона Губарева из Skyeng. Так как с Антоном мы работаем в одной компании, для своего подкаста я решил поговорить с Юлей.



Ниже текстовая расшифровка основных идей из разговора.

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


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

Это произошло с нашим проектом: он стартовал в 2009-м, но долго не было людей и времени, чтобы бороться с неконтролируемым разрастанием кодовой базы. А к 2018-му стало понятно: пора уже как-то реструктуризировать монолит.

Когда встал вопрос, что делать с нашим монолитом, мы, естественно, тоже рассматривали микросервисы. Но У распределенной архитектуры свои накладные расходы. И мы не были к ней готовы. Например, у нас не было команды девопсов от слова совсем.

Не было как такового нормального CI/CD, не было ни докера, ни кубернетеса вообще ничего такого.


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

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

У нас все усугублялось тем, что кусок легаси написан Symfony 1.4 с использованием Propel 2, который не так просто использовать в парадигме DDD (Domain Driven Design). А нам очень хотелось DDD. Для этого хорошо подходит ORM Doctrine, которую к легаси так просто не прикрутишь.

Мы решили скрестить ужа с ежом и теперь живем с двумя фреймворками.


Сейчас я думаю, что можно было пойти другим путем: не прикручивать новый фреймфорк, не прикручивать доктрину, а просто попытаться сделать чистую архитектуру на том, что есть. В основном наша проблема была в том, что бизнес-логика была в Propel Peers, моделях, контроллерах где ее только не было. И можно было, как у ребят из другого выпуска, на старом фреймворке сначала выделить модули, попытаться реализовать архитектуру, а потом уже это все в новый фреймворк перетаскивать. Возможно, так было бы проще и быстрее.


Буквально каждый день, на каждом шагу мы встречали множество вопросов, которые не знали, как решить


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

Параллельно часть команды разработчиков ушла в девопсы.


Они занялись переездом в кубернетес, докер и все такое.

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

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

Это меняет мышление очень сильно. Уже есть такие примеры, что, переделывая какой-то кусочек, его стараются упорядочить и интерфейсами покрыть, чтобы оно было более-менее похоже на чистую архитектуру, чтобы было проще потом вынести.

На все у нас ушло, наверное, три с половиной месяца.


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

И ура! Мы можем писать фичи в 3-4 потока командой из 12 бэкендеров.


Сергей: В PHP мы не можем дать программисту по рукам и запретить использовать какой-то внутренний класс другого модуля. Это же все держится на устных договоренностях внутри команды. Как это все организовать?


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

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

Мы нашли такую утилиту deptrac статический анализатор кода, который помогает контролировать зависимости.


Утилита встроена в наш CI/CD и запускается автоматически: фактически, большая часть договоренностей контролируется с ее помощью. Логические ошибки стараемся отлавливать еще на архитектурном ревью: это встреча, на которой разработчик, которому предстоит пилить фичу, представляет схемы, где все по слоям уже разделено. Там сразу понятно, что в каком контексте, какие взаимосвязи и т.д.

Сергей: А как такую архитектуру мэйнтэйнить?

Юлия: У нас есть статьи по тому, как располагать классы по слоям. Информацию про выделение контекстов очень сложно формализовать, потому что это вещь достаточно специфичная для каждой фичи. Тут каких-то правил не может быть, это просто архитектурный шаблон.

Сергей: БД у нас одна, проект у нас один. Что мне делать, если в моем модуле нужны данные из нескольких других контекстов?

Юлия: Это один из самых сложных вопросов наверное, как в модульной, так и в микросервисной архитектуре. Мы пытались в одном из случаев реализовать объединение данных из разных API: сделали запросы, объединение в памяти, сортировку, фильтрацию. Работало жутко медленно.

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

Сергей: И здесь мы подходим к проблеме с дублированием кода...

Юлия: Дублирование возникает, например, если у нас есть слой, который авторизует операции во всех контекстах и мы его дублируем в каждом контексте. То есть, у нас есть практически одинаковый код, который запрашивает: А есть ли права у пользователей. Но мы считаем, что это достаточно приемлемое дублирование.

Сергей: А что делать, когда одному модулю нужно выполнить действие в другом модуле? Например, при оплате изменить баланс, создать уведомление это все разные контексты. Как в монолите быть с этим?

Юлия: Ты перечислил кейсы, которые хорошо укладываются в событийную модель. У нас много через асинхронные ивенты сделано. Если контекст не должен знать ничего про то, что произойдет в других контекстах, будет событие, которое обработает все заинтересованные в нем лица. Если действие тесно связано с выполняемой операцией и про ее контекст нужно знать, напрямую вызывает метод API.

Все как в микросервисной архитектуре, грубо говоря.


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

Сергей: Но если приложение постоянно усложняется фичами и контекстами, модульный монолит все равно лишь промежуточный шаг к микросервисам?

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

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

P.S. Больше выпусков подкаста Между скобок с интересными людьми из мира PHP можно найти здесь.
Подробнее..

Категории

Последние комментарии

© 2006-2020, personeltest.ru