На рынке сейчас существует два вида организации приложений, о которых мы поговорим в докладе, это:
- монолитная архитектура и ее проблемы;
- и микросервисы – их многие сейчас пробуют использовать или хотят попробовать, но не знают, как. Мы поговорим о том, что это такое, какие у микросервисов плюсы и минусы;
- я расскажу, как применение микросервисов помогло нам повысить эффективность бизнеса.
Монолитная архитектура и ее недостатки
Итак, монолитная архитектура – это архитектура, где приложение представлено в виде единого компонента и представляет собой разрез бизнес-логики, которая модульно прошита.
Все клиенты, как правило, обращаются только к одному приложению.
Казалось бы, если мы сделали приложение, и все работает, то почему бы так дальше и не жить?
Какие проблемы мы выявили в процессе эксплуатации приложения?
- Внеся изменения в одном месте монолитной программы, можно вызвать повреждения в каких-то других ее частях (я думаю, многие в курсе, о чем я сейчас пытаюсь сказать). Все дело в том, что компоненты в монолите могут иметь не всегда очевидные связи. Не всегда можно понять, чем это дальше при изменении может обернуться.
- Попытка изменить что-то в коде может занять массу времени и иметь далеко идущие последствия в плане долгой отладки и разбирательства – почему так произошло.
- Из-за своей сложности монолитные приложения требуют от инженера глубокого понимания внутреннего устройства кода. Это может быть огромное количество легаси, в котором нужно как-то копаться и раскручивать, чтобы внести туда какие-то изменения. Варианта два:
- это документация, которая, как правило, неполная или ее может вообще не быть;
- и второй вариант – это очень долгое погружение человека в проект, поскольку монолит – это достаточно большое приложение.
- Монолитные приложения падают с грохотом и зачастую парализуют полностью бизнес-процессы всей компании.
- С течением времени бизнес растет, у него появляются какие-то новые требования, и иногда приходится переиспользовать текущие наработки в каких-то других проектах или системах. В монолите с этим возникают определенные проблемы – это только дублирование кода решения.
- Разбалансировать нагрузку становится сложнее. Начинают расти затраты на покупку железа, для работы приложения требуются мощные сервера.
- Технологии тоже развиваются – появляются языки либо библиотеки, которые решают текущую задачу эффективнее и быстрее, чем в монолите. С течением времени, как правило, все это начинает тормозить, висеть – настает «красная полоса», когда нужно что-то менять (или людей, или софт).
Микросервисная архитектура
Чтобы побороть минусы монолитной архитектуры, используется подход, который позволяет распиливать большие куски монолита на микросервисы.
Что вообще такое микросервис? Это небольшая программа, запущенная на своем сервере и работающая только над одним типом задач. Например, сервис авторизации, который принимает на вход логин/пароль и далее решает – давать пользователю доступ в систему или нет. Или, например, сервис отправки SMS.
Любое монолитное приложение можно разбить на множество сервисов, которые должны как-то между собой взаимодействовать.
Сервисы могут общаться между собой любым удобным способом:
- отправляя друг другу TCP или UDP-пакеты;
- через REST-интерфейс (дергая методы по HTTP);
- либо через шину данных (RabbitMQ, Apache Kafka).
Как правило, в основном сервисы общаются по HTTP.
Так как сервисы маленькие, ненагруженные, то они могут работать на множестве сравнительно недорогих машин. Более того, под каждый конкретный микросервис можно подобрать железо подходящей конфигурации.
Если в случае с монолитом нам с течением времени придется переходить на очень большой сервер, то здесь мы можем просто выпиливать второстепенную логику, перекладывая ее на небольшое, не сильно производительное железо. И освобождать тем самым ресурсы большого сервера, чтобы он решал более конкретные задачи – расчет себестоимости, расчет зарплаты (какие-то высоконагруженные вещи, которые до сих пор должны оставаться на серьезном железе).
Например, если мы написали для какого-то проекта сервис авторизации – то для другого проекта мы не дублируем код, а просто дергаем этот сервис по REST-протоколу, и он нам возвращает данные.
Допустим, ваше приложение – это магазин, состоящий из набора сервисов (таких, как корзина, формирование заказов, платежный шлюз). И вот в течение дня у вас отваливается шлюз платежной интеграции. Но бизнес позволяет клиентам дальше формировать заказы, видеть витрину товаров. Просто в момент оплаты клиент будет видеть сообщение, что у вас сейчас проблемы с оплатой: «Вы сможете оплатить заказ позже». И когда сервис поднимется, можно будет уведомить клиентов, тем самым, какая-то часть из них может вернуться.
А в случае монолитной архитектуры – при проблеме в основном приложении встает все.
Если мы нашли какую-то функциональность в другом стеке – в Node.js или в Python (что-то, что позволит нам нарисовать красивый дашборд или использовать машинное обучение, которое сейчас актуально), мы можем просто запустить этот сервис рядом и использовать его. При этом основная бизнес-логика остается работать в 1С. Тем самым мы можем брать лучшее из разных технологических миров, взаимодействовать со всем этим в нашей экосистеме, и все будет просто хорошо.
Плюсы-плюсами, но есть и минусы.
- Чем больше сервисов, тем сложнее их мониторить, Понятно, что если их количество приближается к сотне или к тысяче, то уже начинаются интересные проблемы.
- Пересылка данных вызывает небольшие задержки, которые могут быть критичны для приложений, где важна высокая скорость. В случае монолита все вызывается относительно быстро, а в случае микросервисов все уже зависит от канала связи и других вещей.
- Усложняется управление инфраструктурой. Каждый сервис принято запускать на отдельном сервере – это может быть Docker-контейнер, виртуальная машина или какое-то железо. Это может усложняться еще и тем, что используются сборки разных дистрибутивов Linux. Мы используем стандарт – это Docker и Debian 9. Админы в шоке.
Мониторинг микросервисов – Flask Monitoring Dashboard
В качестве REST-шлюза мы используем Flask. Есть OpenSource библиотека Flask Monitoring Dashboard. С ее помощью мы мониторим количество вызовов методов – например, на скриншоте видно, сколько раз происходил вызов определенного метода сервиса. Если в течение двух месяцев мы видим, что этот метод никто не вызывает, мы можем просто его выпилить.
Этот дашборд также позволяет нам смотреть нагрузку на метод в разрезе часов и дней.
Есть профайлер, который собирает в себе, какие входные параметры передавались в метод, и сколько чего выполнилось – это облегчает расследование проблем с производительностью.
Мониторинг шины данных– Kafka Manager от Yahoo
Сервисы обмениваются сообщениями через шину данных – мы используем в качестве шины Apache Kafka.
Шина данных – это такая сущность, которая соединяет собой поставщиков сообщений и их потребителей. Например, когда вы пишете письмо, в качестве шины выступает «Почта России».
Само сообщение выглядит как письмо. Есть тема, которая указывает на название события, и есть данные, и есть потребители. Шина видит, что на эту тему подписаны эти потребители, и она им скидывает эти сообщения по сети.
Шину мониторим через Kafka Manager от Yahoo – он собирает метрики по сообщениям.
Архитектура обмена сообщений между 1С и шиной данных Apache Kafka
Встает логичный вопрос – как подключить Apache Kafka к 1С.
Мы реализовали подключение без использования внешних компонент:
- с одной стороны Kafka, с другой – 1С;
- и между ними прокси-сервис на Python, который подключен к шине и подписан на события – он выгребает эти события из шины и возвращает их в 1С по HTTP;
- а в 1С работает HTTP-сервис, который это все может принять и дальше уже обработать.
Соответственно, 1С стучит GET и POST-запросами в Kafka через такой же прокси-сервис, который имеет соответствующий REST-интерфейс, и этот прокси-сервис скидывает эти сообщения в шину данных.
Вот так можно решить вопрос интеграции 1С и Kafka.
Вот пример, как собирает метрики по сообщениям Kafka Manager от Yahoo. Здесь показаны как раз метрики на то событие, которое выгребает прокси-сервис.
Конечно же, и 1С можно использовать как микросервис, потому что стек 1С ничем не хуже других. И мы можем наши куски монолита распиливать на какие-то отдельные конфигурации, выносить туда бизнес-логику или делать еще какие-то вещи. Тем самым, мы можем дорабатывать одну часть нашей инфраструктуры, и при этом основная логика работы не будет валиться, и наш бизнес не будет останавливаться.
Примеры использования микросервисов. Asterisk client
Поговорим о реальных примерах применения из жизни моего предприятия. Как же нам помогло применение микросервисов в повышении эффективности работы бизнеса.
Недавно мы проводили реструктуризацию бизнес-процесса «Запись на сервис». И одной из точек маршрута было – уведомить клиента за сутки о том, что он собирался приехать. Если клиент подтверждает свое намерение приехать, то бизнес-процесс двигается дальше по ветке, начинается подготовка к заезду и т.д. А если клиент не планирует приезжать, то бизнес-процесс завершается, и переходит уже к другой логике (к попытке вернуть клиента и т.д.).
Сначала эту задачу возложили на людей, но эффективность прозвона менеджерами не сильно повысила продажи. И мы пришли к выводу, что у нас есть телефония Asterisk, и можно попробовать организовать автоматический прозвон.
Это выглядит следующим образом:
- звонит сервис, спрашивает: «Добрый день! Вы приедете завтра к нам на сервис?»
- клиент ему отвечает – «Да» или «Нет», происходит распознавание речи;
- и в зависимости от ответа бизнес-процесс идет дальше – или запись подтверждается, или время в журнале записи освобождается;
- при необходимости разговор разбирается, подключаются менеджеры и т.д.
Как это работает?
- В 1С регламентным заданием создаются задачи на обзвон. Задача 1С – только сгенерировать данные для обзвона (телефон, имя клиента, дату и какой-то текст) и отправить их в сервис. После этого 1С занимается своими делами.
- Итак, 1С по REST дергает сервис, передавая ему в качестве параметров данные для обзвона. В сервисе есть очередь заданий. Он их обрабатывает.
- Основная задача сервиса – это передать данные в Asterisk, чтобы он совершил звонки.
- Далее – подписаться на события Asterisk, чтобы мы понимали, что звонок завершен.
- И еще одна его функциональная обязанность – это принять от Asterisk записанный файл с ответом от клиента и превратить его в текст.
- Далее полученный от Asterisk ответ и его текстовая расшифровка идет в шину данных,
- После чего все это доезжает до 1С, которая уже принимает решение, что мы будем делать дальше – мы либо идем по положительной ветке, либо завершаем процесс.
В результате мы увеличили количество дозвонов и автоматизировали получение ответов (да/нет) по поводу каждого обращения.
Снизили нагрузку на операторов и менеджеров по исходящему трафику.
И в качестве побочного эффекта облегчили менеджерам набор номера клиента, потому что раньше возможности совершить звонок из 1С не было.
Примеры использования микросервисов. Внешний журнал записи
Еще один пример – журнал записи. Он нужен нам для понимания, в какой момент времени к какому менеджеру приедет клиент. Тем самым мы планируем нагрузку на сотрудников, на цех – что позволяет нам избежать коллизий при записи, когда клиенты пытаются записаться на одно и то же время.
По нагрузке на приложение:
- Это более 100 пользователей, которые постоянно с небольшой периодичностью тыкают, обновляют журнал, переключают периоды – создают бурную деятельность.
- Большая разнородность данных. Здесь имеется в виду, что в одном запросе собирается несколько справочников, несколько бизнес-процессов, несколько документов. Это все большие выборки с соединениями нескольких таблиц.
- По датам выборка составляет +/- 90 дней – это тоже доказывает разнородность данных.
- Более 15 подразделений.
- В одном подразделении ~ 10 сотрудников и 5 постов.
Первая реализация, конечно, была полностью сделана средствами 1С и как-то работала, но потом ее пришлось выпилить, потому что 1С не справлялась с задачами бизнеса.
С какими основными проблемами при реализации на 1С мы столкнулись:
- долгая выборка из базы данных при переключении периода;
- недостаточно функциональности 1С диаграммы Ганта;
- нет возможности переиспользовать фронтэнд 1С в каких-то других приложениях (в колл-центре либо для записи с сайта).
После отказа от фронтенда на 1С была выбрана следующая архитектура:
- Сервис написан на Python;
- HTTP сервер на Flask;
- В качестве ORM для работы с базой данных используется библиотека peewee.
- В части фронтенда – это HTML с JS, используется библиотека Timeline.js.
Как это все работает?
- 1С при проведении документа отправляет триггер в сервис.
- Сервис делает запрос в базу данных, формирует JSON и отправляет его в кэш.
- Далее отправляет в шину сообщение, что по этому цеху есть изменение на такое-то время такой-то даты. К шине подключены подписчики на это событие, которые при необходимости могут уже дальше делать какую-то свою логику.
- Когда пользователь меняет дату в 1С или обновляет журнал на веб-форме браузера, уходит GET-запрос в сервис. Если данные есть в кэше, они берутся оттуда, если нет, мы идем в базу, отправляем данные в кэш и обратно клиенту.
- На клиентской стороне происходит прорисовка журнала. К веб-форме реализовано подключение по WebSocket – это нужно для того, чтобы, когда у 10 пользователей открыт один и тот же журнал (они записываются в него), нужно, чтобы если кто-то изменил журнал (добавил или удалил запись), у всех пользователей одновременно происходило обновление журнала. Это реализовано с помощью событийной логики – все доезжает до клиента по WebSocket.
В качестве результата приложения получили единый бекенд. Все данные для журналов (журнал не только в 1С) берутся из одного места. Там все актуально, ничего не разъезжается, дублирования логики нет.
Кроме этого мы получили единый фронтенд. Операторы колл-центра периодически переваливаются из 1С в колл-центр и обратно, они не задают вопросы, как с ним работать – он работает аналогично.
Функциональный фронтенд. Была задача закрашивать серым цветом области, которые не используются в рабочее время (на слайде видно, что нерабочее время по краям выделено серым цветом). Типовой диаграммой это реализовать не получилось.
На слайде показан пример, как это работает – интерфейс очень отзывчивый, ничего не висит.
Мы теперь можем делать произвольные формы, не ограничиваясь 1С-ным стеком. Если нам нужна какая-то дополнительная функциональность, мы ее выносим. На слайде показан пример, где одна форма HTML выводится поверх другой – все реализуемо.
Быстрый отклик при работе из базы 1С. Раньше это работало очень медленно.
Обратите внимание, поле, где работает журнал – это встроенный в 1С Chrome (Chrome Embedded Framework). Потому что текущий движок в платформе 8.3.8 (Internet Explorer) не позволял запускаться js-коду. Там ничего не работало. Чтобы добиться результата, пришлось впилить туда Chrome.
Какие еще преимущества мы получили в результате:
- За счет внедрения промежуточного кэша получили ускорение по отклику на получение данных.
- За счет реализации событийной логики и использования WebSocket получили быструю актуализацию отображения на клиентах.
- За счет переиспользования журнала увеличили количество активных пользователей по нагрузке
Примеры использования микросервисов. Предсказание пробега
Еще один пример – у нас есть сервис предсказания пробега.
Для чего это вообще нужно? Мы с помощью машинного обучения предсказываем, когда человек докатает пробег на следующее ТО, и за две недели до этой даты делаем ему предложение о прохождении ТО у нас.
Тем самым мы: во-первых, повышаем лояльность клиентов, во-вторых, повышаем возможность покупки этого ТО у нас.
Как это все работает?
- 1С при записи добавляет триггер в сервис,
- Сервис добавляет данные в базу MySQL и на основании этих данных делает расчет планового заезда с помощью машинного обучения – записывает в базу план ТО по машинам: дату, пробег и планируемую дату прохождения следующего ТО.
- Другой сервис делает выборку по плановым заездам, генерирует короткие ссылки, а также занимается коммуникациями с клиентом – отправляет ему SMS-сообщения, в WhatsApp, Viber и т.д. При переходе по короткой ссылке клиент видит предложение и может записаться на удобное для него время. Результат коммуникации сервис отслеживает и сохраняет, чтобы мы дальше могли бы уже смотреть выбытие клиентов и т.д. (могли уже дальше какие-то вещи делать). Соответственно, собираются метрики переходов по коротким ссылкам – какой клиент открыл, на какой странице он остановился, что произошло, на какие кнопки он нажал. Туда впилена полная интеграция с Яндекс.Метрикой.
В качестве результата могу сказать, что мы получили проактивную коммуникацию с клиентом по предложениям.
Мы заранее предсказываем его пробег с точностью до 2-х недель в 80-90% случаев.
Создаем предложения по заезду с какой-то дальнейшей обработкой.
Выводы
В качестве выводов могу сказать следующее:
- Писать и поддерживать небольшие сервисы всегда проще, чем большие.
- Для каждого сервиса можно выбрать язык и свой технологический стек, который больше всего подходит для решения этой задачи. Если нужна скорость, можно попробовать сделать микросервис на C++, если постоянно туда-сюда гоняются данные, можно попробовать реализовать сервис на go. А для всего остального есть 1С и Python.
- Не страшно экспериментировать с новыми технологиями. Хочешь добавить какую-то новую функциональность – выкатываешь сервис. Если по метрикам видишь, что там что-то не так, откатываешь его обратно. Остальная инфраструктура от этого не страдает. Если видим, что в сервис больше никто не ходит, просто его выключаем, и все – значит, про него все забыли.
- Вместо рефакторинга проще выбросить сервис и написать его с нуля.
Скорее всего, не во всякой задаче можно или нужно использовать микросервисную архитектуру. Но там, где есть такая возможность, по моему мнению, плюсы превышают минусы.
Вопросы
- Вы используете для машинного обучения какую-то свою разработку или используете какой-то облачный сервис – передаете данные в Яндекс или еще куда-то?
- В первый день конференции был доклад по машинному обучению. Мы используем те же питоновские стандартные библиотеки для машинного обучения – sckit-learn, pandas и т.д. Один в один, просто у нас своя логика идет.
- Все это как-то тестируется? Я знаю, что у микросервисов есть проблема по этой части.
- По тестированию здесь особо я вам ничего не расскажу, мы больше на мониторинг ориентируемся.
- Как себя ведет Chrome Embedded Framework в толстом клиенте 1С:Предприятия?
- У нас используются управляемые формы, и в поле HTMLДокумента есть возможность запустить ActiveX. Есть библиотека Chrome Embedded Framework, которая работает под ActiveX. Получается, что в поле HTML стартует Chrome. Как запустить ActiveX в управляемом приложении – точно так же.
- Я правильно понимаю, существует готовый ActiveX, который показывает Chrome, и этот ActiveX можно вставить в Explorer?
- Да. Код Chrome Embedded Framework открыт, можно скомпилировать его самим и реализовать интерфейс
- У вас переплетено так много технологий, а сколько у вас разработчиков этим занимаются?
- Пять.
- И все по разным языкам?
- Не все. Кто-то на Python, кто-то на 1С, а кто-то и на 1С, и на Python.
- Про микросервисную архитектуру есть два или три тома книжек, которые говорят, что микросервисы, Enterprise – это целая история, ты должен начать с планирования, разделить все на микросервисы, гетерогенный ландшафт не существует. Если делать ландшафт из микросервисов, они должны быть действительно маленькими. У тебя точно микросервисная архитектура или все-таки элементы микросервисов?
- У нас архитектура больше сервис-ориентированная – каждый сервис решает свою бизнес-задачу. Микросервисная архитектура меньше дробится.
- Я так понимаю, что у тебя не совсем микросервисы, а скорее применение более специализированных технологий для решения определенного круга задач.
- Тут надо сначала поднять из тех трех томов понятие о микросервисах, и потом можно будет поговорить об этом дальше.
- Когда вы передаете клиенту этот широкий спектр технологий, он может как-то это сам поддерживать?
- Я сам поддерживаю эти технологии, я представитель бизнеса, а не франч.
- Но как это тиражировать и отдавать?
- Мы не касаемся вопроса тиражирования.
- Вопрос по интеграции с Asterisk. Передается запись звонка с Asterisk, она дальше разбирается в текст, разбирается на какие-то сегменты, а как дальше анализируется? Как система 1С понимает, что клиент согласился на приезд или захотел перенести свою заявку на какую-то другую дату и т.д.
- Сервис отправляет данные в Asterisk, вызывает originate action – пошел набор номера. У нас в Dial-плане прописано, что когда подняли трубку, есть макрос, который при поднятии трубки записывает разговор. Как только записали разговор, Asterisk POST-запросом на PHP возвращает в сервис адрес, где лежит wag-файл. Сервис получает запрос, получает файл, разбирает через speech_to_text, парсит и делает статус 1 или 0, формирует JSON, отправляет его в 1С.
- А кто понимает, что «Наверное», «Да», «Нет» и «Ни за что» – это 1 или 0?
- Есть словари. Мы эту базу расширяем.
- Ты рассказывал, как поделить на микросервисы внешние интеграции – Asterisk и т.д. А есть ли смысл делить саму 1С?
- Внешний журнал записи – это как раз пример, что в микросервис была выделена отдельная функциональность из 1С.
- А есть ли какие-то идеи разделить «Управление торговлей 11» на сеть 1С-ных баз, которые будут работать как микросервисы?
- У меня такой идеи нет. Но возможность есть – я говорил, что можно из основной базы выделить сервис, который занимается оформлением заказов. Какие-то модули можно разделить.
- Были на твоем предприятии такие случаи, что два разных микросервиса на 1С работали?
- У нас 1С-база одна, мы ее не делим. Нам одной хватает.
- У меня вопрос по терминологии. Поскольку сейчас в стационарной платформе произошел треш с передачей файлов на сервер, мы внутри 1С для получения / отправки файлов или получения информации о картинках, остатках и т.д. используем HTTP-сервис внутри этой же базы. Получается, что мы берем монолит 1С, но обращаемся мы к нему как к сервису.
- А зачем?
- Потому что есть ограничение платформы. Но я не знаю, считать это за сервис?
- Я думаю, нет. Потому что у вас потребитель и поставщик один и тот же.
****************
Данная статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART EVENT 2019.