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

Блог компании крок

Аналитика в SD-WAN как она выглядит и зачем нужна?

09.04.2021 18:04:19 | Автор: admin
Привет, я работаю инженером в КРОК, где у нас есть своя SD-WAN-лаборатория. И когда заказчик приходит с вопросами вроде А вот у меня в сети сейчас всё работает так, а как это будет работать, если я захочу перейти на SD-WAN? И будет ли работать вообще? мы можем быстро собрать нужную схему, оттестировать и показать.

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

Расскажу, как эти решения работают в паре и как все настроить.




Принцип работы аналитики в SD-WAN


Работа SD-WAN-сети Cisco, напомню, определяется набором компонентов управления:
vManage управляет конфигурациями и собирает данные для мониторинга сети
vSmart рассылает маршрутную информацию и политики управления трафиком
vBond связывает все компоненты решения воедино



SD-WAN-роутеры получают маршрутную информацию по проприетарному протоколу OMP. В традиционной сети маршрут всегда выглядит как сеть 192.168.4.0/24 доступна через шлюз X. В случае с OMP всё несколько непривычно, например, вот так:



По сути вывод выше означает сеть 192.168.4.0/24 доступна через маршрутизатор с идентификатором 1.1.255.21, через два вида транспорта (MPLS и Private1), а передаваемый туда трафик необходимо упаковать в IPSEC. Все эти навороты необходимы для обеспечения SD-WAN-функционала.

Вдобавок к маршрутам, есть ещё и политики, определяющие выбор вида транспорта, например, Голосовой трафик передавать через MPLS, если MPLS не выдаёт нужное качество, перейти на LTE. Вот так:



Понять, куда пойдёт трафик конкретного приложения в конкретный момент времени становится сложно. Проверить что именно мы настроили можно с помощью инструмента симуляции потоков (Simulate Flows) в vManage



Но кроме этого, хочется понять, как ходил трафик этого приложения по сети в последнюю, скажем, неделю, с учётом того, что качество каналов иногда падало, а объёмы трафика менялись. Стоило ли вообще передавать этот трафик именно по этому пути или стоит пересмотреть политику? Именно в этом и помогает такое средство аналитики как LiveAction.

LiveAction устанавливается в виде сервера или кластера серверов, интегрируется с vManage по API, получает оттуда список маршрутизаторов и данные об их конфигурации, а потом опрашивает их по SNMP и получает данные по cFlowd (аналог NetFlow).

Интеграция


Связались с vManage через API:



Получили список устройств:



Разрешили на них доступ по SNMP (Стандартный Internet OID, добавляется в SNMP-шаблон в vManage):



Настроили отправку cFlowd с помощью политики vManage:



И получаем в LiveAction информацию о сети, например, вот в таком представлении:



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



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



Заглянуть поглубже


По клику на потоке трафика на диаграмме система умеет подтягивать с vManage политики, влияющие на него, опять же через API:



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



Из неё можно увидеть, что, например, трафик FTP-Data из VRF 2 передавался с меткой DSCP 0 через транспорт с названием Private1. В нижней части доступен бегунок, позволяющий определить интересующий нас промежуток времени и кнопка Play, чтобы посмотреть, как менялось поведение маршрутизатора во времени. Таким образом можно не только убедиться в том, что трафик того или иного приложения передавался так, как мы этого хотели, но и расследовать какие-то инциденты в работе сетевого приложения, имевшие место в прошлом. Например, если три дня назад с 12:00 до 12:30 у нас плохо работала видеоконференцсвязь, можно увидеть, что мы почему-то передавали её трафик не через тот канал и без нужной метки DSCP.

Можно вывести список потоков трафика между двумя площадками в виде таблицы:



А потом зайти в конкретный поток и посмотреть путь его прохождения вместе, скажем, с загрузкой интерфейсов, CPU и памяти устройств, участвовавших в передаче данных:



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

И ещё глубже


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



Для каждого устройства можно смотреть так называемый Historical Playback то, как менялись потоки трафика во времени:



Дашборды


Для текущего мониторинга SD-WAN-сети в LiveAction доступны преднастроенные и кастомизируемые с помощью виджетов дашборды. Доступно около 30 различных виджетов, можно создавать свои. Вот пример готового дашборда для отслеживания производительности туннелей SD-WAN:



Для любого дашборда можно сделать постоянную ссылку и вывести его в контрастном виде на плазменную панель в NOC:



Чем полезен LiveAction на этапе тестирования


Наш опыт работы с решением Cisco SD-WAN показывает, что для его успешного тестирования и внедрения особенно важно понимать, какой именно трафик гуляет по сети, какими маршрутами и в каких объёмах. Традиционные сети фокусировались на connectivity соединить площадки A, B, C с ЦОД. Максимум, что можно было сделать для обеспечения качества работы конкретных приложений это шейпинг трафика и распределение его по очередям QoS.

Задачу connectivity, кстати, SD-WAN решает быстрее и проще традиционных сетей, но главная его фишка адаптация под требования сетевых приложений. Real-Time трафик мы можем перебрасывать с одного канала на другой, измеряя задержку и джиттер. Вот как это работает. На трафик, критичный к потерям применяем коррекцию ошибок или передаем его одновременно по двум каналам, а тяжёлый и некритичный трафик сгружаем на дешёвые каналы. Система аналитики как раз позволяет увидеть какие приложения передают трафик по сети и отнести их к тому или иному классу. Причём сделать это можно не только после внедрения SD-WAN, но и до, на этапе тестирования:

  1. Поставить LiveAction и собрать первичные данные с сети
  2. Выбрать для тестирования SD-WAN площадки, паттерн трафика на которых наиболее репрезентативен для текущего состояния сети
  3. Сделать предположения о том, какие политики повысят качество передачи данных
  4. Установить SD-WAN-маршрутизаторы и настроить в тестовом SD-WAN-сегменте политики, согласно предположению
  5. С помощью LiveAction проанализировать результаты работы и скорректировать политики. Увидеть самим и продемонстрировать заинтересованным лицам повышения качества передачи данных
  6. Получить готовую к развёртыванию на всю сеть конфигурацию SD-WAN.

Резюме. Польза от аналитики на уже работающей SD-WAN-сети


Тем, кто уже внедрил у себя решение SD-WAN от Cisco, система аналитики поможет:

  • Проследить за тем, как операторы связи соблюдают SLA и какое вообще качество выдают на своих каналах связи;
  • Увидеть проблемы в работе критичных приложений до того, как их пользователи начнут жаловаться;
  • Корректно подстраивать сеть под работу новых приложений, которые внедряются;
  • Быстрее находить ошибки в настройках, допущенные специалистами по эксплуатации сети;
  • Понять, насколько лучше стала использоваться доступная пропускная способность каналов связи, а значит и оценить эффективность миграции на SD-WAN в деньгах.

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

Свидетели DevOps мифы и байки про девопсов и тех, кто их нанимает

25.02.2021 10:21:06 | Автор: admin

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

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

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

Трудности перевода

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

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

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

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

Байка про хромого девопса

Недавно нас позвали на помощь в один проект, где стояла, на первый взгляд, простая задача. Web-приложение работало через web-сокеты, но было развернуто внутри периметра, а на фронте стоял ISPManager, который в качестве reverse proxy использовал apache. Юный девопс, работавший в этом проекте, перепробовал все примеры конфига апача, которые нашел в Гугле, и вконец разочаровавшись в его поисковых способностях, перешел уже было к Яндексу, но тут менеджер проекта забил тревогу. На задачу к тому моменту было потрачено 72 часа. 72 часа, Карл! Кто вам сказал, что методология DevOps ускоряет разработку и сокращает time-to-market? ;)

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

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

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

Про технологии

DevOps это про культуру и философию совместной работы, но с этим понятием также сопряжен определенный технологический стек. Скорее всего я не ошибусь, если скажу, что какие-нибудь NetApp, Cisco, AIX или MS SQL воспринимаются как старый добрый олдскул (хотя это не совсем так, и классические вендоры делают гигантские шаги в новом направлении), а вот, скажем, Docker, Ansible, Jenkins и Prometheus в нашем сознании прочно ассоциируются с DevOps, SRE и новыми веяниями.

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

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

И отдельная боль это сеть. В сети надо разбираться, владеть инструментами диагностики. Сеть не зависит от платформы, она есть везде и напрямую (а порой больно) влияет на работоспособность и производительность всего остального. Когда человек, грезящий себя девопсом, наивно полагает, что надо установить свежую версию Kibana, потому что она умеет конвертировать адреса IPv6 в IPv4 это звучит как анекдот. Но потом он, например, берет и орудует с сетью вот так:

или вот так:

Дальше хочу немного заострить внимание на двух технологиях, которые почти стали синонимами DevOps.

А давайте-ка все распилим на микросервисы, засунем в Docker и запустим в Kubernetes

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

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

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

Вот, кстати, символичный фрагмент одного из скриптов по деплою:

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

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

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

- А у вас есть kubernetes?

- Да, конечно, ну как у всех! Как полагается.

- А зачем?

- Ну как это зачем? Это же

Дальше следует немая сцена, гримаса ужаса и спустя некоторое время человек, вероятно, идет топиться.

Я считаю себя евангелистом подхода Infrastructure as Code (IaC). Мне спокойно только тогда, когда продукт не просто освоен, а когда его развертывание и настройка автоматизированы. Специально не добавляю слово документированы, потому что декларативный характер инструментов IaC что приятно во много порождает автодокументируемый код.

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

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

Просто через docker run:

docker run

docker run -d \

-e 'ALERTMANAGER_URL=http://alertmanager:9093' \

-e 'BOLT_PATH=/data/bot.db' \

-e 'STORE=bolt' \

-e 'TELEGRAM_ADMIN=1234567' \

-e 'TELEGRAM_TOKEN=XXX' \

-v '/srv/monitoring/alertmanager-bot:/data' \

--name alertmanager-bot \

metalmatze/alertmanager-bot:0.4.3

С помощью docker-compose

docker-compose

networks:

alertmanager-bot: {}

services:

alertmanager-bot:

command:

- --alertmanager.url=http://localhost:9093

- --log.level=info

- --store=bolt

- --bolt.path=/data/bot.db

environment:

TELEGRAM_ADMIN: "1234"

TELEGRAM_TOKEN: XXXXXXX

image: metalmatze/alertmanager-bot:0.4.3

networks:

- alertmanager-bot

ports:

- 8080:8080

restart: always

volumes:

- ./data:/data

version: "3"

А вот тот же сервис в Kubernetes

кубер

apiVersion: v1

items:

- apiVersion: v1

data:

admin: MTIzNA==

token: WFhYWFhYWA==

kind: Secret

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

type: Opaque

- apiVersion: v1

kind: Service

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

ports:

- name: http

port: 8080

targetPort: 8080

selector:

app.kubernetes.io/name: alertmanager-bot

- apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

podManagementPolicy: OrderedReady

replicas: 1

selector:

matchLabels:

app.kubernetes.io/name: alertmanager-bot

serviceName: alertmanager-bot

template:

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

containers:

- args:

- --alertmanager.url=http://localhost:9093

- --log.level=info

- --store=bolt

- --bolt.path=/data/bot.db

env:

- name: TELEGRAM_ADMIN

valueFrom:

secretKeyRef:

key: admin

name: alertmanager-bot

- name: TELEGRAM_TOKEN

valueFrom:

secretKeyRef:

key: token

name: alertmanager-bot

image: metalmatze/alertmanager-bot:0.4.3

imagePullPolicy: IfNotPresent

name: alertmanager-bot

ports:

- containerPort: 8080

name: http

resources:

limits:

cpu: 100m

memory: 128Mi

requests:

cpu: 25m

memory: 64Mi

volumeMounts:

- mountPath: /data

name: data

restartPolicy: Always

volumes:

- name: data

persistentVolumeClaim:

claimName: data

volumeClaimTemplates:

- apiVersion: v1

kind: PersistentVolumeClaim

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 1Gi

storageClassName: standard

kind: List

Если решение все же принято, вам предстоит перелопатить горы документации, написать тонны yaml-a, мучительно искать, где пропущен отступ, по 10 раз пересобирать контейнеры. И в этом момент вы еще и не знаете, что через пару недель пройдете новый круг ада, подстраивая ваш деплоймент под Pod Security Policy и разные энтерпрайзные фичи. Конечно, когда вы это дотащите до конца, вы получите красивый сервис, который легко скейлится, автоматически перезапускается при сбоях, который можно обновлять, используя, например, канареечные релизы или какой-нибудь blue-green deployment.

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

Автоматизация как истинный путь джедая

Наши бэкапшики помнят один случай, как сотрудник заказчика собирался в консоли что-то удалить то ли ненужный симлинк, то ли копию конфига. А его то и дело дергали. По воле случая в один момент так сошлось, что товарищ успел набрать rm -rf /oradata, работая от рута, потом чихнул, что в свою очередь пробудило в его организме рута позывы на исход жидкости, а по дороге обратно он зацепился языками с товарищами. Когда он вернулся на рабочее месте, его экран спал. Не будучи в силах терпеть проделки этого вечно дремлющего устройства и дабы преподнести ему урок бодрости, товарищ решительно разбудил его точным ударом в Enter. В общем, когда все делаешь руками, нелепые вещи случаются сплошь и рядом.

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

Самое плохое в автоматизации это время, которое надо на нее потратить. И самое хорошее в ней тоже время, которое она впоследствие высвобождает. Например, пару лет назад нам потребовалось в нашем облаке IaaS развернуть инфраструктуру под нового e-commerce заказчика. Архитектура проекта: кластер БД, пул серверов приложений, распределенное хранилище, слой кэширования, сетевые балансировщики, WAF, ну и стандартная обвязка в виде телеметрии, СРК и сбора логов с визуализацией. Конечно, виртуальные машины мы давно создавали при помощи terraform, благо под наше облако можно использовать AWS-провайдер, так как мы по API совместимы. Программные компоненты и раньше ставили через ansible, и опыт настройки всего по отдельности, в общем, был. Но мы задались целью описать инфраструктуру проекта в виде единого пайплайна. На это ушло время, ну и до сих пор части этой автоматизации совершенствуются, так как еще много где были нами после переиспользованы.

Когда нам позже подвернулся аналогичный проект, различия описывались на уровне файла ответов. Мы развернули проект за 2 дня, причем большую часть времени занял перенос данных. В Gitlab CI запускался pipeline, который заполнял переменные для terraform, который затем запускался runner-ом. Тот создавал в облаке сети, диски и ВМ. ВМ запускались с cloud-init, который ставил внутрь puppet agent, который после старта связывался с foreman, забирал настройки для своей роли и деплоил все ПО. Через service discovery подключался мониторинг всех служб, везде встал и настроился filebeat, а бакап полился в S3. Voila! Все быстро и четко, без ошибок и ручных тестов на каждом шаге.

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

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

  • осмысленный сайзинг ресурсов;

  • отдельные точки монтирования (отдельный диск/раздел) под данные приложений и все, что может быстро пухнуть;

  • синхронизацию времени по ntp;

  • переход на использование ключей вместо паролей в ssh;

  • настроить ротацию всех логов;

  • иметь автоматический механизм обновления протухающих SSL-сертификатов

  • покрыть мониторингом все ключевые показатели жизнеспособности системы и не забыть про алерты;

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

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

Эти простые меры по принципу Парето составляют не более 20% действий по первичной настройке, но дают 80% вклада в стабильную и автономную их работу в будущем.

Если у вас уже есть provision-система, то следом можно подключить инструмент IaC, и накатывать все эти настройки всегда по умолчанию, через какой-нибудь базовый профиль. Я в такой профиль еще включаю набор обязательных утилит, чтобы, к примеру, в экстренной ситуации не оказалось, что в системе нет lsof, tcpdump и т. п.

Время и внимание хорошего девопса такие проблемы не отнимают, потому что он их еще в самом начале решил.

Как не стать героем баек

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

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

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

И напоследок завет работодателям

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

Если вам понадобился девопс, у вас вероятно уже есть разработка. Задачи, которые выполняет девопс это та же разработка, только инфраструктуры и процессов, поэтому к ней в целом применимы те же правила. Над девопсом должен быть senior или тимлид, который через систему контроля версий делает code review, проверяет и одобряет PR/MR. И совершенно точно не стоит доверять архитектурные вопросы человеку без подтвержденного архитектурного опыта. Лучше поищите стороннюю экспертизу для подстраховки.

Мне также нравится концепция, когда отдельно от специалистов DevOps позиционируется еще одна команда - платформенных инженеров (Platform engineer). Она не работает непосредственно с девелоперами, но именно она снабжает девопса готовыми, отлаженными рычагами к этой платформе и уже настроенному инструментарию. Именно такой подход позволяет снизить планку требований к девопсу, позволяя ему спокойнее учиться и снижая риск его ошибок.

В этом месте ставлю не точку, а многоточие, так как тема неисчерпаемая и весьма холиварная. Комментарии, как говорится, покажут :)

Подробнее..

Интеграционный слой с Kafka и микросервисами опыт построения операционной CRM контакт-центра торговой сети Пятерочка

04.03.2021 10:11:49 | Автор: admin

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



Привет Хабр, на связи Иван Большаков архитектор интеграционных решений, эксперт департамента разработки ПО КРОК. Я расскажу, как мы делали интеграционный слой для CRM-системы группы контакт-центров торговой сети Пятерочка.


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


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


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


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




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


Возможные решения



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


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



Другой вариант enterprise service bus. Это классический сценарий интеграции: разработать пользовательский интерфейс, подключить его к опубликованным на интеграционной шине методам и наслаждаться жизнью.


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



Мы решили использовать для интеграционного слоя микросервисы. Они позволяют реализовать дополнительную бизнес-логику и обеспечивают масштабируемость. Их проще распределить по нескольким ЦОД, по сравнению с ESB.


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


Архитектура интеграционного слоя


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


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


Мы использовали стандартный прием спроектировали интерфейсы, написали адаптеры для каждой системы и связали их с нашим ядром через законтрактованный API.


Так как в интеграционный слой попала бизнес-логика, выбор пал на событийно-ориентированную архитектуру. В ней проще следить за согласованностью данных.


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


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


Вся сложность во взаимодействиях


С внешними системами было просто. Мы не могли ничего менять, так что использовали те API, которые они предоставляли.



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


с бизнес-сущностью, которую обрабатывает сервис user, что-то произошло, вот ее новые данные

Этот топик читают другие сервисы. Они реагируют на изменения и отписываются в свои топики. Так действие пользователя по каскаду распространяется по всей системе.


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


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



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


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


Kafka и очереди сообщений


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



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


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


Взаимодействие с фронтом


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



Ходить за несколькими сущностями в три разных сервиса, а потом собирать на фронте какую-то адекватную модель для представления не очень удобно. Куда удобнее использовать composer, который будет брать сразу несколько сущностей со связями между ними и компоновать в один JSON. Для этого отлично подошел Apache Camel. Правда, в следующий раз мы не станем заморачиваться с REST и используем graphQL.


Service mesh и безопасность


Service mesh нужен, чтобы не прописывать вручную всю логику межсервисных взаимодействий. Как правило, для соединения микросервисов мы используем Istio и в этом проекте тоже рассчитывали на эту платформу. Но в этом году все идет как-то не так, как ожидалось.



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


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


Конечно, полноценный service mesh на коленке не напишешь, но можно было обойтись без управления трафиком, а мониторинг настроить вручную. Главное, что нам нужно было от service mesh, это безопасность.



Было необходимо идентифицировать запросы от фронта к бекенду, проверять токены пользователей в каждом микросервисе и делать запросы GET, POST и так далее, в зависимости от роли в токене.


Итак, мы начали пилить собственный service mesh. В его основу легла простая идея: если нельзя (не хочется) поместить логику в код сервиса, сделаем внешний sidecar-контейнер по аналогии с Istio, использовав OpenResty и язык Lua.


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


Аудит


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



Существуют штатные библиотеки для работы с Kafka, но и с ними возникли проблемы. Все ломалось, как только для подключения к Kafka требовался SSL. Спас положение старый добрый kafka-console-producer, который лежит в каждом sidecar и вызывается с параметрами из nginx.


Получился рабочий почти-service mesh. Казалось бы, можно было расслабиться, но мы чуть не упустили еще одну важную вещь.


Балансировка gRPC


gRPC то работает на HTTP/2, а этот протокол устанавливает соединение и держит, пока оно не порвется. Возможна ситуация, когда инстанс сервиса A намертво прицепится к одному из инстансов сервиса B и будет направлять все запросы только на него. Тогда от масштабирования сервиса B не будет толка. Второй инстанс сервиса B останется не нагружен и будет впустую тратить процессорное время и память.



Мы могли сделать полноценную балансировку на клиентской стороне, но было бы неправильно тратить на это время. После внедрения полноценного service mesh эти наработки потеряют актуальность.


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


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


Управление версиями


Напоследок, несколько слов о том, как мы управляли версиями кода.


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


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



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


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


Еще один момент, который стоит упомянуть, управление версиями интеграционных контрактов между сервисами.


Если сервис A и сервис B общаются по gRPC, и разработчик сервиса B исправит что-то в протофайле и сломает обратную совместимость, это выстрелит только, когда выйдет в рантайм. Слишком поздно. Поэтому мы храним все интеграционные контракты (протофайлы, классы для сериализации Kafka и т. д.) отдельно и подключаем как саб-модули. Благодаря этому решению, многие возможные проблемы проявляются на этапе компиляции.


Что мы вынесли из проекта


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


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


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


Если у вас появились вопросы, или вы знаете, как красиво сделать приоритизацию сообщений в Kafka, пишите в комментариях или на почту IBolshakov@croc.ru.

Подробнее..

Аналитика событий на опасном производстве, или зачем Цифровому рабочему Kafka, Esper и Clickhouse

23.03.2021 10:07:12 | Автор: admin

Привет, Хабр! Я Алексей Коняев. Последние пару лет участвую в развитии платформы Цифровой рабочий в роли ведущего java-разработчика.

Представьте, что вы приехали на экскурсию на завод. Там огромная территория, и вы вместе с гидом передвигаетесь на машине. Он рассказывает: Посмотрите направо, здесь новое здание литейного цеха, а вот слева старое здание, которое скоро должны снести... Как вдруг через минуту это старое здание взрывают! Гид, конечно, в шоке, да и вы тоже, но, к счастью, всё обошлось. Спрашивается, какого черта машина с экскурсантами оказалась в месте проведения взрывных работ?! И наш Цифровой рабочий на этот вопрос тоже не ответит, но он поможет вовремя предупредить всех заинтересованных лиц о том, что в геозоне, где сейчас проводятся опасные работы, появились посторонние в машине местного гида.

Если в двух словах, то система позволяет предупреждать опасные ситуации на производстве благодаря носимым устройствам Outdoor/Indoor-навигации и видеоаналитике. Цифровой рабочий может определять местоположение, физическое состояние или опасное поведение людей, строить различную аналитику, в том числе realtime, и выполнять разбор полётов, т.е. воспроизводить историю событий, чтобы можно было выяснить, что привело к нежелательной ситуации.

Дальше расскажу про архитектуру нашей системы, как мы используем Kafka, Esper и Clickhouse и на какие грабли уже наступили.

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

Пример из жизни Цифрового рабочего на пилоте в нефтянке. Работник залез на стремянку, чтобы затянуть вентиль газовой трубы. Резьба вдруг сорвалась, он не удержался и, упав с высоты 5 метров, от удара потерял сознание. А вентиль при этом открылся, и газ начал поступать в помещение. Но датчики падения и удара, которые встроены в носимое устройство (у него был модуль на каске) передали сигналы на сервер. Там эти два сигнала были обработаны на платформе, и алгоритм выявления внештатных ситуаций сформировал событие-тревогу. Оно было передано оператору, а также другим сотрудникам, которые в тот момент были недалеко от пострадавшего и смогли быстро прийти на помощь.

Архитектура

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

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

В качестве шины или слоя передачи событий выбрали Apache Kafka. На тот момент Kafka уже зарекомендовала себя как зрелый и надежный продукт (мы начинали с версии 2.0.0). Кроме того, выбирали только среди Open-source решений, чтобы удовлетворить требованиям импортозамещения. А с функциональной точки зрения в Kafkа нам понравилась возможность независимо подключать различных консьюмеров к одному и тому же топику, возможность прочитать события из топика ещё раз за период в прошлом, механизм стриминговой обработки Kafka Streams, ну и, конечно, масштабируемость благодаря партиционированию топиков.

Архитектура системы включает следующие компоненты:

  • Есть различные носимые устройства (метки) и системы позиционирования, которые уже существуют на рынке и которые умеют работать с теми или иными девайсами.

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

  • Далее эти события обрабатываются Транслятором, который выполняет первичную обработку (связывание метки с сотрудником, вычисление геозоны, в которой находится сейчас метка и др.).

  • Модуль Complex Event Processing-а (CEP-процессор) обрабатывает события, которые порождает Транслятор; здесь мы занимаемся выявлением внештатных ситуаций, анализируя различные типы событий, в том числе от разных меток.

  • В UI поступают события как от Транслятора (для отрисовки перемещения сотрудников), так и от CEP-процессора (отображение алертов).

  • Для хранения справочных данных, как то список меток, сотрудников, геозон и пр., используем реляционную БД PostgreSQL.

  • А для хранения данных, по которым строится аналитика ClickHouse.

  • Но в ClickHouse напрямую никто не ходит для этого используется модуль Reports, который выполняет обработку запросов к аналитическим данным (запросы на обновление данных виджетов на аналитической панели в UI, запросы на формирование различных отчётов и др.).

  • И ещё есть файловое хранилище S3, где мы храним файлы 3D-моделей и файлы сформированных отчётов.

Ну а теперь давайте расскажу поподробнее про все модули системы, как они устроены внутри.

Интегрируемся со всеми: адаптеры

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

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

Хотя для некоторых меток мы всё-таки запилили систему позиционирования сами, когда не удавалось найти существующего решения или хотелось поэкспериментировать. А один из экспериментов привел к тому, кто мы разработали свою метку с креплением на каску:

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

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

Сырые события бывают такие:

  • TagMovement перемещение метки, содержит координаты;

  • TagInfo телеметрия со значениями датчиков метки;

  • TagAlert события нажатия тревожной кнопки, события падения и удара.

Разделяй и властвуй: топики Kafka

Отдельно хочу остановиться на топиках.

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

  1. Индивидуально настраивать retention для каждого топика. Так, например, для сырых событий ретеншн всего 1 сутки, потому что эти события практически сразу будут обработаны, и хранить их долго не нужно (но 1 сутки всё-таки храним на случай сбоя).

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

  3. Реализовать автоматическую сборку топологии Kafka Streams процессоров если вкратце, то работает она так:

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

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

    3.3. все процессоры это Spring Bean-ы;

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

Примерно так выглядит топология процессоров Транслятора, о котором речь пойдет ниже:

Шеф-повар: транслятор

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

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

Внутри Транслятора несколько процессоров на Kafka Streams (см. processor-api), причём многие из них используют состояние.

Kafka Streams предоставляет API для работы с состоянием как с Key-Value таблицей. Тут важно понимать, что для каждого ключа входного события процессора существует свое состояние. Ключ у каждого типа события свой. Например, для события перемещения метки это будет серийный номер метки. Это позволяет выполнять обработку очередного события от какой-то конкретной метки с учетом истории обработки событий от этой же метки.

Транслятор решает следующие задачи:

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

  • Связывание метки и сотрудника. Здесь процессор Транслятора обращается к реляционной БД за справочной информацией, чтобы определить, какой именно сотрудник сейчас носит эту метку.

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

  • Обнаружение потери сигнала от метки. Тут используем такую штуку, как Punctuator это механизм Kafka Streams, который позволяет с заданной периодичностью просматривать состояния процессора по всем ключам. И логика простая: если нашли состояние, в котором время последних полученных координат позже, чем максимально разрешенное, то значит, сигнала от метки не было давно, и следует считать сигнал потерянным.

  • Ещё есть процессоры, которые работают с геозонами. Суть в том, что вся территория и здания размечаются на геозоны. Например, Корпус Альфа, который, в свою очередь, разделяется на геозоны этажей, а каждый этаж на коридоры и кабинеты. И есть процессор, который определяет, что координаты метки попали внутрь той или иной геозоны, а другой процессор выполняет подсчёт количества сотрудников внутри геозон.

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

  • эти события уже представляют интерес для пользователей системы события перемещения сотрудников передаются в UI для отрисовки их на карте; также в UI отображается телеметрия метки, которая уже ассоциирована с определённым сотрудником;

  • почти все бизнес-события сохраняются в аналитическую БД;

  • многие бизнес-события используются для выявления внештатных ситуаций;

  • и ещё эти события мы храним в Kafka долго (1 месяц) для того, чтобы иметь возможность воспроизвести их и посмотреть, что происходило в определённый интервал времени в прошлом.

Спасительный кэш при потоковой обработке

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

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

  • обновляться с некоторой периодичностью;

  • периодически сливать изменения в БД.

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

Мы сделали выбор в пользу Hazelcast-а, потому что:

  • Его достаточно легко использовать это просто библиотека, которую вы подключаете в проект.

  • Кэши Hazelcast-а автоматически синхронизируются на всех нодах. Но тут нужно быть осторожным если не ограничить область видимости кэша через задание имени группы (в конфиге экземпляра Hazelcast-а), то он может незаметно для вас реплицироваться в каком-нибудь ещё модуле, где вы тоже решили использовать Hazelcast. Т.е. в нашем случае, все кэши, которые нужны Трансляторам и только им, объединены в группу translator.

После добавления кэширования производительность Транслятора выросла на несколько порядков! Цифры получились такие: одна нода, которой выделены ресурсы, эквивалентные инстансу t4g.micro в облаке Amazon EC2 (2CPU + 2Gb), обрабатывала без задержки до 500 входящих сырых событий в секунду. 500 кажется не много, но метки разных производителей передают данные с разной частотой от 3 событий в минуту до 5 событий в секунду. И высокопроизводительные метки, которые дают большую точность, могут использоваться не на всей территории объекта. Таким образом, в худшем случае одна нода Транслятора выдерживает нагрузку от 100 меток, а в лучшем от 10 тысяч.

Высоко сижу далеко гляжу: отображение объектов на карте

UI состоит из двух частей серверная часть и клиент.

Серверная часть подписывается на определённые бизнес-события, в первую очередь события перемещения сотрудников. Эти события через WebSocket передаются на клиента, но предварительно выполняется:

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

  • редукция событий события накапливаются в буфере и отправляются на клиента 1 раз в секунду.

Это нужно для того, чтобы снизить нагрузку на клиента.

Клиентская часть это web-приложение на React-е. Основную рабочую область UI занимает карта с 3D-моделями зданий, которые можно посмотреть в разрезе провалиться на любой этаж и увидеть, что там происходит. Для отрисовки 3D-моделей мы используем библиотеку CesiumJS.

Complex Event Processing

Термин Complex Event Processing (CEP) придумал профессор Стенфордского университета David Luckham. Вкратце определение звучит так: Complex Event Processing это обработка потока различных событий в реальном времени с целью выявления паттернов значимых событий. Ещё часто CEP сравнивают с ESP (Event Stream Processing). И здесь David Luckham выделяет следующие отличия между ними:

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

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

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

Но в тоже время, в одной из своих статей David Luckham с коллегой, видя, что современные инструменты Event Stream Processing-а всё больше и больше приобретают возможности CEP-инструментов, делают вывод, что со временем разница между ними будет стерта (см. The Future of Event Stream Analytics and CEP).

CEP-процессор

Давайте перейдем от теории к практике!

Как вы уже поняли, в Цифровом рабочем именно модуль CEP-процессор выполняет сложную обработку событий, которыми в контексте нашей системы являются внештатные ситуации, такие как:

  • Вход сотрудника в геозону, имеющую в данный момент статус опасная.

  • Пульс выше или ниже нормы.

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

В качестве CEP-движка мы используем Open-source библеотеку Esper, которую с 2006 года разрабатывает компания EsperTech.

Esper мы выбрали по следующим соображениям:

  • Описание паттернов сложных событий (или правил) выполняется на языке Event Processing Language (EPL), который является расширением стандарта SQL-92; соответственно, правила описываются в декларативном виде, а нам очень хотелось, чтобы эти правила могли понимать не только программисты, но и, например, аналитики (хотя, если правило действительно сложное, то без подготовки его будет трудно понять).

  • Esper мощный инструмент, и достаточно сложные паттерны можно описать в несколько строк на EPL.

  • Есть интеграция с Kafka, которая позволяет описывать правила, оперируя событиями, потребляемыми из Kafka, а результат работы правила также оформлять в виде события и публиковать в Kafka.

Пример реализации правила на Esper-е

Давайте рассмотрим небольшую задачу и её решение на Esper-е. В КРОКе есть свой ЦОД и газотурбинные генераторы, которые используются как резервный источник питания. Эти штуки нужно периодически запускать, но оставлять их включёнными без присмотра надолго нельзя. Предположим, что сотрудник, который их обслуживает, не всегда соблюдает регламент и может отлучиться на более продолжительное время, чем это разрешено.

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

Для отладки решения будем использовать Esper Notebook, в котором можно описать правило на EPL-е и сценарий с входными данными.

Чтобы Esper Notebook понял, что текст это правило, в самом начале нужно написать ключевое слово %esperepl.

Далее, нужно определить схемы или таблицы, строки которых будут представлять входные события, в потоке которых мы будем искать интересующий нас паттерн:

@Description('Кол-во людей в геозоне')create schema PersonsInZone(zoneId string, number int);@Description('Статус устройства (вкл / выкл)')create schema DeviceStatus(deviceId string, zoneId string, turnedOn bool);

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

create context TurnerOnDeviceContext    partition by deviceId from DeviceStatus    initiated by DeviceStatus(turnedOn = true)    terminated by DeviceStatus(turnedOn = false);

Контекст это своего рода окно, в рамках которого мы будет наблюдать входящие события.

// для выражения можно задать имя, чтобы видеть его в логах@Name('Unattended device')// указывая контекст, мы говорим, чтобы данное выражение// выполнялось только для событий из контекстаcontext TurnerOnDeviceContextselect    ds.zoneId,    ds.deviceIdfrom    // в качестве источника событий задаем шаблон,    // который словами можно сформулировать так:    // Устройство включили  потом Все ушли  потом (Прошло 10 минут И Никто не вернулся)    pattern [        ds = DeviceStatus(turnedOn = true)        -> every (            PersonsInZone(zoneId = ds.zoneId and number = 0)            -> (timer:interval(10 minutes)                    and not PersonsInZone(zoneId = ds.zoneId and number > 0)               )        )    ];

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

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

Таким образом, мы получим ситуацию, когда часть шаблона Все ушли ("Прошло 10 минут И Никто не вернулся) будет найден снова, в то время, как первая часть Устройство включили уже была найдена ранее. И, чтобы целый шаблон найти ещё раз, нужно написать every перед второй его чатью.

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

%esperscenario// задаем начальное времяt = 2020-12-10 12:00:00.000// публикуем событие в помещение A вошёл 1 сотрудникPersonsInZone = {zoneId=room-A, number=1}// через 1 минуту включаем генератор 1 в помещении Аt = t.plus(1 minute)DeviceStatus = {deviceId=generator-1, zoneId=room-A, turnedOn=true}// через 4 часа сотрудник вышел из помещения А, не выключив генераторt = t.plus(4 hours)PersonsInZone = {zoneId=room-A, number=0}// прошло ещё 10 минут  и должно сработать наше правило!t = t.plus(10 minute)

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

Unattended device-output={ds.zoneId='room-A', ds.deviceId='generator-1'}

Вот ещё один пример сценария, посложнее:

%esperscenariot = 2020-12-10 12:00:00.000// сотрудник вошёл в помещение АPersonsInZone = {zoneId=room-A, number=1}// через 1 минуту включил генератор 1t = t.plus(1 minute)DeviceStatus = {deviceId=generator-1, zoneId=room-A, turnedOn=true}// через 30 минут вышел, не выключив генераторt = t.plus(30 minutes)PersonsInZone = {zoneId=room-A, number=0}// но через 5 минут вернулсяt = t.plus(5 minute)PersonsInZone = {zoneId=room-A, number=1}// прошло ещё 5 минут  тревоги не должно быть, сотрудник ведь вернулсяt = t.plus(5 minute)// ещё через 3 часа ушёл, а генератор всё также остался включённымt = t.plus(3 hour)PersonsInZone = {zoneId=room-A, number=0}// через 10 минут  тревога!t = t.plus(10 minute)

Этот же пример, но с полноценной интеграцией с Kafka, который можно собрать и запустить, доступен по ссылке digital-worker-architecture.

В двух словах, его отличие в том, что нужно:

  1. настроить движок Esper-а подключить к нему плагины для взаимодействия с Kafka;

  2. зарегистрировать типы классов, которые будут представлять события в Kafka, и десериализатор для них.

И тогда при описании правил можно уже не создавать схемы событий, а использовать имена классов событий. А результат работы выражений (select-ов) оборачивать в создание выходных событий, которые публиковать в соответствующие топики Kafka.

Всех посчитали: регистрация внештатных ситуаций

CEP-процессор при срабатывании правил делает следующее:

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

  • Формирует событие-нотификацию, которое, как и все остальные события в Цифровом рабочем, публикуются в свой топик в Kafka. На этот топик подписан модуль Нотификаций, который выполняет их маршрутизацию. В результате нотификация передается в UI (оператор видит уведомление) или конкретному сотруднику через тот канал, который для него определён (например, на почту, в Telegram или на метку, которую носит сотрудник, если она поддерживает обратный канал).

Летим по приборам: аналитика

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

Виджеты это те же отчёты, у которых есть какие-то свои входные параметры, но результат выводится не в Excel или PDF-файл, а в виде графика или диаграммы. Еще виджеты обновляются раз в 15 секунд, что позволяет оператору видеть актуальные на текущий момент времени данные.

Также существуют отчёты со специализированным отображением информации непосредственно на карте (тепловая карта и маршруты):

Данные, по которым строится аналитика, хранятся в БД ClickHouse. Но прежде, чем попасть в ClickHouse, они проходят дополнительную обработку в модуле Подготовки данных. А, чтобы достать эти данные из БД и передать потребителю (в данном случае, в UI), используется модуль Формирования отчётов.

ClickHouse

К аналитической БД у нас были следующие требования:

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

  • нужно быстро выполнять запросы с условием С ПО, т.е. за определённый период времени.

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

Из особенностей ClickHouse мы для себя выделили следующие:

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

  • Хорошо подходит для Time-serias данных ClickHouse может партиционировать таблицу по ключу, который является функцией от временной метки события, что позволяет хранить в общей партиции все события полученные, например, за один и тот же день. А это позволяет эффективно выполнять запросы, у которых задан период времени (сперва будут выбраны только нужные партиции, а уже потом только по ним выполняется остальная часть запроса).

  • Есть встроенная интеграция с Kafka ClickHouse напрямую из Kafka умеет загружать данные в таблицы, при этом можно дополнительно выполнять обработку данных непосредственно в момент их загрузки.

  • Есть возможность подключить внешнюю реляционную БД мы подключаем справочники, которые храним в PostgreSql, после чего их можно использовать как обычные таблицы в Sql-выражениях.

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

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

Что касается схемы БД, то она устроена примерно так:

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

  • Но также есть специализированные таблицы, которые хранят данные в ином виде, удобном для формирования каких-то конкретных отчётов.

  • И придерживаемся принципа: данные в БД готовим исходя из сценария их использования (какие именно запросы будем выполнять к БД и с какими условиями фильтрации).

Подготовка данных

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

Модуль подготовки данных это Kafka Streams приложение, которое обрабатывает бизнес-события и выполняет следующие действия:

  • фильтрация бизнес-событий может быть очень много (например, события перемещения сотрудника), а для некоторых отчётов все они не нужны, и их можно проредить;

  • денормализация и обогащение чтобы при формировании отчёта лишний раз не выполнять join-ы, здесь мы заранее собираем все необходимые данные, например, по ИД сотрудника получаем его ФИО и название должностной позиции;

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

Формирование отчётов

Для того, чтобы получить отчёт, заказчик отчёта отправляет в топик Kafka report-request событие-запрос. Здесь мы отходим от принципа один тип события один топик для каждого конкретного отчёта существует свой тип события, который содержит специфичные для данного отчёта параметры. Но при этом все они унаследованы от базового класса ReportRequest.

Эти ReportRequest-ы обрабатывает модуль формирования отчётов:

  • по типу запроса определяется генератор запроса;

  • генератор формирует специфичный для отчёта SQL-запрос в ClickHouse, и, при необходимости, выполняет дополнительную обработку результата SQL-запроса уже на стороне java-кода;

  • результат работы генератора, если нужно, преобразуется в Excel или Pdf файл, который сохраняется в файловое хранилище;

  • создается событие-ответ, унаследованное от базового ReportResponse-а, которое содержит данные отчёта или ссылку на файл в хранилище.

  • в событие-ответ добавляется информация о событии-запросе, чтобы заказчик отчёта мог связать ответ с ранее отправленных запросов, после чего оно публикуется в топик report-response.

Мы выбрали такую схему формирования отчётов, потому что:

  • хотели сделать запрос отчётов асинхронным, чтобы не блокировать заказчика отчёта, пока тот формируется (обычно отчёты формируются быстро, но если задать очень большой временной интервал, за который нужно получить данные, то придется подождать);

  • хотели предоставить возможность формировать отчёты любым клиентам, у которых будет доступ к соответствующим топикам Kafka; это могут быть как модули Цифрового рабочего, так и внешние системы, с которыми мы интегрируемся;

  • использование Kafka автоматически позволяет масштабировать модули формирования просто поднимаем несколько узлов и получаем балансировку нагрузки (каждый узел обрабатывает свои партиции топика report-request).

Файловое хранилище

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

  • 3D-модели зданий, которые загружаются на клиента при отрисовке карты.

  • Сформированные отчёты.

  • Возможно, какой-то ещё статический контент.

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

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

  • Научиться получать большой список файлов из Sling-а так, чтобы не вычитывать каждый файл всякий раз для получения его размера;

  • Попробовать другое хранилище.

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

Заменили Sling на S3. У него не было проблем с получением большого списка файлов, а как бонус мы перестали поднимать свое файловое хранилище на стендах, а стали использовать S3, поднятое в облаке КРОК. Т.е. немного упростили процесс развертывания системы.

Как это было: потоки событий и воспроизведение истории

Если посмотреть на все модули системы вместе, то можно связать их потоками событий, которые протекают между ними:

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

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

Этот механизм реализован следующим образом:

  • UI подписывается на нужные ему события с помощью нашего KafkaConsumer-а, который инкапсулирует взаимодействие с Kafka и имеет два режима работы: REAL_TIME и PAST_TIME.

  • Если включен режим REAL_TIME, то KafkaConsumer просто передает события, которые в данный момент поступают в топики Kafka.

  • А когда включен режим PAST_TIME (при его включении необходимо задать период времени в прошлом), то KafkaConsumer вычитывает события из топиков, начиная с offset-а, соответствующего началу периода, и заканчивая offset-ом конца периода. При этом KafkaConsumer делает задержки между событиями, чтобы передавать их потребителю с тем же темпом, с которым они поступали в реальном времени.

Плюсы этого решения такие:

  • для истории не нужно отдельного хранилища вся история хранится в Kafka; при этом retention можно задавать большим только для тех топиков, которые нужны для воспроизведения истории;

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

Но есть и минус: в начальный момент времени периода в прошлом мы не можем получить полное состояние системы. Предположим, в 12:00 в кабинет вошло 10 сотрудников, а к 13:00 у половины из них сел аккумулятор метки, и она перестала передавать события со своим местоположением. Тогда воспроизводя историю с 13:00, мы увидим в этом кабинете только 5 сотрудников, у которых метки продолжили работать, т.к. только от этих меток в топиках будут события, начиная с 13:00.

Я подозреваю, что решить эту проблему только на базе Kafka не получится. Но сейчас текущее решение удовлетворяет нашим потребностям, поэтому мы его не трогаем. А как вариант на будущее, можно будет перенести хранение истории в ClickHouse и сделать Consumer, который будет для REAL_TIME-режима ходить в Kafka, а для PAST_TIME в ClickHouse.

А что у вас?

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

Было бы интересно услышать в комментариях, разрабатываете ли вы что-то подобное, например, в области IoT с потоковой обработкой данных, какие технологии применяете и как?

И, кстати, вот: Оцифровка рабочего в режиме реального времени - мой доклад на SmartData conf.

Подробнее..

Сам сломаю, сам и починю как я эпически нажал не туда на проде

14.04.2021 10:21:24 | Автор: admin
Привет, Хабр!

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

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

Начинается история так: заказчик хочет перенести на эту группу коммутаторов ядро всей сети. Такое решение обусловлено тем, что архитектура ACI, в которую собрана эта группа коммутаторов очень отказоустойчивая. Хотя это не типично и в целом фабрика в любом ЦОД не используется как транзитная сеть для других сетей и служит только для подключения конечной нагрузки (stub network). Но такой подход вполне имеет место быть, поэтому заказчик хочет мы делаем.

Дальше произошло банальное я перепутал две кнопки: удаления политики и удаления конфига фрагмента сети:

image

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

По порядку


Запрос заказчика звучал так: нужно было построить отдельные порт-группы под перенос оборудования непосредственно на эту фабрику.
Коллеги, просьба перенести настройки портов Leaf 1-1 101 и leaf 1-2 102, порты 43 и 44, на Leaf 1-3 103 и leaf 1-4 104, порты 43 и 44. К портам 43 и 44 на Leaf 1-1 и 1-2 подключён стек 3650, он пока не введён в эксплуатацию, переносить настройки портов можно в любое время.

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

Проблема в том, что на фабрике настройки этих порт-групп привязаны к отдельной сущности (которая возникает вследствие того, что фабрика управляется с контроллера). Этот объект называется port policy. То есть к группе портов, которые мы добавляем, нужно ещё сверху применить общую политику как сущность, которая будет управлять этими портами.
То есть нужно было сделать анализ, какие EPG используются на портах 43 и 44 на нодах 101 и 102 для того, чтобы собрать аналогичную конфигурацию на нодах 103-104. После анализа необходимых изменений я начал настраивать ноды 103-104. Для настройки нового VPC в существующей политике интерфейсов для нод 103 и 104 нужно было создать политику, в которую будут заведены интерфейсы 43 и 44.

И там есть в GUI один нюанс. Я создал эту политику и понял, что в процессе конфигурирования допустил незначительную ошибку, назвал её не так, как принято у заказчика. Это не критично потому что политика новая и ни на что не влияет. И мне эту политику нужно было удалить, поскольку изменения в неё уже внести нельзя (название не меняется) можно только удалить и заново политику создать.

Проблема в том, что в GUI есть иконки удаления, которые относятся к политикам интерфейса, а есть иконки, которые относятся к политикам коммутатора. Визуально они почти идентичны. И я вместо того, чтобы удалить политику, которую я создал, удалил всю конфигурацию для интерфейсов на коммутаторах 103-104:

image

Вместо удаления одной группы фактически удалил все VPC из настроек ноды, использовал delete вместо trashbin.

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

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

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

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

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

Восстановление фабрики


На восстановление фабрики с учётом всех звонков и сбора всех причастных ушло 30 минут.

Нашли другой VPN, через который можно зайти (это потребовало согласования с безопасниками), и я откатил конфигурацию фабрики в Cisco ACI это делается в два клика. Ничего сложного нет. Просто выбирается точка восстановления. Занимает это 1015 секунд. То есть на само восстановление ушло 15 секунд. Всё остальное время было потрачено на то, чтобы понять, как получить удалённое управление.

image

После инцидента


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

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

Так же мы покопались глубже в ПО Cisco Network Assurance Engine (NAE), где нашли возможность сделать на фабрике ACI две простые, но очень важные вещи:

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

Если интересно больше деталей у нас завтра вебинар про внутреннюю кухню техподдержки, будем рассказывать, как всё устроено у нас и у вендоров. Ошибки тоже будем разбирать)
Подробнее..

Свершилось ценники, которые всегда актуальны, пилот на 79 тысяч штук в магазине

22.04.2021 10:12:30 | Автор: admin
image
(фото из зарубежного проекта вместо текущего по просьбе безопасников)

До этого в России были внедрения электронных ценников в рознице (МАН, Магнит и так далее), но использовались устройства без сетевой связности, то есть нужно было ходить и обновлять их с помощью программатора либо выставлять на них цену кнопками, как на электронных часах. Плюс прошлые поколения ценников были с жидкокристаллическими дисплеями и суровым bluetooth, а новые с e-ink и сильно переделанной версией IEEE 802.15.4 с поддержкой сна и невероятно экономичных по питанию транзакций. То есть прошлым надо было менять батарею раз в три-семь дней, а новые уже держат два года (по заявлению производителя, пока не было шанса проверить, но аналогичные устройства LORA мы начали использовать лет десять назад, и один-два года похоже на правду), причём год это в секции холодильников, где аккумуляторы должны чувствовать себя зябко.

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

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

Пока накрыто два крупных магазина федеральной розничной сети, там 79 тысяч ценников. Если этот проект проживёт полгода успешно, через год ждите такое почти по всей России и наконец-то пропадут проблемы про мы не успели переклеить и акция уже кончилась. Но, возможно, будут новые с тем, что в 18:30 алкоголь будет дороже, чем в 7:00.

Что за устройства


Каждый отдельный модуль представляет из себя экран e-ink с несколькими вариациями цветов (это не RGB, а, скорее, примерный аналог CGA) + управляющая плата + радиоустройство + две плоских батареи C2R2 (в ценниках больше батареи другие).

image

Больше деталей про ценники вот здесь.

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

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

Радиомодуль


Используется протокол ZigBee. Это надстройка к IEEE 802.15.4, созданная специально для медленных IoT с низким потреблением питания. Особенности очень устойчивая сеть с mesh-топологией (хотя у нас это больше похоже на просто звёзды до точек доступа), самовосстановление сети и гарантированная доставка пакетов, даже если устройство надолго выпало из сети или отказал один из опорных узлов. Большую часть времени радиомодуль спит, но иногда просыпается, ждёт апдейта и снова спит, если его нет. Диапазон 2,42,48 ГГц (стандарт позволяет и другие, но это базовый), заявленная скорость 250 Кбит/с в лабораторных условиях, фактическая около 58 Кбит/с (это не сюрприз). Пакеты апдейта цены обычно как раз на секунду.

Архитектура выглядит так:

image

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

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

Расширенные возможности


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

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

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

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

Сам ценник можно брендировать по рамке под компанию, выбирая её цвет.

Как шло внедрение устройств


Основная масса устройств ценники с экраном 2,9 дюйма с двумя батареями C2R2. Полностью процедура замены крышки с батареями занимает 2540 секунд в зависимости от того, насколько вы опытны (и не обгрызли ли вы ногти). Предполагается, что после вставки батарей ценники себя находят в сети сразу и даже как-то базово определяют своё геометрическое положение относительно базовой станции.

В нашем случае порядка к 4-5 % пришлось подносить программатор (устройство ближнего радиодиапазона) и давать ребут. После такого пинка устройства находились сразу.

image

Полноценное радиообследование магазина не делали, но подозревали, что сложности будут на железных шкафах и в ряде мест с товарами хозназначения из металла. Диапазон выбирался между 1,9 до 5 ГГц, остановились на каналах чуть выше 2,4. На помехи им, в общем-то, плевать из-за протоколов доставки он-деманд, то есть по факту получения сообщения. А оно доставляется всегда, это тоже в протоколе. По-хорошему обследование на таких проектах нужно, это в перспективе означает меньшее энергопотребление оконечных устройств. У нас же была готовая карта расстановки, которую рекомендовал вендор на основе планировки магазина, но вендор до этого не знал, как у нас охраняют колбасу, поэтому в молочку и в мясной отдел мы понатыкали примерно в два раза больше точек. В прикассовой зоне устройства начали создавать помехи друг другу: там мелкие товары, большая плотность устройств, тоже пришлось раскидывать по диапазону шире.

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

Весь немаленький магазин накрыли за пять дней:

  1. Затяжка кабелей (для точек доступа).
  2. Установка креплений.
  3. Установка самих точек доступа.
  4. Конфигурация сети и подключение оконечных устройств.
  5. Проверка работы, перезагрузка, где это требуется (почти везде!).

Но потом кое-что пошло не так.

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

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

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

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

Итог


image
Подробнее..

Внутренняя автоматизация почему мы отказались от low-code системы в пользу Camunda

17.06.2021 10:17:44 | Автор: admin

Привет! Меня зовут Мирослав, я инженер-разработчик проекта по реализации BPM-решений для внутренней автоматизации КРОК.

Наш проект не гоняет миллионы строк каждую ночь через фильтры и правила, это не сложная система, которая отвечает за кадровую информацию, бюджетирование или сведение план-факта. Наш проект автоматизирует КРОК на самом понятном пользователю языке их у нас сейчас более 2 000 сотрудников. Если есть рутинная задача, которую можно представить в BPMN, мы ее реализуем.

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

Теперь пользователь просто прописывает путь к папке, выбирает тип доступа (чтение/редактирование), оставляет при желании какой-нибудь увлекательный комментарий и все, дальше все делает BPMN.

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

Каким мы хотели видеть BPMS

Потребность в новой BPM-системе стала очевидной еще в 2018 году. Текущая K2 4.7 не шла в ногу со временем, а K2 5.0 не устроила нашу команду. В конце 2018 года менеджер нашего проекта в компании пары аналитиков начали изучать рынок BPM-решений в поисках альтернативы.

Тогда как раз набирала обороты глобальная трансформация КРОК (что это значит, в одном абзаце не объяснить, поэтому просто оставлю это здесь как факт). Бизнес повсеместно стремился к изменениям, и это, конечно же, влияло на нас. То, как было по-старому, работать перестало нужны были гибкая разработка, регулярные демо, работа бок о бок с заказчиком на понятном ему языке.

Нашей идеальной системе предстояло усилить взаимодействие команды с заказчиками и ускорить процесс разработки. Для этого отлично подходили iBPMS, в которых, при нашем сценарии использования, ведущая роль разработки отводилась аналитику и автогенерируемому интерфейсу. Именно аналитик должен был проектировать BPM-схему, собирать модель данных и создавать страницы в UI-дизайнере. Разработчики, в свою очередь, должны были насытить BPM-схему логикой при помощи скриптов, а также развернуть окружение и наладить workflow внедрения новых бизнес-процессов.

Спустя пару месяцев наш выбор пал на Bonita, а в феврале 2019 года мне поручили ее внедрение на нашем проекте.

Опыт использования Bonita

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

Архитектура Bonita BPMАрхитектура Bonita BPM

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

Bonita Studio

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

С чем столкнулись

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

Вот так выглядит BPMN-схема для процесса "Выдача прав доступа" в BonitaВот так выглядит BPMN-схема для процесса "Выдача прав доступа" в Bonita
  • Ограничение лицензии не позволяло нам открыть два окна Bonita Studio, а значит, два проекта одновременно, чтобы скопировать схемы или скрипты.

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

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

    Дальше мы старались писать фронтенд по старинке, при помощи Angular 2+, и налаживать взаимодействие с Bonita через REST API.

Bonita Portal

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

С чем столкнулись

  • Такое пространство удобное решение, если нет необходимости его дорабатывать. У Bonita есть возможность кастомизировать портал при помощи архивов стилей, накатываемых прямо в Web. Мы легко перекрасили оформление и даже поменяли язык всего портала на русский. Но когда дело дошло до каких-то детальных изменений, не предусмотренных BonitaSoft, мы столкнулись с проблемой для подобных доработок Bonita Portal не был приспособлен.

  • В Bonita Portal можно редактировать скрипты и параметры бизнес-процессов в runtime. Это достаточно мощное решение, с которым можно здесь и сейчас устранить проблемы пользователей, но в перспективе эта опция создает огромные проблемы и хаос в Production среде. И естественно с этими перспективами мы столкнулись лицом к лицу. Но это уже совсем другая история :D.

Bonita Runtime

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

Version Control

Это опция Bonita Studio, которая обеспечивает взаимодействие с Git-репозиториями. Не очень красивая, и на самом деле, совершенно необязательная, так как можно воспользоваться каким угодно иным инструментом для работы с Git. Но работает исправно :)

Bonita Storage

С чем столкнулись

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

  • После создания модель данных содержалась в xml-файле, который необходимо было заархивировать и развернуть в Bonita Portal.

XML-схема, которую генерит Bonita на основе business data model. Далее в соответствии с этой схемой будут созданы таблицы в БДXML-схема, которую генерит Bonita на основе business data model. Далее в соответствии с этой схемой будут созданы таблицы в БД

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

  • После деплоя архива с xml-схемой в BonitaPortal на ее основе создавались таблицы в заранее указанной базе данных. Выглядели они не совсем так, как нам хотелось. При этом в самой Bonita были ограничения по именованию объектов BDM. Все таблицы лежали в одной БД, хранить их иначе было невозможно. Для того, чтобы исключить пересечения именований, мы добавили префиксы, но в названиях таблиц (сущностей в модели данных) нельзя было использовать точки или нижние подчеркивания. В результате это были просто буквы, с которых начинались все названия сущностей.

    Еще были сложности с изменением модели данных. Добавление нового столбца или изменение Nullable могло обернуться вынужденным сносом всех данных из таблицы этого в проде мы допустить не могли.

Information systems

Пласт коннекторов, позволяющий Bonita взаимодействовать с внешними системами.Этот механизм облегчает жизнь разработчику можно подключиться к БД, SOAP, REST, отправлять письма. Пласт коннекторов, позволяющий Bonita взаимодействовать с внешними системами.Этот механизм облегчает жизнь разработчику можно подключиться к БД, SOAP, REST, отправлять письма.

С чем столкнулись

  • Основная проблема этого механизма - в его предопределенности. Здесь ситуация очень сильно похожа на Bonita Portal. В рамках задач, обозначенных BonitaSoft, коннекторы справлялись хорошо, но расширить их настройки или спектр применения было попросту невозможно. Да, мы могли создать самописные коннекторы, но тогда какой же это low-code? В итоге некоторые взаимодействия с внешними системами происходили через проставку из самописного сервиса.

Выводы

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

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

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

Поиск новой BPMS

В этот раз в выборе BPM системы участвовала большая часть проектной команды все те, кто был причастен к разработке процессов на Bonita. Пропустив через этот опыт решения из прошлого исследования, выбрали четырех финалистов Bizagi, ELMA, BpmOnline и Camunda.

Bizagi не устроила нас по цене, ELMA показалась слишком похожей на Bonita. BpmOnline мы смогли изучить подробнее, благодаря опыту наших коллег она уже используется в КРОК в качестве внутренней CRM-системы. В нашем случае она казалась не самым удачным вариантом могли быть трудности с поддержкой нетривиальных схем. У Camunda не было богатого набора инструментов iBPMS как у Bonita (но именно к ним у нас и было больше всего вопросов). Но зато у нее была Community-версия что стало дополнительным аргументом "за". Нам хотелось быстро и безболезненно протестировать решение, и быстро отмести его, если вдруг что-то опять пойдет не так. В общем-то, по этой причине мы выбрали ее качестве объекта для исследования и внедрения в тестовой среде.

Новая BPMS

Camunda - BPM Engine

Рассказывать о том, что такое Camunda можно долго, но на самом деле об этом уже написано достаточно статей. Вот, например, отличный материал от Tinkoff, позволяющий быстро и легко погрузиться в особенности этого BPM движка.

Добавлю лишь немного лайфхаков.

  • Ссылка на git-репозиторий с огромным количеством тестовых проектов Camunda на любой вкус, которые помогут быстрому старту и поиску решений проблем, возникших при самостоятельном знакомстве.

  • Ссылка на telegram-канал русскоязычного сообщества Camunda, куда можно обратиться за помощью, когда документация и Google не смогли подсказать решение. Эти ребята ни раз меня выручали в период знакомства с движком, за что им огромное спасибо :)

Наша основная проблема

Начав исследовать Camunda я столкнулся с очевидной проблемой. Camunda написана на Java, разворачивается в среде Java и расширяется при помощи Java-подобных языков. А вся наша команда пишет на .NET (надеюсь, у вас тоже проигралась заставка из Ералаша).

Вероятных решений было два:

  • Научиться писать на Java или Kotlin, но не растерять при этом навыков .NET, так как на поддержке у команды остается еще более двадцати бизнес-процессов

  • Интегрировать Camunda в нашу экосистему таким образом, чтобы рассинхрон стека как можно слабее повлиял на получаемый результат

Мы решили попробовать пойти по второму сценарию и вот что из этого получилось.

Новая концепция взаимодействия с BPM

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

Spring Boot

Java-часть нашей BPMS выглядит так:

Здесь мы используем Spring Boot, в который как зависимость импортируем Camunda.

У Camunda есть свой REST API и, конечно, BPMN-составляющая, а также своя БД, используемая для хранения процессных данных.BPM-движок через схему обращается к коду, написанному на Kotlin, который, в свою очередь, обращается к нашему .NET приложению для получения бизнес-данных.

.NET

Основная часть бизнес-процесса представляет из себя .NET приложение:

Бизнес-данные хранятся в БД, с помощью EF Core мы потребляем их в слой сервисов, где рассчитываем бизнес-логику и откуда обращаемся к Camunda REST API. Также у приложения есть формы на Angular для взаимодействия с пользователями и REST API для доступа к бизнес данным из Camunda и внешних систем.

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

Как теперь все устроено

За 8 месяцев мы исследовали и внедрили движок Camunda, а также мигрировали на него все бизнес-процессы, тем самым полностью отказавшись от Bonita BPM. Теперь у нас есть 3 отдельных Spring Boot приложения Camunda, под каждый бизнес-контур (Sales, HR и Production), самописный CROC BPM Portal, агрегирующий информацию о состоянии экземпляров процессов, и 4 бизнес-процесса, работающих в production-среде вот таких:


Выдача прав доступа

С него начался этот пост. Это инструмент, позволяющий автоматизировано получать права и доступ на файлы и папки КРОК.

Обходной лист

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

Согласование тендера

Мы упростили коммуникацию по согласованию участия в тендере и исключили из этого процесса электронную почту или мессенджеры. Теперь наши менеджеры используют автоматизированное приложение с продуманным WorkFlow.

Пульс проекта

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


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

Bonita Portal => CROC BPM Portal

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

Task-модуль CROC BPM Portal на тестеTask-модуль CROC BPM Portal на тесте

Bonita Runtime => Spring Boot и Camunda

Также, вместо standalone-подхода мы используем импорт библиотеки Camunda в Java-приложение. И таких приложений у нас несколько, в целях увеличения отказоустойчивости, каждое под свой бизнес-контур.

Bonita Storage => EF Core

Еще мы полностью контролируем бизнес-данные, для обновления БД используем миграции, а таблицы хранятся в удобном для нас виде:

Information systems => Самописные сервисы

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

Почему BPM это круто?

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

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

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

Что дальше?

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

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

Подробнее..

Смотрим в оба как мы сделали технологическое видеонаблюдение для завода

29.04.2021 10:23:13 | Автор: admin

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

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

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

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

Забудьте всё, чему учили в школе

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

  • массасоставляющих, определяющих выбор оборудования и технических решений;

  • проведение работ в условиях повышенной опасности;

  • взаимодействие с рядом служб предприятия;

  • очень много бюрократии.

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

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

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

Противогаз есть? Есть!

Тут сделаю первое отступление и расскажу, что на самом деле нельзя просто так прийти и начать делать свою работу, скажем, на нефтеперерабатывающем предприятии. Сначала мы должны были потратить один день на прохождение инструктажа и получение пропусков. Для этого мы 5 (пять!) часов в компании 100 любезных господ с вахты стояли в очереди на улице, чтобы прослушать важную информацию. Настрой был слегка негативный, но инструктаж на удивление оказался полезным: основные правила ОТ и ТБ мы, естественно, знаем, но на предприятии своя специфика и ее много. В дальнейшем всё это помогло нам сэкономить весьма крупную сумму на штрафах. Правила ТБ на таких предприятиях закон, и словить 50k штрафа вообще не проблема. Поэтому слушаем, расписываемся и бежим за пропуском.

Уже в следующий приезд мы заранее договорились, чтобы нас ждал начальник установки, иначе мы просто рисковали сразу уехать домой. Приехать и пойти на установки нельзя, в лучшем случае просто отберут пропуск. И, кстати, в таких проектах можно не волноваться про полезные для здоровья 20k шагов в день они точно будут. Площадки разбросаны по большой территории, и всё обойти сложно даже за два дня. Ещё и поэтому, кстати, СТВН и нужна: если оператор побежит осматривать установку, на это уйдёт немало времени.

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

Фото забавное, но сразу сделаю оговорку, что так на предприятии ходить было нельзя)) Противогаз просто должен быть с собойФото забавное, но сразу сделаю оговорку, что так на предприятии ходить было нельзя)) Противогаз просто должен быть с собой

Что для меня еще оказалось интересно, так это то, что промышленное предприятие живой и буквально бурлящий организм. Можно, например, столкнуться с ситуацией, когда эстакаду, на которой основывалась половина проекта, снесли, пока шло проектирование. А колонну размером с шестиэтажный дом перенесли в другое место. И да, то единственное здание на площадке, куда вы всё сводили, перестроили к концу проекта. Так что я вывел правило всегда интересоваться планами заказчика не только на текущий, но и на следующий год. Чтобы не получилось так, что при выходе на реализацию мы имеем дело с совсем другой площадкой. Ну и честно скажу, что ещё один из наших таких проектов был изменен в ходе работ по проектированию на 30-40%.

Подготовительный этап

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

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

Что еще важно при создании СТВН?

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

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

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

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

Технологии и решения: что мы использовали

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

В итоге у нас на проекте было:

  • 80 камер во взрывозащищенных кожухах типа Ex tb IIIС T80C. Они подбирались по специальным требованиям среды на площадках. Главная опасность пары горючих веществ и взрывоопасный газ. Мы выбрали специальное исполнение кожуха с герметичными вводами, чтобы даже в местах входа кабеля ничего не могло просочиться к нашему оборудованию. При это стоит особое внимание обратить именно на кабельные вводы, так как они отличаются в зависимости от типа используемого кабеля, его оплётки и брони. К каждому кожуху подходят питание и сам информационный кабель.

Внешний вид взрывозащищенного кожухаВнешний вид взрывозащищенного кожуха
  • 30 взрывозащищенных коммутаторов. Аналогично камерам выбирали и линейное оборудование. Все очень большое и тяжёлое, как мы любим, поэтому заранее требовалось подобрать и места для креплений. Как правило, нужны крепкие металлические или бетонные опоры. Вешали такие коммутаторы втроём. Для сравнения: есть боксовые уличные коммутаторы по сути, герметичная пластиковая коробка весом в 10 кг. Такую легко повесит и один человек. С кабельными вводами ещё интереснее теперь ты уже можешь ошибиться не на один вход в камеру, а на 6-8, так как это оборудование агрегации. И после подбора ещё пару ночей я просыпался в поту, что где-то ошибся на 2 мм, и кабель будет болтаться или не влезет.

 Коммутатор во взрывозащищенном кожухе Коммутатор во взрывозащищенном кожухе
  • 4 км оптического и 6 км медного кабеля и порядка 1,5 км лотков. Лоток есть лоток бери больше, кидай дальше. Но специфика предприятия в том, что надо всё делать на специальных эстакадах, а кроме нас там ещё 100500 устройств и линий. А поскольку эстакады высокие, нам нужен подъемник + куча согласований, план работ, и всё по ТБ. И да, красную ленточку для ограждения тоже не забываем, а то минус круглая сумма (в некоторые моменты реально задумываешься, что если бы люди знали, сколько штрафов они могли бы получить, то даже не подумали бы там работать. Но зато потом, уже прожжённым (плохое слово для завода) опытом, им ничего не страшно.

  • серверы, стойки, АРМ на всех площадках

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

Особенности инсталляции: крутить гайки можно, жечь нельзя

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

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

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

Как решали? Бригадир монтажников очень адекватно подошел к задаче много сам ходил и общался со службами на объекте. Где-то договаривались, где-то делали с нуля, иногда подключали заводское управление.

Что получилось

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

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

Если остались вопросы по теме поста, пишите в комментарии, постараюсь ответить. Моя почта IVoloshin@croc.ru

Подробнее..

Запускаем Rust-приложение на мобильной ОС Аврора

02.03.2021 10:09:04 | Автор: admin

Всем привет! Меня зовут Шамиль, я ведущий инженер-разработчик в КРОК. Помимо всего прочего мы в компании занимаемся ещё и разработкой мобильных приложений для операционной системы Аврора, есть даже центр компетенций по ней.

Для промышленной разработки мы, конечно же, пока используем связку C++ и QML, но однажды подсев на "ржавую" иглу Rust, я не мог не попробовать применить свой любимый язык программирования для написания мобильных приложений. В этой статье я опишу эксперимент по написанию простейшего приложения на Rust, предназначенного для запуска на мобильном устройстве под управлением вышеупомянутой ОС. Сразу оговорюсь, что легких путей я не искал эксперименты проводил на сертифицированной версии Авроры, которая добавила огонька в этот процесс. Но, как говорится, только защищённая ОС, только хардкор.

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

Готовим окружение

Итак, работа будет вестись из-под Ubuntu Linux с уже установленным Rust. В качестве подопытного планшета выступает Aquarius NS220 с сертифицированной ОС Аврора последней (на момент написания статьи) версии 3.2.2 с включённым режимом разработчика, который обеспечивает связь по SSH, а также привилегированный доступ с правами суперпользователя.

Первым делом добавим средства кросскомпилятора для архитектуры ARM, так как на целевом планшете стоит именно такой процессор.

sudo apt install -y g++-arm-linux-gnueabihfrustup target add armv7-unknown-linux-gnueabihf

В сертифицированной версии ОС Аврора не разрешается запускать неподписанные приложения. Подписывать надо проприетарной утилитой из состава Aurora Certified SDK под названием ompcert-cli, которая поддерживает на входе только пакет в формате RPM. Поэтому сразу установим замечательную утилиту cargo-rpm, которая возьмёт на себя всю рутинную работу по упаковке приложения в RPM-пакет:

cargo install cargo-rpm

Саму процедуру подписывания RPM-пакета я описывать не буду, она неплохо документирована в справочных материалах ОС Аврора.

Aurora SDK можно скачать с сайта производителя.

Часть 1. Hello. World

TL;DR Исходники проекта можно найти в репозитории на Гитхабе.

Создаем минимальный проект

Создаём пустое приложение на Rust:

cargo new aurora-rust-helloworld

Пытаемся сгенерировать .spec файл для RPM-пакета:

cargo rpm init

Получаем ошибки, что не хватает некоторых полей в Cargo.toml, добавляем их:

Cargo.toml:

[package]name = "aurora-rust-helloworld"version = "0.1.0"authors = ["Shamil Yakupov <syakupov@croc.ru>"]edition = "2018"description = "Rust example for Aurora OS"license = "MIT"

Закидываем в папку .cargo конфигурационный файл с указанием правильного линкера для компоновки исполняемого файла под архитектуру ARM:

.cargo/config.toml:

[target.armv7-unknown-linux-gnueabihf]linker = "arm-linux-gnueabihf-gcc"

Собираем RPM-пакет:

cargo rpm initcargo rpm build -v --target=armv7-unknown-linux-gnueabihf

Всё собралось, забираем RPM из папки target/armv7-unknown-linux-gnueabihf/release/rpmbuild/RPMS/armv7hl, подписываем его, копируем на планшет и пытаемся установить:

$ devel-suPassword:# pkcon install-local ./aurora-rust-helloworld-0.1.0-1.armv7hl.rpm

Получаем ошибку:

Fatal error: nothing provides libc.so.6(GLIBC_2.32) needed by aurora-rust-helloworld-0.1.0-1.armv7hl

Смотрим версию glibc на устройстве, и понимаем, что она явно ниже той, что нам требуется:

$ ldd --versionldd (GNU libc) 2.28

Что ж, тогда попробуем забрать нужные библиотеки с планшета, закинуть их в директорию lib и слинковать с ними. Для верности будем пользоваться линкером, входящим в состав Aurora SDK, который закинем в директорию bin. Для начала посмотрим, какие именно библиотеки нам нужны. Меняем содержимое .cargo/config.toml:

[target.armv7-unknown-linux-gnueabihf]rustflags = ["-C", "link-args=-L lib"]linker = "bin/armv7hl-meego-linux-gnueabi-ld"

Пробуем собрать:

cargo build --release --target=armv7-unknown-linux-gnueabihf

Получаем ошибки:

aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lgcc_saurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lutilaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lrtaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lpthreadaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lmaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -ldlaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lcaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find -lutil

Копируем недостающие библиотеки с планшета:

mkdir -p libscp nemo@192.168.2.15:/usr/lib/libgcc_s.so ./libscp nemo@192.168.2.15:/usr/lib/libutil.so ./libscp nemo@192.168.2.15:/usr/lib/librt.so ./libscp nemo@192.168.2.15:/usr/lib/libpthread.so ./libscp nemo@192.168.2.15:/usr/lib/libm.so ./libscp nemo@192.168.2.15:/usr/lib/libdl.so ./libscp nemo@192.168.2.15:/usr/lib/libc.so ./libscp nemo@192.168.2.15:/usr/lib/libutil.so ./lib

Снова пытаемся собрать, получаем новую порцию ошибок:

aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: skipping incompatible /lib/libc.so.6 when searching for /lib/libc.so.6aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /lib/libc.so.6aurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: skipping incompatible /usr/lib/libc_nonshared.a when searching for /usr/lib/libc_nonshared.aaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /usr/lib/libc_nonshared.aaurora-rust-helloworld/bin/armv7hl-meego-linux-gnueabi-ld: cannot find /lib/ld-linux-armhf.so.3

Копируем недостающее:

scp nemo@192.168.2.15:/lib/libc.so.6 ./libscp nemo@192.168.2.15:/usr/lib/libc_nonshared.a ./libscp nemo@192.168.2.15:/lib/ld-linux-armhf.so.3 ./lib

Ещё надо подредактировать файл libc.so (который является фактически скриптом линкера), чтобы дать понять линкеру, где надо искать библиотеки:

lib/libc.so:

/* GNU ld script   Use the shared library, but some functions are only in   the static library, so try that secondarily.  */OUTPUT_FORMAT(elf32-littlearm)GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux-armhf.so.3 ) )

Запускаем сборку RPM-пакета, копируем, пытаемся установить.

Здесь позволю себе небольшое лирическое отступление. Перед установкой RPM-пакета на сертифицированной версии ОС Аврора запускается RPM-валидатор утилита, которая проверяет, насколько собранный пакет удовлетворяет требованиям системы. И до тех пор, пока пакет не пройдёт валидацию, установить приложение не получится. Безопасность превыше всего.

Итак, мы видим, что валидатор выдал несколько ошибок:

вот таких
Desktop file============ERROR [/usr/share/applications/aurora-rust-helloworld.desktop] File is missing - cannot validate .desktop filePaths=====WARNING [/usr/share/aurora-rust-helloworld] Directory not foundERROR [/usr/share/applications/aurora-rust-helloworld.desktop] File not foundWARNING [/usr/share/icons/hicolor/86x86/apps/aurora-rust-helloworld.png] File not foundWARNING [/usr/share/icons/hicolor/108x108/apps/aurora-rust-helloworld.png] File not foundWARNING [/usr/share/icons/hicolor/128x128/apps/aurora-rust-helloworld.png] File not foundWARNING [/usr/share/icons/hicolor/172x172/apps/aurora-rust-helloworld.png] File not foundERROR [/usr/share/icons/hicolor/[0-9x]{5,9}/apps/aurora-rust-helloworld.png] No icons found! RPM must contain at least one icon, see: https://community.omprussia.ru/doc/software_development/guidelines/rpm_requirementsLibraries=========ERROR [/usr/bin/aurora-rust-helloworld] Cannot link to shared library: libutil.so.1Symbols=======ERROR [/usr/bin/aurora-rust-helloworld] Binary does not link to 9__libc_start_main@GLIBC_2.4.Requires========ERROR [libutil.so.1] Cannot require shared library: 'libutil.so.1'

Что ж, будем бороться с каждой ошибкой по списку.

Добавляем недостающие файлы

Добавим иконки и ярлык (файл с расширением desktop) в директорию .rpm.

.rpm/aurora-rust-helloworld.desktop:

[Desktop Entry]Type=ApplicationX-Nemo-Application-Type=silica-qt5Icon=aurora-rust-helloworldExec=aurora-rust-helloworldName=Rust Hello-World

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

Makefile
.PHONY: all clean install prepare release rpmall:@cargo build --target=armv7-unknown-linux-gnueabihfclean:@rm -rvf targetinstall:@scp ./target/armv7-unknown-linux-gnueabihf/release/aurora-rust-helloworld nemo@192.168.2.15:/home/nemo/@scp ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/RPMS/armv7hl/*.rpm nemo@192.168.2.15:/home/nemo/prepare:@rustup target add armv7-unknown-linux-gnueabihf@cargo install cargo-rpmrelease:@cargo build --release --target=armv7-unknown-linux-gnueabihfrpm:@mkdir -p ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES@cp -vf .rpm/aurora-rust-helloworld.desktop ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES@cp -rvf .rpm/icons ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES@cargo rpm build -v --target=armv7-unknown-linux-gnueabihf

Обновим aurora-rust-helloworld.spec:

.rpm/aurora-rust-helloworld.spec
%define __spec_install_post %{nil}%define __os_install_post %{_dbpath}/brp-compress%define debug_package %{nil}Name: aurora-rust-helloworldSummary: Rust example for Aurora OSVersion: @@VERSION@@Release: @@RELEASE@@%{?dist}License: MITGroup: Applications/SystemSource0: %{name}-%{version}.tar.gzSource1: %{name}.desktopSource2: iconsBuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root%description%{summary}%prep%setup -q%installrm -rf %{buildroot}mkdir -p %{buildroot}cp -a * %{buildroot}mkdir -p %{buildroot}%{_datadir}/applicationscp -a %{SOURCE1} %{buildroot}%{_datadir}/applicationsmkdir -p %{buildroot}%{_datadir}/icons/hicolor/86x86/appsmkdir -p %{buildroot}%{_datadir}/icons/hicolor/108x108/appsmkdir -p %{buildroot}%{_datadir}/icons/hicolor/128x128/appsmkdir -p %{buildroot}%{_datadir}/icons/hicolor/172x172/appscp -a %{SOURCE2}/86x86/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/86x86/appscp -a %{SOURCE2}/108x108/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/108x108/appscp -a %{SOURCE2}/128x128/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/128x128/appscp -a %{SOURCE2}/172x172/%{name}.png %{buildroot}%{_datadir}/icons/hicolor/172x172/apps%cleanrm -rf %{buildroot}%files%defattr(-,root,root,-)%{_bindir}/*%{_datadir}/applications/%{name}.desktop%{_datadir}/icons/hicolor/*/apps/%{name}.png

Для сборки пакета теперь достаточно выполнить:

make rpm

Убираем зависимость от libutil.so

Я не нашёл способа, как убедить cargo при вызове команды линкера не передавать ключ -lutil. Вместо этого я решил создать скрипт-заглушку для линкера с какой-нибудь незначащей командой.

lib/libutil.so:

/* GNU ld script   Dummy script to avoid dependency on libutil.so */ASSERT(1, "Unreachable")

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

Добавляем символ __libc_start_main

Перепробовав несколько способов, остановился на том, чтобы добавить при линковке стандартный объектный файл crt1.o. Копируем его с планшета:

scp nemo@192.168.2.15:/usr/lib/crt1.o ./lib

И добавляем в команды линкера:

.cargo/config.toml:

[target.armv7-unknown-linux-gnueabihf]rustflags = ["-C", "link-args=-L lib lib/crt1.o"]linker = "bin/armv7hl-meego-linux-gnueabi-ld"

Однако при попытке сборки получаем ошибки:

undefined reference to `__libc_csu_fini'undefined reference to `__libc_csu_init'

Добавим заглушки этих функций в main.rs:

src/main.rs:

#[no_mangle]pub extern "C" fn __libc_csu_init() {}#[no_mangle]pub extern "C" fn __libc_csu_fini() {}fn main() {    println!("Hello, world!");}

Ещё один быстрый и грязный хак, зато теперь RPM-пакет проходит валидацию и устанавливается!

Момент истины близок, запускаем на планшете и получаем очередную ошибку:

$ aurora-rust-helloworld-bash: /usr/bin/aurora-rust-helloworld: /usr/lib/ld.so.1: bad ELF interpreter: No such file or directory

Смотрим зависимости:

$ ldd /usr/bin/aurora-rust-helloworldlinux-vdso.so.1 (0xbeff4000)libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xa707f000)librt.so.1 => /lib/librt.so.1 (0xa7069000)libpthread.so.0 => /lib/libpthread.so.0 (0xa7042000)libm.so.6 => /lib/libm.so.6 (0xa6fc6000)libdl.so.2 => /lib/libdl.so.2 (0xa6fb3000)libc.so.6 => /lib/libc.so.6 (0xa6e95000)/usr/lib/ld.so.1 => /lib/ld-linux-armhf.so.3 (0xa70e7000)

И видим динамическую линковку с библиотекой ld-linux-armhf.so.3. Если решать в лоб, то нужно создать символическую ссылку /usr/lib/ld.so.1 /lib/ld-linux-armhf.so.3 (и это даже будет неплохо работать). Но, к сожалению, такое решение не подходит. Дело в том, что строгий RPM-валидатор не пропустит ни пред(пост)-установочные скрипты в .spec-файле, ни деплой в директорию /usr/lib. Вообще список того, что можно, приведён здесь.

Долгое и разнообразное гугление подсказало, что у линкера GCC есть нужный нам ключ (dynamic-linker), который позволяет сослаться непосредственно на нужную зависимость. Правим config.toml:

.cargo/config.toml:

[target.armv7-unknown-linux-gnueabihf]rustflags = ["-C", "link-args=-L lib lib/crt1.o --dynamic-linker /lib/ld-linux-armhf.so.3"]linker = "bin/armv7hl-meego-linux-gnueabi-ld"

Собираем RPM-пакет, подписываем, копируем на планшет, устанавливаем и с замиранием сердца запускаем:

$ aurora-rust-helloworldHello, world!

Часть 2. Запускаем приложение с GUI

TL;DR Исходники проекта можно найти в репозитории.

В Авроре всё очень сильно завязано на Qt/QML, поэтому сначала я думал использовать крейт qmetaobject. Однако в комплекте с ОС идёт библиотека Qt версии 5.6.3, а qmetaobject, судя по описанию, требует минимум Qt 5.8. И действительно, попытка сборки крейта приводит к ошибкам.

Поэтому я пошёл по пути точечных заимствований из исходников qmetaobject благо, лицензия позволяет.

Для начала копируем проект, созданный в предыдущей части, и переименовываем его в aurora-rust-gui.

Приступаем

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

вот таких
scp nemo@192.168.2.15:/usr/lib/libstdc++.so ./libscp nemo@192.168.2.15:/usr/lib/libQt5Core.so.5 ./lib/libQt5Core.soscp nemo@192.168.2.15:/usr/lib/libQt5Gui.so.5 ./lib/libQt5Gui.soscp nemo@192.168.2.15:/usr/lib/libQt5Qml.so.5 ./lib/libQt5Qml.soscp nemo@192.168.2.15:/usr/lib/libQt5Quick.so.5 ./lib/libQt5Quick.soscp nemo@192.168.2.15:/usr/lib/libGLESv2.so.2 ./libscp nemo@192.168.2.15:/usr/lib/libpng16.so.16 ./libscp nemo@192.168.2.15:/usr/lib/libz.so.1 ./libscp nemo@192.168.2.15:/usr/lib/libicui18n.so.63 ./libscp nemo@192.168.2.15:/usr/lib/libicuuc.so.63 ./libscp nemo@192.168.2.15:/usr/lib/libpcre16.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libglib-2.0.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libsystemd.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libQt5Network.so.5 ./libscp nemo@192.168.2.15:/lib/libresolv.so.2 ./libscp nemo@192.168.2.15:/usr/lib/libhybris-common.so.1 ./libscp nemo@192.168.2.15:/usr/lib/libicudata.so.63 ./libscp nemo@192.168.2.15:/usr/lib/libpcre.so.1 ./libscp nemo@192.168.2.15:/usr/lib/libselinux.so.1 ./libscp nemo@192.168.2.15:/usr/lib/liblzma.so.5 ./libscp nemo@192.168.2.15:/usr/lib/libgcrypt.so.11 ./libscp nemo@192.168.2.15:/usr/lib/libgpg-error.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libcap.so.2 ./libscp nemo@192.168.2.15:/usr/lib/libsailfishapp.so.1 ./lib/libsailfishapp.soscp nemo@192.168.2.15:/usr/lib/libmdeclarativecache5.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libmlite5.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libdconf.so.1 ./libscp nemo@192.168.2.15:/usr/lib/libgobject-2.0.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libQt5DBus.so.5 ./libscp nemo@192.168.2.15:/usr/lib/libdconf.so.1 ./libscp nemo@192.168.2.15:/usr/lib/libffi.so.6 ./libscp nemo@192.168.2.15:/usr/lib/libdbus-1.so.3 ./libscp nemo@192.168.2.15:/usr/lib/libgio-2.0.so.0 ./libscp nemo@192.168.2.15:/usr/lib/libgmodule-2.0.so.0 ./lib

А еще копируем заголовочные файлы, которые идут в составе Aurora SDK:

  • AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/qt5 include/qt5

  • AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/sailfishapp include/sailfishapp

  • AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/GLES3 include/GLES3

  • AuroraOS/mersdk/targets/AuroraOS-3.2.2.21-cert-armv7hl/usr/include/KHR include/KHR

Для сборки проекта напишем скрипт build.rs и укажем его в Cargo.toml.

build.rs:

fn main() {    let include_path = "include";    let qt_include_path = "include/qt5";    let sailfish_include_path = "include/sailfishapp";    let library_path = "lib";    let mut config = cpp_build::Config::new();    config        .include(include_path)        .include(qt_include_path)        .include(sailfish_include_path)        .opt_level(2)        .flag("-std=gnu++1y")        .flag("-mfloat-abi=hard")        .flag("-mfpu=neon")        .flag("-mthumb")        .build("src/main.rs");    println!("cargo:rustc-link-search={}", library_path);    println!("cargo:rustc-link-lib=sailfishapp");    println!("cargo:rustc-link-lib=Qt5Gui");    println!("cargo:rustc-link-lib=Qt5Core");    println!("cargo:rustc-link-lib=Qt5Quick");    println!("cargo:rustc-link-lib=Qt5Qml");}

Cargo.toml:

[package]# ...build = "build.rs"[dependencies]cpp = "0.5.6"[build-dependencies]cpp_build = "0.5.6"#...

Теперь возьмёмся за само приложение. За создание инстанса приложения у нас будет отвечать структура SailfishApp по аналогии с приложением для Авроры, написанном на C++.

src/main.rs:

#[macro_use]extern crate cpp;mod qbytearray;mod qstring;mod qurl;mod sailfishapp;use sailfishapp::SailfishApp;#[no_mangle]pub extern "C" fn __libc_csu_init() {}#[no_mangle]pub extern "C" fn __libc_csu_fini() {}fn main() {    let mut app = SailfishApp::new();    app.set_source("main.qml".into());    app.show();    app.exec();}

SailfishApp это по сути обвязка (биндинги) к соответствующему классу на C++. Берём за образец структуру QmlEngine из крейта qmetaobject.

src/sailfishapp.rs
use crate::qstring::QString;cpp! {{    #include <sailfishapp.h>    #include <QtCore/QDebug>    #include <QtGui/QGuiApplication>    #include <QtQuick/QQuickView>    #include <QtQml/QQmlEngine>    #include <memory>    struct SailfishAppHolder {        std::unique_ptr<QGuiApplication> app;        std::unique_ptr<QQuickView> view;        SailfishAppHolder() {            qDebug() << "SailfishAppHolder::SailfishAppHolder()";            int argc = 1;            char *argv[] = { "aurora-rust-gui" };            app.reset(SailfishApp::application(argc, argv));            view.reset(SailfishApp::createView());            view->engine()->addImportPath("/usr/share/aurora-rust-gui/qml");        }    };}}cpp_class!(    pub unsafe struct SailfishApp as "SailfishAppHolder");impl SailfishApp {    /// Creates a new SailfishApp.    pub fn new() -> Self {        cpp!(unsafe [] -> SailfishApp as "SailfishAppHolder" {            qDebug() << "SailfishApp::new()";            return SailfishAppHolder();        })    }    /// Sets the main QML (see QQuickView::setSource for details).    pub fn set_source(&mut self, url: QString) {        cpp!(unsafe [self as "SailfishAppHolder *", url as "QString"] {            const auto full_url = QString("/usr/share/aurora-rust-gui/qml/%1").arg(url);            qDebug() << "SailfishApp::set_source()" << full_url;            self->view->setSource(full_url);        });    }    /// Shows the main view.    pub fn show(&self) {        cpp!(unsafe [self as "SailfishAppHolder *"] {            qDebug() << "SailfishApp::show()";            self->view->showFullScreen();        })    }    /// Launches the application.    pub fn exec(&self) {        cpp!(unsafe [self as "SailfishAppHolder *"] {            qDebug() << "SailfishApp::exec()";            self->app->exec();        })    }}

Биндинги для используемых классов QByteArray, QString, QUrl копируем из того же qmetaobject и расфасовываемым по отдельным файлам. Здесь приводить их не буду, если что, исходники можно посмотреть в репозитории на GitHub.

Немного скорректируем заголовочный файл sailfishapp.h, чтобы он искал заголовочные файлы Qt в правильных местах:

include/sailfishapp/sailfishapp.h:

// ...#ifdef QT_QML_DEBUG#include <QtQuick>#endif#include <QtCore/QtGlobal>  // Было `#include <QtGlobal>`#include <QtCore/QUrl>      // Было `#include <QUrl>`class QGuiApplication;class QQuickView;class QString;// ...

Осталось только добавить файлы QML и положить их в дистрибутив RPM.

все здесь

qml/main.qml:

import QtQuick 2.6import Sailfish.Silica 1.0ApplicationWindow {    cover: Qt.resolvedUrl("cover.qml")    initialPage: Page {        allowedOrientations: Orientation.LandscapeMask        Label {            anchors.centerIn: parent            text: "Hello, Aurora!"        }    }}

qml/cover.qml:

import QtQuick 2.6import Sailfish.Silica 1.0CoverBackground {    Rectangle {        id: background        anchors.fill: parent        color: "blue"        Label {            id: label            anchors.centerIn: parent            text: "Rust GUI"            color: "white"        }    }    CoverActionList {        id: coverAction        CoverAction {            iconSource: "image://theme/icon-cover-cancel"            onTriggered: Qt.quit()        }    }}

.rpm/aurora-rust-gui.spec:

# ...Source3: qml# ...%install# ...mkdir -p %{buildroot}%{_datadir}/%{name}cp -ra %{SOURCE3} %{buildroot}%{_datadir}/%{name}/qml%cleanrm -rf %{buildroot}%files# ...%{_datadir}/%{name}/qml

Makefile:

# ...rpm:# ...@cp -rvf qml ./target/armv7-unknown-linux-gnueabihf/release/rpmbuild/SOURCES# ...

Собираем:

make cleanmake releasemake rpm

Подписываем, копируем, устанавливаем, запускаем из командной строки и вуаля:

$ devel-suPassword:# pkcon install-local ./aurora-rust-gui-0.1.0-1.armv7hl.rpmInstalling filesTesting changesFinishedInstalling filesStartingResolving dependenciesInstalling packagesDownloading packagesInstalling packagesFinishedDownloaded  aurora-rust-gui-0.1.0-1.armv7hl (PK_TMP_DIR)         Rust GUI example for Aurora OSInstalled   aurora-rust-gui-0.1.0-1.armv7hl (PK_TMP_DIR)            Rust GUI example for Aurora OS# exit$ aurora-rust-gui[D] __cpp_closure_14219197022164792912_impl:33 - SailfishApp::new()[D] SailfishAppHolder::SailfishAppHolder:15 - SailfishAppHolder::SailfishAppHolder()[D] unknown:0 - Using Wayland-EGLlibrary "libpq_cust_base.so" not found[D] __cpp_closure_16802020016530731597:42 - SailfishApp::set_source() "/usr/share/aurora-rust-gui/qml/main.qml"[W] unknown:0 - Could not find any zN.M subdirs![W] unknown:0 - Theme dir "/usr/share/themes/sailfish-default/meegotouch/z1.0/" does not exist[W] unknown:0 - Theme dir "/usr/share/themes/sailfish-default/meegotouch/" does not exist[D] onCompleted:432 - Warning: specifying an object instance for initialPage is sub-optimal - prefer to use a Component[D] __cpp_closure_12585295123509486988:50 - SailfishApp::show()[D] __cpp_closure_15029454612933909268:59 - SailfishApp::exec()

Вот так выглядит наше приложение с разных ракурсов:

 Рабочий стол с ярлыком Рабочий стол с ярлыком Главное окно приложенияГлавное окно приложения Панель задач Панель задач

Последние штрихи

Приложение отлично стартует из командной строки при подключении по SSH, однако никак не реагирует при попытке запуска с помощью ярлыка. Путём некоторых экспериментов удалось установить, что для этого надо экспортировать символ main (RPM-валидатор выдавал предупреждение на этот счёт, но некритичное).

Серия проб и ошибок показала, что надо добавить ещё один ключ линкера: -export-dynamic.

.cargo/config.toml:

[target.armv7-unknown-linux-gnueabihf]rustflags = ["-C", "link-args=-L lib lib/crt1.o -rpath lib --dynamic-linker /lib/ld-linux-armhf.so.3 -export-dynamic"]linker = "bin/armv7hl-meego-linux-gnueabi-ld"

После этого всё работает так, как и ожидается.

Заключение

Понятно, что до того, как использовать Rust в проде, ещё надо решить немало вопросов. Как минимум, я предвижу сложности с дополнительными зависимостями при подключении новых крейтов, извечные танцы с бубном вокруг сегфолтов при FFI-вызовах, увязывание систем владения Qt и Rust. Некоторые интересные подробности можно почерпнуть из статьи от автора qmetaobject-rs. Наверняка, время от времени будут всплывать и другие проблемы.

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

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

Буду рад вопросам и замечаниям в комментариях. И ставьте лайк, подписывайтесь на канал :-)

Подробнее..

Как я ходил на удалённые собеседования JAVA-разработчика, чтобы лучше нанимать людей

16.03.2021 10:10:28 | Автор: admin

Если обычные разработчики ходят на собеседования тренироваться и набирать опыт, то я пошёл выписывать все косяки. Чтобы их не было у меня, потому что я нанимаю людей. Собственно, стало интересно, как устроено в других компаниях и я пошёл собеседоваться. Началось всё c базового набора: аккаунт зума, почта, резюме. Дальше можно пройти за неделю 10-12 собеседований, на что до тотальной удалёнки ушёл бы месяц.


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


image


Выложил на HH. Дальше ждать пришлось недолго. Первый час уже несколько откликов и звонок. Всего за сутки было 20 откликов и пять звонков. Предложений много, все с самыми интересными проектами, стеком, ДМС и макбуком (которого пока нет, но обязательно пришлём через месяц-два).


На третий день я набрал примерно 30 проектов, которые были бы мне интересны, если бы я действительно искал работу (пост бы неожиданно закончился здесь, если бы нашёл что-то более интересное, чем уже есть), и начал описывать то, что попало в отсев.


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


Первичный отсев


Что сразу попадало в отсев:


Когда HR пишет или говорит, что проекты классные, но не может сказать, чем они классные. Или хотя бы какие это проекты. Будет что-то там-то это не объяснение. Ещё одна интересная фраза команда 30 человек по скраму, но это не точно. Сразу в мусорник, нам не нужны неудачники.


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


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


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


Организация


Интересное:


  • Ачивка Самая быстрая рука на Диком Западе 40 минут на собеседование, обратная связь я бы взял и оффер.
  • Ачивка Тяжело, как поцеловать кобру обещанный один этап превратился в два по два часа, потом я получил оффер.
  • HR-специалисты в большинстве своём сами адекватны. Девушек больше, чем парней, но до этого много лет назад парней я вообще не видел на первичных собеседованиях. Почти никто не путал Java и Javascript. Несколько раз делали технический скрининг. Мало кто пытался копаться в моём личном текущей зарплате, сколько у меня детей или домашних животных, чем я занимаюсь в свободное время и так далее. Иногда собирают информацию о текущих офферах. В целом очень положительное впечатление.
  • Во всех отобранных мной вариантах собеседования назначались оперативно, с учётом моих хотелок. На собеседование все пришли вовремя.

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


Проекты формата пошли пилить на нашем классном внутреннем творении я отклонял на самом первом этапе. Это может быть интересно, но редко и не всем.


Везде предлагали белое оформление и всё по ТК.


Что спрашивали


Я шёл с мыслью, что трава может быть действительно зеленее и на рынке прорыв, а я чего-то не знаю, но оказалось всё тривиально:


  • Java 8/11.
  • Spring.
  • Rabbit/Kafka.
  • Camunda.

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


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


Были задачи на алгоритмы, но редко.


По проектам могу сказать, что чаще всего это:


  • T&M.
  • Пресейлы.
  • Продуктовая разработка.
  • Архитектура.

Команды в проектах были от 5 до 30 человек с эджайлом в придачу.


  • Пять человек одна компания.
  • Пятьсемь три компании.
  • Продуктовые команды больше десяти человек десять компаний.
  • По-разному (от 5 до 30) остальные.

Проектный подход в примерно одинаковых долях:


  • Agile в разных вариациях.
  • Waterfall.
  • Всё подряд.

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


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


Результаты


Основными критериями для принятия решения я обозначил:


  • Задачи.
  • Деньги.
  • Стек.
  • Компания (бренд/польза для меня).

Дополнительно при прочих равных:


  • Скорость процесса.
  • Техника.
  • Соцпакет.

image

Выписывал результаты


Результат такой: всё примерно одинаково, меняются только деньги и название позиции. Позиции тут всегда всё персонально, кому-то лучше без управления, кому-то дайте больше кода.


Теперь деньги:


  • Редко, но было, меня пытались ужать по деньгам ещё на этапе HR (непонятно зачем) или давали ровно столько, сколько я попросил изначально.
  • В остальных случаях это +5-25 % к стартовой сумме. Иногда говорили про премию, однозначного ответа хорошо это или плохо нет, но могу отметить, что в случае хорошо работаем работу и наличии квартальных премий вполне можно хорошо заработать, больше чем в предложениях голый оклад, да и психологически приятно получать такую мотивацию время от времени.
  • Иногда говорили сразу про премий не будет, иногда была квартальная за выработку или по другому показателю, иногда годовая от личной эффективности и прибыли компании, иногда небольшие нерегулярные поощрения 1015 тысяч.
  • Ещё был интересный кейс если в проекте остались деньги. Тут я либо должен был поверить, что менеджмент у них просто звёзды, то ли с ходу смириться, что премий не будет.

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


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


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

Подробнее..

Как этот год работала наша внутренняя служба гражданской обороны от первых слухов до развития кризиса

25.03.2021 10:19:47 | Автор: admin
image

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

У нас было 40 тысяч масок, 5 тысяч респираторов, 10 тысяч перчаток и 350 литров антисептиков, но опасение вызывала информированность. Не то чтобы это был необходимый запас для офиса, но раз уж вы начали готовиться к ковиду, то становится трудно остановиться. Началось всё ещё весной 2020, когда половина офисных сотрудников в эпидемию не верила, а другая половина бегала в панике и не знала, как защищаться. У нас работает больше 2500 человек, поэтому было важно организовать процессы, связанные с этим всем.

В первую очередь мы взялись за сбор и оценку информации и сделали отдельную поддержку чисто по COVID-19.

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

Начало кризиса, в эпидемию верят не все


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

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

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

Формировали списки СИЗов, надёжных подрядчиков, делились со своими партнёрами. Рассказывали коллегам про наши меры, типизации. Когда начали появляться тест-лаборатории, делились их адресами, тест-системами.

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

image

image

image

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

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

Руководители начали замечать признаки паники у некоторых из бойцов. Тогда в СМИ было много разной и противоречивой информации. Люди не знали, чему верить. После того как у нас в один из дней заболело сразу трое (первые известные случаи на компанию), мы тут же добавили к разведке линию поддержки. Тут же пошёл шквал вопросов про то, как работает с COVID-19 корпоративный ДМС (работает), есть ли что-то дополнительное и так далее. ДМС-поддержка вошла в эту линию. В неё поступил звонок:
Слушай, Люб, у меня что-то в груди подавливает, сдавливает.
Возможно, в обычных обстоятельствах, мы бы так не встревожились. Но тогда удалось выбить КТ в тот же день. Подтвердилось. Хочется верить, что этим действием мы спасли несколько десятков человек от возможного серьёзного осложнения и даже гибели.

Люди возвращались из-за границы, появлялись первые указы и распоряжения по подготовке и соблюдению мер по нераспространению коронавирусной инфекции. Разведка обрабатывала сотни источников: от врачей до СМИ, от ДМС-брокера до профессоров университетов. Наши люди рассказывали, как их лечат, что говорят их врачи, что нужно. Когда был популярен гидроксихлорохин, никто не мог ответить на вопрос: Насколько он полезен или вреден, помогает или нет? Но все его искали, скупали мы нашли и реквизировали партию для компании. Позже выяснилось про цинк, витамин D, витамин С, их чудодейственные свойства, люди просто не могли купить термометр мы искали, где всё это есть, и помогали доставать силами АХО, что-то набрали в запасы. Я в компании 15 лет, есть люди, которые 1012 лет, большая часть кадровиков поддержки была три-четыре года. То есть мы принимали решения, чётко понимая, что будем помогать не просто безымянным людям, а друзьям и делали всё возможное. И непонятно, насколько плохо человеку может стать возможно, один день будет решать или какой-то купленный препарат.

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

Переделка офиса


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

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

image
Это был тот период, когда температуру уже мерили, но то, что у большинства людей температура тела 32 градуса, настораживало мало кого. Нас настораживало, пришлось переходить от простеньких пирометров к более серьёзной технике. Кроме входных групп нужны были ещё контрольные точки внутри офиса, потому что люди с улицы (особенно в дождь) часто более холодные, чем в обычном офисном помещении.

Установили бесконтактные открыватели дверей:

image

Обеззараживатели воздуха:

image

image

Сделали индивидуальные шкафчики в гардеробе, чтобы люди не беспокоились за оставленные вещи:

image

Положили маски на входе:

image

Их ещё надо утилизировать правильно, появились новые типы мусорников:

image

Сделали перегородку на стойках ресепшен:

image

Положили коврики с антисептиком:

image

Привычные уже диспенсеры:

image

Понятное дело, столовая:

image

Вся еда стала в упаковке по порции:

image

Будни поддержки


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

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

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

С эвакуацией тоже проблемы. Бесплатных скорых не было, просто спрашивали, не сильно ли срочно, можно ли на завтра. Мы звонили в скорые и первое, что мы говорили: У нас умирает человек, он задыхается. Через сколько можете приехать? В итоге вызвали пять коммерческих служб с интервалом в четыре-три-два и один час доезда. Первым приехал, час доезда. Остальных мы поотменяли, кому-то заплатили/переплатили за наши вызовы, в тот момент было неважно. Параллельно вторая команда искала место, куда можно госпитализировать.
Вторая команда это волонтёры поддержки. Это секретари, кадровики, инженеры, техники, курьеры. Инженеры, техники, курьеры проводили обеззараживание офиса, обеспечивали разъездные задачи, а секретари и кадровики вели обзвон. Когда коммерческая скорая забирала больного, варианта ещё не было, мы просто попросили их выехать со двора. Минут через пять только нашли. Человека спасли. Потом ему потребовалась реабилитация, он начал отказываться, мол: Да не надо, у меня же всё хорошо.

Тех, кто ложился в региональные больницы (у нас сотрудники не только в Москве), мы решили контролировать по чек-листу симптомов, чтобы понять, всё ли хорошо делают врачи. Тогда уже был протокол Минздрава, из которого следовало много чего интересного. Пример такой: молодой парень, у него температура 38. Принял парацетамол, на третий день сам себя госпитализировал по ОМС, выполнил все предписания, лёг в больницу. Мы в очередной обход вечерний узнаём вдруг, что у него резко упала сатурация. Узнаём у врача нужно редкое средство, которого в больнице просто нет. Связываемся со своими врачами, они рекомендуют перевезти его в платную клинику, где больше возможностей. С главврачами договорились, чтобы из реанимации его перевели в другую больницу. Там его очень быстро поставили на ноги, сработала комбинация из различных методов лечения. Я боюсь напутать, но, кажется, мы спасли его от цитокинового шторма.

Поддержка работала к тому моменту так:

  1. Мы уже настроили PUSH вместо PULL по запросам самочувствия в командах, плюс люди привыкли, что надо звонить по любому поводу, даже если он не очень важный. Звонили не все, но стало всё равно лучше.
  2. Очень чётко мы донесли, что поддержка это не блокирующее звено, оно должно быть асинхронным: сначала скорая, потом мы.
  3. Дальше люди писали и звонили: Ой, мне кажется, что-то не так, вот скажите, что делать? Мы сразу же высылали памятку, где подробно расписано, что делать, и задавали уточняющие вопросы и шаблон дневника: Расскажи, что у тебя? Понимали, какой список симптомов есть, и в первый же день брали анализ.
  4. Если по симптомам непонятно отправляли в лабораторию. Если симптомы есть вызывали специальную бригаду космонавтов.
  5. В конце отсматривали ежедневную динамику и фиксировали в дневниках динамические изменения.

Отдельно были вопросы по техническим средствам, развитию, симптомам, слежению за нашими больными, ДМС и так далее.

image

Дневники оказались очень важны. Первая задача выявить объективные симптомы. Человеку может казаться про своё здоровье: либо всё хорошо, либо плохо. Но дневник показывал объективную картину, делая срез за несколько дней. Динамическая история показывала, становится хуже или лучше не по ощущениям, а на основе объективных данных.

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

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

Как устроено взаимодействие со страховыми


У нас был наш Согаз, который обеспечивал ДМС. Ещё в самом начале кризиса мы взяли страхового брокера, который дальше во многом помог информацией, кого и как лечить. За год у страховых сменилось несколько подходов к лечению ковида и других заболеваний. В какой-то момент медицина была чуть ли не вся заблокирована, и ДМС нам совсем не помогал. Позже страховая начала помогать с поиском платных мест в той же Пироговке, например, помогали организационно преодолевать бюрократию. Застрахованный человек ложился, затем море бумажек, затем страховая оплачивала ему услуги больницы. Потом страховые разморозились, плановые операции и плановые наблюдения возобновились. КТ стало можно делать через страховую. На этом этапе брокер помогал нам находить экспертов рынка, информацию, аналитику, сверять разные вопросы, уточнять данные. С его помощью мы вышли ещё на одну организацию ВИП-центр Росгосстраха, у них есть ВИП-департамент. Если до этого ЛОРы и пульмонологи помогали нам сверхурочно просто так, то теперь мы заключили все нужные договоры и сделали это оплачиваемым процессом. Выработав алгоритм взаимодействия, мы потом тоже заключали договор напрямую с клиниками и работали с ними. Знали список платных клиник, кто принимает с коронавирусом, кто не принимает, кто специализируется на беременных и так далее. Человек звонил в поддержку, говорил: У меня бабушка или дедушка, мы говорим: Вот тебе список и просто скидывали памятку, которая была. Дальше мы помогали уже нашими ДМС-сервисами как могли.

У моего дедушки ангина, он тут у меня задыхается, уже семь дней температура 39, и ему ставят ангину и выписали антибиотики.
А кислород мерили?
Нет, сатурацию нет.
КТ делали?
Нет, КТ не делали.
Отправляем делать КТ поражение 50 %, ставят признаки коронавирусной инфекции. Парой дней позже начали бы лечить был бы прогноз куда хуже. Очень много похожих ситуаций было, когда пожилой родственник пил утроенные дозы антибиотиков вместо того, чтобы нормально госпитализироваться.

Гости офиса


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

image

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

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

Итог


675 заболевших обратилось в поддержку, на момент отчёта 635 выздоровели. 136 заболевших перенесли пневмонию, из них 28 прошли программу реабилитации.
Подробнее..

Пожарный не из Чикаго как тушить огонь в ИТ-проектах

15.04.2021 16:11:54 | Автор: admin

Привет, Хабр! Меня зовут Александр. 17 лет в КРОК. В основном занимаюсь разработкой и внедрением заказного ПО, хранилищ данных, решений Big Data для бизнеса и госсектора. Начинал консультантом по внедрению и последние 11 лет работаю менеджером крупных комплексных проектов. А еще я немного пожарный, потому что регулярно помогаю коллегам тушить проектный огонь.

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

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

Про коллаборацию заказчика и соисполнителей

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

Как справились с огнем? В этом проекте, который мы развиваем по сей день, очень помогают плотная коллаборация с командой на стороне заказчика и задушенная на корню бюрократия на стороне соисполнителей, обеспечивающих сервисы для функционирования ЕМИАС. Я вспомнил про этот сложный проект, чтобы отметить одну из основных лучших практик в масштабных проектах обязательное наличие квалифицированной команды, обладающей полномочиями оперативного принятия управленческих решений на стороне заказчика. Без этого подобные проекты обречены. Проблемы вроде не работает сетевой порт решались одним звонком коллегам от провайдера, а не отписками заведите обращение, подождите, пока оно пройдет многоступенчатую эскалацию и вообще у нас заказчик не КРОК вовсе обращайтесь через них. Такая слаженная, ориентированная на общий результат целой группы компаний работа, вот лучшая практика и один из важных для меня уроков после этого проекта.

Про коллаборацию заказчика и соисполнителей еще раз

Годы работы в проектах ЕМИАС преподносили нам очень разные вызовы в 2013 у нас была команда внедрения с 700+ консультантами во всех амбулаторно-поликлинических учреждениях Москвы. В 2018 нам надо было найти 100+ консультантов для внедрения лабораторного сервиса ЕМИАС это два месяца собеседований нон-стоп. Но оно того стоило!

Как справились с огнем? Тут, опять же, заказчик помогал в согласовании плана внедрения на стороне объектов внедрения с постепенным наращиванием оборотов и административным ресурсом с оповещением поликлиник, лабораторий. Это еще раз подтверждает тезис необходимости совместной мощной команды не только со стороны исполнителя, но и заказчика. В сложных проектах верно выстроенный процесс взаимодействия и коммуникаций (читай синергия команд обеих сторон процесса) путь к успеху. И вторая мораль этой истории не бояться огня. Глаза боятся (осознав, сколько нужно консультантов и в какой срок, задача казалась нерешаемой в принципе), а руки взяли и сделали! Хоть и собеседования проводили всем миром.

Про ток, или Как снять напряженность клиента

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

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

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

Несколько похожая, но вместе с тем иная ситуация была у меня и в другом проекте, где мы для одного из банков делали Big Data систему для построения профиля клиента и оценки рисков при выдаче кредита. В момент подключения меня в проект была не первая фаза, а я не первым РП на стороне исполнителя. Ситуация была схожа с прошлым кейсом непрозрачный процесс разработки для заказчика усугублялась отсутствием четкого ТЗ, ибо такого рода систем в банке, да и на рынке, в то время по сути еще никто не делал. Были первые ласточки в банке Т и банке А, однако готовых решений (да еще на open source) не было. По сути строили с нуля, склеивая кусочный опыт в комплексное решение, попутно синхронизируясь с заказчиком. И еще требования бизнес-заказчиков ловко и резко менялись по ходу представления.

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

Как справились с огнем? Здесь применили проведение регулярных встреч (еженедельных) так называемый управляющий комитет проекта. На них присутствовали представители всех смежных отделов и РП разработки систем банка, с которыми нужно было интегрироваться. Вместе мы составили общий роадмап и реперные точки релизов, вместе же постоянно контролировали возможные сдвиги выпуска той или иной функциональности у нас и в системах клиента. Так мы успешно реализовали проект, подтвердили свой профессионализм заказчику и допродали развитие системы еще на 1,5 года.

Про не всемогущий agile

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

А от исполнителя нужно только локальное управление внутри задач и команды, приоритеты и контроль, состав спринтов. Работали по T&M, еженедельно отгружая таймшиты. При этом нам полностью доверили экспертизу и проектирование системы и ее архитектуры, но на входе дали лишь основную суть бизнес-задачи. Детальное исследование и постановка была тоже на нас. Главная проблема была в том, что кроме РП со стороны заказчика в его команде первые два месяца по сути никого не было. И осознал он (мы заметно раньше) эту проблему только через два месяца работы. То есть когда мы, во-первых, не дошли до ожидаемого им результата (напомню, управление на стороне заказчика) и, во-вторых, ему показалось, что выставленный счет слишком высок, несмотря на регулярные таймшиты, которые принимались и фиксированные ставки договор-то был по T&M. Пахло кризисом жанра. Ситуацию усугубляло еще и то, что со стороны заказчика, как и в прошлом кейсе, системы-источники для разрабатываемой системы были не готовы с нами интегрироваться, а заказчик отказывался принимать результаты работ без демо работоспособного решения.

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

Про опытных пожарных

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

Мало огня?

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

Этот кейс был особенно сложен еще и тем, что по ходу проекта (это более 1,5 лет) многие задачи делались от потребности заказчика в моменте, без оглядки на ТЗ. К концу проекта оказалось, что сделана гигантская работа, но не по ТЗ. Хотя многое реально потеряло актуальность за время проекта. А подписались-то мы под ТЗ. И особенности конкретного заказчика были таковы, что невыполненные требования ТЗ к принимаемой системе это путь под откос.

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

Противопожарные меры

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

Со стороны исполнителя важные и проблемные места, которые могут привести к пожару:

1. Отсутствие полной команды управления исполнителя. Для КРОК это два менеджера РП и технический менеджер ТМ, а для комплексных проектов с несколькими командами РП и несколько ТМ;

2. Проблемы коммуникаций не пускают к функциональным заказчикам;

3. Проблемы коммуникаций между смежными командами внутри исполнителя (тоже бывает не так уж редко), и, конечно, с командами заказчика;

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

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

Со стороны клиента:

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

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

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

Про самое важное в проекте для исполнителя про команду

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

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

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

Другим классным инструментом, которым в КРОК по мере возможности пользуюсь тимбилдинги. И это вовсе необязательно замороченное мероприятие типа командной сдачи норм ГТО (хотя и такое было, и это было огонь!). Тут можно и просто собрать команду в неформальной обстановке, пообщаться, поиграть в дженгу и киккер и просто снять таким образом напряжение зума, тимса, вебекса и бесконечных созвонов-созвонов-созвонов Это работает! Я проверил!

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

Вместо заключения

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

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

Подробнее..

Аптайм 500 дней перезагрузка падение собираем бэкап по частям

09.06.2021 10:16:43 | Автор: admin

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

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

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

Но после накатывания бэкапа система просто легла.

В этот момент нас позвали отмечать день рождения сервера. Без него не работала балансировка нагрузки на операторов внутри КЦ.

Что это была за система?

Система Avaya Call Management System (CMS). Это кусок колл-центра, который собирает статистику по звонкам, операторам, нагрузке исторические и реал-тайм данные. На этом же сервере каждое утро собираются отчёты о работе. В реальном времени сервер говорит, какие операторы сейчас в каких статусах находятся, какие звонки обрабатываются, сколько звонков висит в очереди. В целом система нужна, чтобы следить за группами операторов, за колл-центром, чтобы правильно распределять нагрузку, потому что можно переносить операторов из ненагруженных линий в нагруженные и так далее. Обычно там просто сидят супервизоры и следят за всем происходящим. Прямых аналогов нет, обычно используются самописные решения или же всё вообще делается вручную. Аваевскую систему выбирают за надёжность и многофункциональность.

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

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

Первый день пятница

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

Приезжаем на место (напомню, что сервер лёг и удалённого доступа нет), подключаемся с монитором и клавиатурой, ещё раз смотрим, как система не стартует.

Я подключился не сразу. Когда подключился увидел, что диск переполнился ошибками из-за проблем бэкапа. Некоторые сервисы не стартовали почистили логи, стартовали руками.

У нас условно есть три части системы: железный сервер, который входит в ПАК, поставляемый сразу с софтом в виде чёрного ящика от вендора, CMS и база данных. Бэкапы CMS (конфигураций) и базы делаются в разные места.

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

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

Итак, у нас на руках железный оракловский сервер, с которым что-то не то (но это не посыпавшийся раньше времени диск), на нём Solaris c базjq Informix от IBM + пакет CMS от вендора. Решение продаётся как программно-аппаратный комплекс, то есть всё там как поставил вендор, так никто и не трогал.

Бэкапы БД делались. Итерации были по 180 дней, бэкапирование настроено в планировщике системы. Логи бэкапов никто особо не читал, консистентность не проверяли, назад до этого юбилея сервака накатывать не пытались.

Складировались бэкапы прямо на этот же сервер.

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

Дальнейшее исследование

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

К утру мы всё ещё думали, что справимся быстро (в КЦ уже начались проблемы). Решили не трогать бренную земную оболочку сервера, а сразу снять с него образ и развернуть на виртуалке. Это стандартная процедура и для форензики, и для восстановления чего-то, где может посыпаться дальше диск, и вообще очень удобно в конечном итоге в плане не навреди ещё.

Сначала мы развернули виртуалку на стенде прямо у заказчика и начали препарировать там. Фактически Авая сделала больше, чем должна была, подарив лицензию на виртуальную систему. Ну, точнее, заказчику. Выяснили, что бэкап встаёт с ошибкой устройства, но в остальном норм, правда, система пустая. Довольно быстро стало понятно, что бэкап битый полностью.

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

Откатили виртуалку из снапшота на начальное состояние (до бэкапа системы) и пробуем использовать только бэкап базы. Он восстанавливается удачно, но там нет данных.

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

В лаборатории

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

Сразу стало понятно, что свежий бэкап неконсистентен и вообще похож на записанный прямо из /dev/random. То есть последний месяц (который не бэкапился) пропал просто в силу того, что его никто никуда не резервировал. Следующие полгода пропали из-за битого бэкапа. И только в следующей итерации нашлись таблицы, где были реальные данные. То есть минус семь месяцев от момента аварии, и, как позже выяснилось, целых данных там было не очень много, не больше года, а часто по некоторым показателям и меньше.

Вручную с таблицы перенесли данные в базу данных и скормили всё это нашей виртуалке.

То есть в итоге оставили систему в рабочем режиме со старыми данными, руками настраиваем всё то, что не удалось восстановить из бэкапа системы (пользовательские учётки, коннекторы к другим системам, скрипты).

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

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

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

Выводы

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

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

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

Подробнее..

Промышленные VS офисные сети построение, защита, подвохи, и как надежно отделить первые от вторых

07.06.2021 18:08:54 | Автор: admin
Привет, Хабр! Этим постом я хотел бы начать серию публикаций по промышленным решениям, которые мы сейчас активно тестируем в нашей КРОК-лаборатории. Для начала попробую разобрать основные вопросы проводных промышленных сетей и показать, чем их построение отличается от классических офисных. В качестве подопытного кролика возьму наиболее востребованное на рынке оборудование и софт от Cisco и разберу их особенности.



Как организовать Ethernet-подключения в промышленных зонах?


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

Здесь возникает первая сложность и первое же отличие промышленных сетей от офисных: большая часть коммутаторов устанавливается не в серверные, а в монтажные шкафы, разбросанные по цехам или по территории объекта. Тянуть от каждого монтажного шкафа по две оптические линии по разным путям дорого и сложно, из-за этого становится сложнее организовать привычную и надёжную звездообразную топологию. Приходится использовать кольца. Каждый, кто погружался в построение Ethernet-сетей, помнит, что кольца из коммутаторов зло. В случае со Spanning-Tree это действительно так. Этот протокол в кольцевой топологии может отрабатывать до 30 секунд, что часто неприемлемо для сетей, обслуживающих производственные процессы. Хуже того, скорость сходимости STP падает с увеличением количества хопов от корневого коммутатора до крайних коммутаторов, и как правило, рекомендуется не превышать расстояние в 7 хопов. Это значит, в кольце должно быть не больше 14 коммутаторов.

Что с этим можно сделать? В случае с коммутаторами Cisco, самое простое решение использовать вместо STP Resilient Ethernet Protocol REP и его модификацию REP Fast. Данный протокол специально предназначен для кольцевых топологий и обеспечивает сходимость сети максимум за 50-100мс при любых типах неисправностей и размерах колец до 50 коммутаторов. Причём 50 коммутаторов в кольце это не предел для такого протокола. Время сходимости при росте кольца конечно будет увеличиваться, но тот же Spanning-Tree на кольцах такого размера не сойдётся вообще никогда. REP поддерживается не только в промышленных коммутаторах, но и в офисных, в частности в серии Catalyst 9000, которые могут служить в качестве коммутаторов агрегации.

Протокол очень прост в настройке, вот пример:



Для более сложных случаев доступны протоколы PRP и HSR. Они предполагают полную дупликацию трафика по двум путям в сети. При отказе одного из путей потерь в передаче данных не возникает вообще. Однако и стоимость реализации такой устойчивости выше протокол поддерживается только в старших моделях и только промышленных Ethernet-коммутаторов (IE3400, IE4000, IE4010, IE5000). Впрочем, требования к надёжности и сходимости промышленной сети, как правило жёстко определяются характером производственного процесса, который эта сеть будет обслуживать. Один простой даже в 50 миллисекунд порой может стоить дороже, чем хорошее сетевое оборудование.

Как обеспечить требуемую надёжность работы?


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

монтаж в компактные шкафы на DIN-рейку, питание от постоянного тока;
защита микросхем и портов от электростатических разрядов до 4000 кВ;
отсутствие вентиляторов высокоэффективное охлаждение конвекцией, несмотря на малый размер устройств;
способность выдерживать скачки напряжения электропитания согласно требованиям сертификаций IEC 61000-4-11, IEC 61850 коммутаторы Cisco продолжают работать при пропадании электропитания на промежуток времени до 50 мс, а при отключении отправляют сигнал Dying Gasp;
высокоточные внутренние часы;
возможность быстро заменить неисправный коммутатор, просто переставив SD-карту в новый (при этом новый коммутатор поднимется не только с тем же конфигом, что и старый, но и с тем же образом IOS);
быстрая загрузка (в пределах 80 секунд);
тщательное тестирование на соответствие промышленным сертификациям.


Рисунок 1. Симуляция процесса охлаждения коммутатора конвекцией


Рисунок 2. Тестирование коммутатора на устойчивость к электромагнитным воздействиям


Рисунок 3. Тесты с воздействием водой на коммутатор с уровнем защиты IP67

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



Они монтируются в 19-дюймовый шкаф, могут питаться и от постоянного и от переменного тока, обеспечивают высокую плотность портов, высокую производительность, но при этом промышленную надёжность и поддержку промышленных протоколов, например PTP, PRP, HSR, PROFINET MRP. Как и другие коммутаторы промышленной линейки, Cisco IE5000 умеют принимать сигналы тревоги от устройств автоматики, например, устройств контроля климата или датчика открытия двери в помещение, и отдавать их например для включения сирены и светового оповещения, помимо, конечно же, SNMP и Syslog-сообщений о состоянии коммутатора, отсылаемых в системы мониторинга. Кроме того, эти коммутаторы поддерживают стекирование через 10G-порты. Вот пример построения сети с использованием REP-колец и коммутаторов IE5000 в качестве агрегирующих:



Поддержка промышленных протоколов


В промышленных Ethernet-сетях используются Ethernet-версии различных промышленных протоколов: PROFINET, CCLINK, CIP и т.п. При этом, как правило, от сетевого оборудования требуется поддержка таких протоколов в том или ином виде. К примеру, при использовании PROFINET, требуется управлять с помощью этого протокола не только контроллерами, сенсорами или исполнительными устройствами, но и самими коммутаторами, образующими сеть. Для этого в моделях промышленных коммутаторов Cisco начиная с IE3000 реализована поддержка работы по PROFINET в качестве устройства ввода-вывода. Кроме того, некоторыми моделями коммутаторов Cisco можно управлять с помощью портала Siemens TIA.

Ещё один пример промышленного стандарта, поддержка которого часто требуется Time-Sensitive Networking (TSN). Это набор стандартов Ethernet, позволяющий обеспечить доставку Ethernet-фреймов с предсказуемой и не меняющейся во времени задержкой. Привычный Ethernet, напомню, работает асинхронно и фреймы в нём доходят до адресата настолько быстро, насколько получается. Функционал TSN протокол поддерживается в коммутаторах Cisco IE3400, IE4000, IE4010 и IE5000.

Как защитить промышленную сеть?


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

трафик не должен проходить между офисной и промышленной сетями насквозь;
любой протокол, разрешённый между ДМЗ и промышленным сегментом должен быть в явном виде запрещён между ДМЗ и офисным сегментом;
в промышленный сегмент сети не должно быть доступа из интернета, даже через межсетевой экран;
И конечно никаких Any в полях для IP-адресов, портов и протоколов в политиках межсетевого экрана.

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

Промышленный, офисный и ДМЗ-сегменты отделяются друг от друга межсетевыми экранами. Здесь у Cisco явное преимущество на её продуктах можно построить защищённую сеть от и до.
Межсетевые экраны Cisco умеют распознавать не только промышленные сетевые протоколы:







но и промышленные устройства, подключённые к сети:



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



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

Межсетевые экраны обеспечивают так называемую макросегментацию сети разделение на крупные участки, трафик между которыми либо запрещён, либо фильтруется через правила межсетевого экранирования. Таким образом отделяются друг от друга не только ДМЗ, промышленный и офисный сегменты сети, но и, например, разные цеха и производственные линии в промышленном сегменте. Для последней задачи может пригодиться межсетевой экран Cisco Industrial Security Appliance (ISA) полноценный фаерволл в промышленном исполнении.



Как правильно обеспечить удалённый доступ?


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

Здесь, помимо межсетевых экранов Cisco Firepower, огромную помощь может оказать решение Cisco Identity Services Engine. Межсетевые экраны обеспечивают подключение с помощью AnyConnect VPN или проксирование трафика удалённого рабочего стола, а ISE позволяет максимально чётко идентифицировать и человека, получающего доступ и объект в сети, к которому этот доступ предоставляется, а также определить политики такого доступа в виде своего рода матрицы:



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





Как выполнить требования регуляторов?


Стандарты международных организаций и дизайн-документы Cisco Validated Design только дают рекомендации как лучше. Но кроме рекомендаций есть ещё и требования регулирующих органов, которые необходимо выполнять при построении промышленных сетей. В России к таким относится приказ 239 ФСТЭК Об утверждении требований по обеспечению безопасности значимых объектов критической информационной инфраструктуры Российской Федерации. Он содержит перечень архитектурных решений функционала, которые должны быть реализованы.

Часть требований приказа, такие как наличие межсетевого экрана и обновляемого IPS на периметре промышленного сегмента, сегментация сети, организация ДМЗ закрываются межсетевыми экранами Cisco Firepower, описанными выше. Требования по аутентификации и авторизации Cisco ISE. Далее, целый набор требований, связанных с мониторингом промышленной сети закрывается решением Cisco CyberVision.

Решение Cisco CyberVision может собрать данные с промышленной сети в виде SPAN-трафика или со специальных сенсоров в сетевых устройствах и представить картинку происходящего администратору, а также отправить необходимую информацию в системы управления конфигурациями и SIEM. Администратор сети может получить полный список устройств, подключённых к промышленному сегменту сети (не только Ethernet-коммутаторов, но и устройств промышленной автоматики), проверить их на известные уязвимости и отследить их поведение.


Рисунок 4. Пример отображения известных уязвимостей для промышленных устройств

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

Тру-истории из жизни инженера по AV-системам экран в бассейне, финский гараж и особенности ПНР в пандемию

13.04.2021 10:07:06 | Автор: admin

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

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

История первая: Иркутск, пандемия, больница, пусконаладка

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

Ничего не подозревающий, простуженный в первый же день командировки инженер (Иркутск зимой не самое дружелюбное место) как ответственный человек идет к врачу, чтобы проверить, всё ли с ним в порядке. В результате его без объявления войны отправляют в местную инфекционную больницу до выяснения обстоятельств. Чем параллельно саботируют процесс ПНР.

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

А бежать очень хочется, ведь внутри картина не лучше:

Кое-как на пятый день нам удалось пробиться в больницу и вручить ему компьютер и какие-то личные вещи. И это позволило отыграть своё. Надев визор (позвонив монтажнику), мы поставили в сеть ноутбук, прикрутили web-камеру, чтобы хоть как-то снимать ответы с железок. По сути, мы сделали недвижимого дрона, которого из комнаты в комнату двигал еще один Дрон (монтажник Андрей).

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

Разумеется, заказчик не мог столько ждать и попросил нас сделать все без неё. А это не очень просто, учитывая что 30% оборудования врезные инсталляции в ту самую мебель.

На совместном брифинге было принято решение монтировать и делать ПНР так, как есть, то есть на коленке или на полу. Примерно так и родились царства пакетов и, как я это назвал, консерв. Аккуратненько ножиком открываешь, а на тебя смотрит готовая система. Просто добавь воды мебель.

История вторая: светодиодный экран в бассейне

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

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

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

На фото наш инженер, ещё не знающий, что всё пыльно, вскрывает плёнку экрана по щиколотку в воде. Нарушения ТБ, кстати, тут нет, всё отключено от электропитания, а сапоги вообще проверены в лаборатории:

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

История третья: финский гараж, или немного Хельсинки платформу для коллаборативной работы

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

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

Тут расписал немного о самом решении

Прежде всего, Multitaction это коллаборативный софт. Он состоит из двух продуктов.

Canvas

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

Showcase

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

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

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

Лекции были или непосредственно в цеху сборки, или на кухне. Как раз на ней стоит оптимальная, на мой взгляд, конструкция 4х1 из панелей 55 дюймов:

Что интересного в этих панелях: там не ИК-рамка и не резистивный дисплей. Там 32 видеокамеры за матрицей, которые и считывают все наши прикосновения. И поэтому они понимают не только количество пальцев, но и на какой руке эти пальцы, где стоит человек, они могут разобрать предметы, QR коды и прочее (то есть практически всё, что мы им показываем, если предварительно немного их научить).

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

Жалко, нельзя передать напиток через видео))

Кстати, самое интересное в Хельсинки это их пиво. Да, в каждом приличном баре можно найти свой гозе. И это именно то, что нужно, чтобы после встречи с производителем обсудить всё за бокальчиком пенного.Ну а пока у нас закрытые границы, обсудить можно здесь:)

Подробнее..

Прокторинг на стероидах, или как контролировать онлайн-экзамены

20.04.2021 10:21:38 | Автор: admin

Недавно ProctorEdu и КРОК запустили систему для контроля онлайн-тестирования на экономическом факультете МГУ. Она помогает наблюдать за студентами, которые сдают экзамен.

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

Такой подход к онлайн-обучению, прокторинг, первыми внедрили Coursera и Udemy. Разработчики ProctorEdu задумали собственную систему прокторинга в 2016 году именно для учебных заведений, но вскоре поняли, что она способна решать другие, более серьезные задачи.

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

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

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

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

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

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

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

Как это работает

Во время экзамена ProctorEdu ведет запись с камеры, микрофона и экрана компьютера.

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

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

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

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

E [0, 100] оценка доверия (если E < 0, то E = 0), xk усредненное за сеанс значение метрики k, wk весовой коэффициент метрики k, M {b1,b2,c1,c2,...} метрикиE [0, 100] оценка доверия (если E < 0, то E = 0), xk усредненное за сеанс значение метрики k, wk весовой коэффициент метрики k, M {b1,b2,c1,c2,...} метрики

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

Протокол сеанса в PDF-форматеПротокол сеанса в PDF-формате

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

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

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

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

Ограничения браузера и детекция лиц

Запись камеры и экрана, распознавание лиц, логирование клавиатуры Это звучит не секьюрно, поэтому разработчики ProctorEdu сознательно отказались от идеи устанавливать свое ПО на компьютеры участников экзамена.

ProctorEdu работает через браузер при помощи супервизор SDK JavaScript-библиотеки, в которой реализованы алгоритмы машинного обучения.

SDK не требует установки расширений и плагинов. ProctorEdu интегрируется с сервисом онлайн-тестирования при помощи стандарта IMS LTI или нескольких API-команд. Система запускается на странице тестирования и работает параллельно с ним.

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

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

Распознавание лиц в ProctorEdu реализовано при помощи сверточных нейросетей с использованием OpenCV и Dlib. Они регулярно переобучаются на свежесобранных данных. Для детекции лиц используется отдельная модель.

Разработчики с самого начала планировали запустить эти алгоритмы в браузере. Обычно такие задачи решают при помощи компиляции C++ в WebAssembly (Wasm). Считается, что это хорошая практика.

Чисто теоретически Wasm работает быстрее, чем JavaScript сценарий, но на практике выяснилось, что он медленнее, потребляет больше памяти и процессора, весит больше. Только загрузчик такого кода получается от 10 МБ.

Пришлось разрабатывать на JavaScript в несколько итераций. Первые версии были слабенькими и часто ошибались, но со временем команда ProctorEdu добилась стабильной работы и вывела это решение в продакшн.

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

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

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

Сейчас разработчики планируют перенести в браузер и алгоритм распознавания лиц. Пока что модель великовата (2030 Мбайт с учетом сжатия), это в то время как все SDK весит около 1 мегабайта. Но здесь стоит постараться и найти решение.

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

Серверная часть ProctorEdu

Кстати, об архитектуре системы.

Основной компонент ProctorEdu сервер приложений. Он работает на Node.js и занимается обработкой веб-запросов и веб-сокетных соединений. Сервер приложений связан с базой MongoDB. Там хранятся все данные, не являющиеся бинарными объектами. Для файлов, изображений, записей экзаменов предусмотрено отдельное S3-совместимое объектное хранилище.

Архитектура ProctorEdu включает отдельный сервис под API распознавания лиц и документов, и TURN-сервер для координации WebRTC-подключений между компьютерами участников.

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

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

Обычно ProctorEdu разворачивают на базе одного из российских хостингов, поддерживающих хранение персональных данных, но систему можно запустить и на локальном сервере, как в проекте с МГУ и КРОК.

Требования к железу невысокие: компьютер с восьмиядерным процессором и 8 ГБ оперативной памяти потянет порядка 500 одновременных сессий. Однажды ProctorEdu обслуживала больше 5 тыс. одновременных участников экзамена и понадобилось всего 6 серверов для обработки клиентских запросов.

Можно ли обмануть систему?

Можно, но не так, как это обычно пытаются сделать.

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

Был случай, когда один из участников подготовился особенно серьезно: напечатал чужое фото на листе А4, вырезал глаза, привязал резинку и использовал как маску.

Конечно, это все легко детектируется.

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

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

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

Конечно, и это не панацея. Если постараться, Safe Exam Browser можно обмануть. Еще можно раздобыть скрытые наушники или аппаратный сплиттер для мониторов. Любой алгоритм можно обойти, вопрос лишь в том, сколько усилий для этого потребуется. ProctorEdu делает так, чтобы было проще выучить, чем смухлевать. И наши клиенты подтверждают, что система успешно справляется с этой задачей.

Подробнее..

Как из одной базы данных сделать 10 разных, храня только инкременты обзор решения

18.05.2021 10:20:20 | Автор: admin
История очень простая: есть большая продуктовая база данных. Она нужна пяти-шести командам разработки, тестировщикам и другим командам. Можно сделать штук 10 разных инстансов + БД, но обычно это дорого и долго. Гораздо лучше взять одну мастер-базу и хранить её инкременты для тех команд, которые с ней работают. Для этого есть специальные утилиты. Если лет пять назад они только начинали распространяться в России, то теперь их использование абсолютно нормальная практика.

Давайте посмотрим, как это работает, на примере Actifio:

image
Слева Shapshots, на их основе можно создавать виртуальные БД (VDB).

Итак, берём продуктовую базу и начинаем её клонировать. Нужно это для того, чтобы, в частности, получать тестовую базу за 15 минут, а не за две недели (а бывает и дольше), как обычно в крупных компаниях.

Куда нужна такая БД?


Да почти везде:

image

Обычный процесс выглядит так:

image

На самом деле это процесс курильщика, потому что вот процесс здорового человека, подумавшего когда-то про правильную инфраструктуру:

image

Для этого мы делаем не вот так:

image

То есть каждый инстанс БД взаимодействует в режиме read-write (да-да, именно чтение и запись, это не оЧепятка ;) !!!) через Actifio с основной и единственной на всех БД и её инкрементами. Или, если вы не хотите нагружать её чтением, с единственным зеркалом для разработки/препрода/тестов и иных полезных задач.

image

То есть, допустим, разработчики говорят: нам нужна тестовая БД для быстрой выкатки нового функционала. ОК. Заходим в GUI Actifio, нажимаем раз пять-шесть мышкой и делаем провижн виртуальной БД (VDB), которая является клоном продуктивной БД. Таких клонов (VDB) может быть сколь угодно много. VDB готовится из одной-единственной копии продуктивной БД. И эта копия БД постоянно обновляется (догоняет) информацией из продуктивной БД (по графику, который можно установить произвольным образом).

У нас среднее время от тикета до предоставления базы 30 минут.

Actifio ещё можно использовать для задач Disaster Recovery:

image

Ну и бекапа и восстановления БД соответственно примерно так же.

Как выглядят интерфейсы?


Вот так. Процесс создания виртуальной БД (VDB):

image

Слева выбираем необходимый снэпшот для создания виртуальной БД (VDB) и нажимаем кнопку Mount (внизу справа):

image

Заполняем необходимую информацию о создаваемой VDB и нажимаем кнопку Submit. Процесс создания VDB начался, он займёт минут 1520:

image

Сам процесс создания VDB можно контролировать:

image

Собственно, всё.

Практика


У нас было так: сначала просишь железячников подготовить сервер, потом стораджиста, инженера, подготовить сторадж, сетевика подключиться к вопросам и так далее. Потом надо сделать копии этой базы, перетащить её на целевой сервер, где будут работать разработчики, развернуть эту базу, скоммутировать её со стораджем. Иногда при этом ещё нужно покупать саму хранилку (железо). А это тендер и прочие радости. Теперь мы берём, один раз делаем копию продуктивной базы, потом запускаем процедуру обновления вот этой базы. Клон базы используется как источник для всех остальных команд, он связан с основной базой асинхронной репликации или репликацией по типу бекапа (по ночам, например). Все команды работают с одним этим клоном независимо друг от друга.

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

От клона в разные стороны торчат тестовые инстансы, где команды могут полноценно работать с базой. Каждая запись хранится как инкремент для этого инстанса, то есть каждый работает со своей версией базы и может там менять что хочет, но база типа 15 ТБ занимает с 22 нашими инкрементами в районе 20 ТБ (потому что там ещё включён дедуп, который не используется на проде из-за хайлоада).

Разворачивается на Linux, UNIX, Windows. Нужно проверить версию операционки и версию СУБД, но всё популярное подходит. С легаси может не срастись.

Это всё в эксплуатации уже больше пяти лет.

С какого момента это окупается?


Обычно с баз от 3 ТБ и четырёх команд. Мы начали использовать на базе 6 ТБ и шести команд у себя лет пять назад.

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

Архитектурные паттерны в iOS страх и ненависть в диаграммах. MV(X)

30.03.2021 12:10:29 | Автор: admin

Каждый iOS разработчик в своей жизни уходил с собеседования в расстроенных чувствах и мыслью это что еще за новая аббревиатура?. Архитектурами пугают и джунов, и миддлов, и синьоров (и наверное даже синьорит). Важно не просто знать что стоит за названием, но еще и в каком случае какую использовать. Литературы по этому вопросу преступно мало, редкие обсуждения в интернете ограничиваются собственным опытом и какими-то поделками на гитхабе.

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

Первая часть посвящена MV(X) паттернам: самым известным и распространенным практикам в индустрии.

Это первая статья из цикла, посвящённого архитектурным паттернам в iOS разработке. Расскажу про плюсы и минусы, а также когда и где их лучше применять. В этой статье начну с основных и самых популярных MV(X) практик. Во второй части речь пойдёт о реализациях концепции Чистой Архитектуры (Clean Architecture), а в третьей об FRP практиках и паттернах в iOS разработке.

Я Маша, ведущий инженер-разработчик iOS в КРОК, а также аспирант-препод в МЭИ.

Быть iOS-разработчиком непросто. Сначала Xcode не хочет подключаться к устройству, потом ты возишься неделю с сертификатами, потом полгода изучаешь Swift и пытаешься понять когда использовать `guard`, а когда `if let`. Или когда ты уже написал не один калькулятор и приходишь на собеседование в крутой проект, тебя с порога начинают закидывать какими-то страшными аббревиатурами.

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

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

Что такое MV(X)?

Основные части MV(X) архитектур это, так или иначе, модели, виды и контроллеры.

Модель отвечает за использование предметных (бизнес, domain) данных. Это так же может быть data access layer. Модели бывают двух видов: активные и пассивные. Активные модели умеют уведомлять окружающих об изменениях в себе, а пассивные нет.

Вид (Представление, View) отвечает за слой представления (GUI). В каком виде вам это представить? :) Вид не обязательно должен быть связан с UI отрисовкой: если вы хотите представлять данные в виде сменяющих друг друга диодов на arduino-плате этим все равно будет заниматься Вид. Помимо представления пользователю данных, у Вида есть ещё одна важная задача: принять событие пользователя (нажатие на кнопку, например) и пнуть кого-то, кто знает что с этим делать.

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

Любой нормальный человек, только что закончивший изучать ООП, задаст себе вопрос: а нафига плодить эти сущности? Зачем мне так много классов/структур/файлов/сообщений? Какие такие офигенные бенефиты дает вся эта возня? Вон я писал все в одном файле на Паскале/Питоне/Си/Свифт-плейграуде и работало же!

Хорошая архитектура нужна чтобы:

  1. Код становится читабельнее (как минимум для человека, знакомого с архитектурой, как максимум для любого человека)

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

  3. (проще и быстрее) покрыть код юнит-тестами

  4. Расширять (масштабировать) код без мигрени и убийств

Хотя скорее всего если вы нашли эту статью, то вы уже знаете зачем вам нужна архитектура :)

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

Создание архитектуры программы или как проектировать табуретку (обязательно походите по ссылкам внутри)

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

MVC

CocoaMVC это iOS архитектура, которую предложили Apple, создавая iOS Developer SDK. Но стоит оговориться, что, вообще говоря, видение Apple немного отличается от традиционного понимания MVC как архитектуры.

Традиционная MVC выглядит как-то так:

Сплошная стрелочка по заветам UML тут означает ассоциацию. Переводя на программерский: Контроллер владеет Моделью (например у класса Контроллера есть поле типа Модели). Я дальше вместо совершенно нетолерантного слова владеть буду говорить Контроллер ЗНАЕТ О Модели, ведь знание сила.

Пунктирная стрелочка означает зависимость. То есть когда Контроллер владеет Видом, то Вид оказывается у него в зависимости (то есть у Контроллера есть поле типа Вид). У нас в свифте мы зависимость часто видим на примере `weak` свойств на родительские объекты и/или делегаты.

То есть:

  • Вид: рисует кнопочки

    • зависит от Контроллера

      • сообщает Контроллеру о событиях ввода

    • знает о Модели

      • запрашивает данные у Модели

      • получает изменения в данных от Модели

  • Контроллер: знает где взять текст для кнопочки и какой кнопочке его дать

    • знает о Виде

      • может менять конфигурацию Вида или заменять один Вид другим

    • знает о Модели

      • запрашивает изменения в данных Модели

  • Модель: знает как выглядят данные (типы, структуры), что делать с данными (бизнес-логика), где лежит БД и как в нее ходить (инкапсулирует доступ к данным)

    • зависит от Контроллера

      • меняет данные по запросу Контроллера

    • зависит от Вида

      • сообщает Виду об изменении в данных

Тут важный момент в том, что Вид не имеет состояний, то есть является stateless. Он просто отрисовывается заново, как только в Модели что-то меняется. Хороший пример: веб-страница в рунете нулевых, которая полностью перезагружается, если вы нажали на какую-то кнопку.

А ещё обратите внимание, что у View нет доступа на запись в Модель. Все изменения Модели производятся только через Контроллер, при этом права на чтение Модели у Вида не просто есть он ими активно пользуется (чтобы обновлять себя и показывать актуальные данные на экране).

Вкратце достоинства классической MVC:

  1. К одной Модели можно присоединить несколько Видов так, чтобы не менять код Модели. Например, табличные данные хочется показать и таблицей, и гистограммой, и пай-чартом.

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

  3. Разработка бизнес-логики не зависит от разработки представлений и vice versa. А значит, можно посадить несколько человек одновременно долбить код одной фичи.

  4. Однонаправленный поток данных (Вид -> Контроллер -> Модель -> Вид) делает дебаг проще и приятнее

Все это звучит очень классно, но немного запутанно и архаично. Apple предлагает вот такую реализацию Cocoa MVC:

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

Любой iOS-ник скажет, что эта картинка вообще не вяжется с реальностью и будет по-своему прав. На самом деле в большинстве случаев Cocoa MVC будет выглядеть вот так:

Что кажется хоть и до боли знакомой, но довольно примитивной картиной. Так что неудивительно, что она создает столько проблем.

ViewController и View настолько плотно завязаны друг на друга, что сложно вообще отличить где заканчивается одно и начинается другое. С одной стороны: ну вот же UIView его можно отдельным классом написать, там экстеншены-категории все вот это вот, вы меня за дурака держите?

С другой: UIView не умеет отрабатывать IBAction (тк он не посылает никаких actions это делают UIControl), а .xib-ы легче подключаются к контроллерам (наверняка же сталкивались с историей, что если xib не заканчивается на -Controller то он не подключается из коробки? :)). В итоге чтобы отделить UIView от UIViewController в терминах целого экрана, а не отдельного компонента нужно пройти сквозь огонь, воду и LLVM.

Так как ходить через LLVM никому не нравится, все пихают логику Вида в UIViewController, что приводит к тому, что MVC элегантным жестом превращается в Massive View Controller. Разобраться в этой мешанине делегатов, датасорсов, экшенов и просто вспомогательных функций задача на любителя.

Происходит это из-за того, что у Вида может быть достаточно большое количество различных состояний: представьте себе форму регистрации из серии введите емейл, пароль, подтвердите пароль. Логично, чтобы все поля имели валидацию ввода и цветовую индикацию: хорошо/плохо. Получается, что это три текстфилда, каждый с как минимум двумя состояниями. Записать это состояние в Вид нельзя он stateless, в Контроллер тоже нельзя он не должен управлять состояниями Вида, лишь передавать ему данные. В итоге, состояние Вида приходится хранить в Модели. Так у нас Модель получается перегружена: она хранит в себе и Domain Model (модель предметной области: данные, бизнес логика и тп) и View Model (модель вида: его состояния, хранимые данные, логика переключений состояний и тп).

Пример несколько утрированный, и опытные разработчики скорее всего не увидят проблему в реализации подобной фичи (ну сделай ты кастомный контрол и делов-то!). Но если говорить о формальном следовании архитектуре MVC/CocoaMVC, то видно как всё быстро становится достаточно запутанно.

Ну а протестировать взаимодействие между View и ViewController задача настолько нетривиальная, что в MVC приложениях как правило тестируют только модель и нетворк слой (что во многих случаях бывает так же сложно разделить как и UIView с UIViewController: представьте модель данных и интерфейс доступа к данным (к БД)).

В итоге, чтобы сделать действительно MVC-шный MVC на iOS придется исхитряться ломая либо Cocoa MVC (например давая UIView возможность самостоятельно ходить в модель), либо логику UIKit и делегирования (чтобы сообщения в контроллер приходили действительно от условных UIView, а не от других контролов и контроллеров).

MVP

Прозорливый читатель заметит, что всех проблем c Cocoa MVC можно было бы избежать, если пару UView+UIViewController воспринимать как View, а под слой Controller выделить отдельную сущность, которая не знает о UIKit и занимается только тасканием данных и событий между View и Model, как и было задумано.

То есть:

  • Презентер:

    • зависит от Вида

      • сообщает Виду о необходимости обновить отображение измененных данных

    • знает о Модели

      • запрашивает изменить данные

      • получает сообщения об изменившихся данных

  • Вид:

    • знает о Презентере

      • запрашивает у Презентера реакцию на действия пользователя (пользователь нажал на красную кнопку, куда его послать, сэр?)

  • Модель:

    • зависит от Презентера

      • получает запросы Презентера на изменения данных

      • посылает Презентеру сообщения об изменившихся данных

Выглядит классно и вполне адекватно! Только вот

Нам очень хочется, чтобы Вид ничего не знал о Модели, так? Если собирать эту диаграмму в код напрямую, то получится, что в условном Виде содержится полем объект Контроллера, Контроллер содержит внутри себя Модель, ну и при инициализации Вида у нас по цепочке через Контроллер будет инициализироваться управляющий объект Модели. Так знает Вид о Модели или нет? Как-то некрасиво получается, да и с концепцией не вяжется.

Эта проблема сборки (assembly problem) корнями растет напрямую из Cocoa MVC. Ведь именно Cocoa MVC заставляет нас в первую очередь ориентироваться на UIViewController как на единицу сборки и навигации.

В идеальном мире мы бы сделали как:

```

let newModel = Model() // а возможно она уже где-то существует и мы на нее ссылаемся

let newPresenter = Presenter(model: newModel)

let newView = MyViewController(presenter: newPresenter)

```

Получается красивая инъекция зависимостей через конструктор, и все бы хорошо, если бы было понятно а где собственно она должна происходить. По идее (согласно Cocoa MVC) мы вызываем новые виды (UIViewController) из других видов (других UIViewController). В итоге получается что-то вроде `self.present(newViewController)`. Так значит какой-то другой Вид будет знать про модель нового Вида? Или этим должен заниматься Презентер?

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

Вид: эй, Презентер, юзер хочет перейти на новый экран, что мне делать?

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

В большинстве примеров в интернете и в жизни вы найдете код, где ViewController спокойно себе инитит модель, а потом кладет её в параметры инициализатора Презентера. У такого подхода нет ничего плохого, только надо следить за ссылками и понимать, что это не чистый MVP как на диаграмме, да и заменить модель при случае будет не так просто, как хотелось бы.

Решается проблема сборки как правило тем, что создается ещё один управляющий слой: Роутер (Router), который собирает MVP-кусочки, управляет их жизненным циклом и передает их друг другу при необходимости. По этой же причине так часто встречается связка MVP+Coordinator (на эту архитектуру часто ссылаются как на MVP+C).

MVP+C

Выглядит это дело вот так:

Задача координатора создавать MVP блоки и управлять тем какой UIViewController показывается на экране прямо сейчас (например через `navigationController.pushViewController`).

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

Вид: эй, Презентер! Юзер Иванов хочет посмотреть на красную кнопку.

Презентер: *потея* ох, но у нас её нету, надо искать где-то в другом месте Координатор, нужно показать красную кнопку Иванову!

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

Презентер: *деинитится вместе с Видом и, возможно, Моделью*

Это не единственный способ решить проблему сборки в MVP, но остальные методы не слишком-то элегантны:

Так что подведем итоги:

  • При грамотном подходе все три компоненты (Вид, Презентер и Модель) растут примерно в одинаковых масштабах, что здорово помогает справиться с проблемой Massive View Controller.

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

  • Покрыть тестами логику ответа на действия пользователя теперь тоже намного проще: Презентер хорошо отделён от Вида

  • Правда, как это ни парадоксально, переиспользовать Презентер вряд ли получится: всё же, хоть он и отделен, но заточен на работу с конкретным представлением [2] Впрочем, тут все действительно зависит от вас и ваших навыков в SOLID

MVP оказывается хорошей альтернативой MVC, если выбран осознанно для решения конкретной проблемы. В противных случаях он ощущается как слишком много лишнего кода (намёк на роутер) и какой-то громоздкий костыль к MVC (нафига ещё презентер, если ViewController это всё умеет?)

MVP хорошо подходит небольшим командам, однако в крупном проекте с большим количеством разработчиков может стать настоящим яблоком раздора в GIT: разработчики могут постоянно править одни и те же переиспользуемые классы (например, роутеры или модели), работая над разными фичами, что неизменно приводит к большому количеству конфликтов при мержах, разгребать которые никому не нравится :)

Источники:

[1] iOS Architecture Patterns and Best Practices for Advanced Programming - 2021

[2] MVP vs. MVVM in iOS Development. Let's discuss those architectural | by Ahmed Ragab Issa

[3] iOS Architecture Patterns. Demystifying MVC, MVP, MVVM and VIPER | by Bohdan Orlov | iOS App Development

MVVM

MVVM очень похож на MVP, но совсем другой :) Он был создан в Microsoft для работы с WPF и Silverlight, но благодаря своей элегантной модуляризации приобрел популярность и далеко за пределами WPF приложений.

Давайте начнём с картинки:

Как видно, картинка в точности повторяет MVP, только стрелочки почему-то двунаправленные стали, а Презентер превратился в Модель Вида (ViewModel). Ну и как читать это безобразие?

Начнём с того, что тут View это, как и в MVP, связка UIView+UIViewController. Мы вроде уже достаточно взрослые на данном этапе чтобы понять почему. Дальше, кстати, будет так же.

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

Всё это звучит очень круто и удобно, но потом приходит iOS-ник и такой:

И действительно, штатных (предоставленных Apple) средств организовать биндинг в iOS SDK (вне SwiftUI) нет, но зато есть другие инструменты, с помощью которых можно симулировать такое поведение.

Так как делать биндинги вообще? Есть четыре способа:

  • KVO (Key-Value Programming) очень крутая и мощная штука прямиком из Cocoa, которая позволяет подписаться и наблюдать (observe) за переменной по её имени (keyPath) и получать уведомления об изменении её значения (value). Кажется, то что надо!

  • FRP (Functional Reactive Programming) парадигма программирования (заметьте: не язык и не фреимворк, а целая пАрАдИгМа) для обработки событий и данных как потоков. Ну, например представьте, что у вас есть какой-то поток данных и вы хотите для каждого объекта в этом потоке что-то предпринять. Эдакий forEach, только вы не знаете когда появится новый объект.```let lowercaseNames = cast.map { $0.lowercased() }``` видали? Вот вам и FRP, где поток это статичный массив (cast).Реализация FRP в Swift обычно отдается на откуп RxSwift и ReactiveSwift, но есть ещё и Combine от Apple сейчас можно говорить, что он лучше всех, но это конечно не точно.

  • Delegate делегирование можно использовать чтобы передавать сообщения об изменении данных.

  • Boxing если вы первым делом подумали про `didSet` то это для вас! Похоже на KVO, кстати, но придется каждое свойство оборачивать в кастомный дженерик класс (Box). Подробнее детали реализации можно посмотреть в крутом туторе вот тут.Ну а если вы пришли из Objective-C, то с паттерном коробки у вас и подавно проблем возникнуть не должно! Это тот же самый паттерн, что используется в Obj-C (и не только) для оборачивания скалярных типов в ссылочные (например float в NSNumber), только теперь мы ещё и листенер туда навесить пытаемся. По сути обычная обертка, совсем не страшно.

Пятый, бонусный способ: SwiftUI и его @State и @BindingУдивительное дело, но в SwiftUI Apple решила отказаться от концепции ViewController как такового! Вместо этого роль передатчика данных между View и Model на себя берет FRP фреймворк Combine (а вы думали отвертитесь от его изучения?). Самая простая иллюстрация для тех кто совсем в танке:- в описании View (читайте его как ViewModel) переменная помечается аннотацией @State- в описании Компонента (CounterButton, читайте это уже View) эта же переменная, привязываемая к UI контролу, помечается аннотацией @Binding - вуа-ля! Очень реактивно и роскошно :)

Тут есть конечно свои нюансы (например то, что SwiftUI больше подходит для Redux-like паттернов), но да ладно.

Что же мы видим в итоге?

  • Модель Вида:

    • зависит от Вида

      • биндится с данными в Виде, которые могут обновляться в Модели или в GUI

    • знает о Модели

      • запрашивает изменить данные

      • получает сообщения об изменившихся данных

  • Вид:

    • знает о Модели Вида

      • биндится с данными в Модели Вида, которые могут обновляться в Модели или в GUI

  • Модель:

    • зависит от Модели Вида

      • получает запросы Модели Вида на изменения данных

      • посылает Модели Вида сообщения об изменившихся данных

При этом функции компонент очень строго разделены и немного отличаются от оных в MVC/MVP:

Модель:

  • Содержит описание данных

  • Реализует CRUD [2]

  • Оповещает Модель Вида о произошедших изменениях в данных

  • Содержит бизнес-логику [1]

  • Содержит логику валидации данных [1]

  • Вообще говоря MVVM никак не описывает реализацию Модели, и она может быть реализована любым способом, хоть VIPER модулем [3]

Вид:

  • Определяет структуру, расположение и внешний вид элементов интерфейса (как в MVC и MVP)

  • Содержит логику Вида: анимации, переходы между Видами и манипуляции с дочерними Видами

  • Передаёт действия пользователя дальше (в Модель Вида)

Модель Вида:

  • Хранит состояние Вида

  • Знает о Модели и может менять её состояние (вызывая соответствующие методы Модели) [1]

  • Как правило образует связь один ко многим с несколькими Моделями [3]

  • Преобразует данные, полученные от Модели в формат, удобный для отображения Видом и обратно

  • Ничего не знает о Виде и может с ним коммуницировать только благодаря биндингам

  • Может содержать логику валидации данных [2]

  • Может включать в себя бизнес-правила работы с действиями пользователя [2,3]

Как видим, Модель Вида какой-то монстр, который всё обо всех знает и всеми погоняет. Это и достоинство, и недостаток MVVM:

  • С одной стороны, Модель Вида удобный медиатор, оторванный от мира UI и Data Access, а значит её удобно тестировать и можно переиспользовать на других платформах, если вдруг понадобилось сделать еще и приложение для tvOS, например

  • с другой стороны, Модель Вида занимается и управлением состояниями своего Вида и зависимостей, и различного рода логикой. А значит её код разрастается и мы возвращаемся к проблеме Massive View Controller. Чтобы этого избежать, необходимо крайне осторожно подходить к проектированию Моделей Вида

И, хоть Модель Вида и легко протестировать, то дебажить приложение на MVVM совсем непросто: ведь благодаря биндингам данные меняются мгновенно. И, что бы это не значило со стороны пользователя, для разработчика это означает огроменный call stack подписок и ивентов, в котором чёрт ногу сломит:

Иллюстрация из [4]Иллюстрация из [4]

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

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

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

Источники:

[1] iOS Architecture Patterns and Best Practices for Advanced Programming - 2021

[2] Advanced iOS App Architecture | raywenderlich.com

[3] Modern MVVM iOS App Architecture with Combine and SwiftUI

[4] iOS Architecture Patterns. Demystifying MVC, MVP, MVVM and VIPER | by Bohdan Orlov | iOS App Development

[5] Architectural Patterns by Pethuru Raj, Anupama Raman, Harihara Subramanian

[6] MVP vs. MVVM in iOS Development. Let's discuss those architectural | by Ahmed Ragab Issa


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

На больших проектах со сложной бизнес-логикой требуются более основательные подходы к проектированию кодовой базы приложения. Один из таких подходов концепция Чистой Архитектуры, о которой мы поговорим в следующей статье. Обсудим VIPER, CleanSwift, RIBs и относительно малоизвестную штуковину под названием Elements.

Не переключайтесь! :)

Подробнее..

Архитектурные паттерны в iOS привет от дядюшки Боба, или Clean Architecture

03.06.2021 10:20:31 | Автор: admin

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

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

Введение

Привет, Хабр! Я всё ещё ведущий инженер-разработчик iOS в КРОК и аспирант-препод в МЭИ. В этом посте я рассказывала про архитектурные паттерны MV(X). У всех MV(X) архитектур есть один общий недостаток: они не описывают как должно происходить взаимодействие между экранами, только то как данные циркулируют внутри экрана.

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

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

По сути, MV(X) архитектуры и не являются архитектурами вовсе это презентационные паттерны, которые описывают слой представления и не более того. В этом-то и кроется вся проблема! Мы пытаемся использовать MVC как архитектуру, когда это просто паттерн для описания её кусочка.

Чистая архитектура

Основная часть заблуждений относительно того, является MV(X) архитектурой или нет кроется в том, что в MV(X) всегда отделяют слой Модели, и кажется что этого как-то достаточно. Но на самом деле нет.

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

  1. Логика предметной области (Enterprise business logic) описывает собственно бизнес-процессы. Например объект студент можно преобразовать в магистра и в программера (по отдельности или одновременно) это описание предметной области. Также при преобразовании студента в магистра ему необходимо выдать шапочку то есть это уже целый бизнес-процесс.

  2. Логика приложения (Application logic) описывает процессы и потоки данных внутри приложения. Как правило, они мало связаны с логикой предметной области и больше зависят от UI/UX дизайна и внутренней кухни платформы. Например, чтобы этот человечек получил красивую шапочку, нужно запустить бизнес-процесс его преобразования из студента в магистра, а для этого надо перейти на экран выдавания шапочек и нажать кнопку дать шапку это и есть логика приложения. Иначе она может называться как сценарии использования (Use Cases) и, вообще говоря, описывает то, как модели предметной области применяются в нашем приложении.

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

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

Виды и весь UI-специфичный слой зависит, понятное дело, от презентеров и контроллеров.

Непокрытыми у нас остались только всякие нетворк-слои, data access layers и различные внешние зависимости. Обобщая, мы увидим, что во внутренних слоях, описанных выше, им места нет, а значит, придется их вывести наружу.

Получим примерно вот такое [1]:

Каждый круг изображает части ПО. Внешние круги описывают механизмы взаимодействия, а внутренние правила взаимодействия [1]. Названия в секторах на иллюстрации примерные и не обязаны быть именно такими [4] (может приложение вообще без нетворка работает имеет право!), и приведены просто чтобы вы представили что именно представляет из себя тот или иной слой. По сути их можно поделить следующим образом:

  1. Сущности (предметная область и логика)

  2. Сценарии использования (логика приложения)

  3. Адаптеры интерфейсов (контроллеры, презентеры всё, что помогает внешним фреймворкам общаться с приложением)

  4. Внешние фреймворки (и/или устройства)

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

а) переиспользовать описание предметной модели, просто взяв сорсы и впихнув в другое приложение

Гексагональная архитектура

Похожий принцип выделения адаптеров и логики используется в так называемой гексагональной архитектуре (Hexagonal Architecture, она же Ports&Adapters Pattern) за исключением того, что в гексагональной архитектуре нет разделения на слои.

Вкратце, вот отличная иллюстрация этого подхода [1]:

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

Но почитать о ней подробнее можно здесь:

[1] Hexagonal Architecture for iOS. An architecture pattern that focuses on | by Oleksandr Stepanov

[2] Clean and Hexagonal Architectures for Dummies | by Lus Soares | CodeX | Mar, 2021

Если представить эту же диаграмму как пирамидку, то запомнить что UI это низкоуровневое, а предметная модель верхнеуровневое, становится совсем легко:

Более того, таких слоёв может быть и больше (и меньше): порой имеет смысл какие-то из них разделить и вложить друг в друга или наоборот. Если говорить о чистой архитектуре в целом, то такую задачу разделения слоёв приходится решать каждый раз заново это и есть проектирование архитектуры. В [4] предлагается разделять компоненты на верхнеуровневые политики и низкоуровневые детали:

  • политики это правила по которым что-то происходит с данными (бизнес-логика, правила валидации)

  • детали это компоненты, которые что-то делают с данными согласно политикам (СУБД, UIKit)

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

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

Правило зависимостей

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

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

Это называется правило зависимостей (Dependency Rule) [1], и означает оно следующее: ничто во внутреннем круге не может знать или как-либо ссылаться на что-либо во внешнем круге. К примеру, ни одно понятие (класс, функция, переменная), упомянутое во внешнем круге, не должно упоминаться во внутреннем.

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

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

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

Источники:

[1] Clean Coder Blog | The Clean Architecture

[2] madetech/clean-architecture: A (work-in-progress) guide to the methodology behind Made Tech Flavoured Clean Architecture

[3] Заблуждения Clean Architecture / Блог компании MobileUp / Хабр

[4] Clean Architecture | A CRAFTSMANS GUIDE TO SOFTWARE STRUCTURE AND DESIGN Robert C. Martin

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

VIPER

VIPER страшный сон большинства iOS разработчиков на рынке. На интервью вопросы про VIPER вызывают разные реакции, но самая распространенная бей и беги.

Кажется, VIPER это что-то прикольное, давайте разберёмся, что это все-таки за зверь.

VIPER расшифровывается в схожей манере с MV(X):

  • View показывает что скажет Презентер и передает ввод пользователя Презентеру

  • Interactor содержит описание сценария использования

  • Presenter содержит логику отображения и умеет подготавливать данные для представления пользователю, а также реагировать на ввод пользователя

  • Entity описание предметной модели

  • Routing описывает логику навигации между экранами

VIPER это про SOLID, так что у нас так много компонент для того чтобы обеспечить S из SOLID Single Responsibility Principle (принцип единственной ответственности: это когда каждый элемент отвечает за что-то одно).

Если рисовать, все это будет выглядеть примерно так:

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

  • Вид: наша любимая связка UIView+UIViewController.

    • знает о Презентере

      • посылает ему действия пользователя

      • получает от него запросы на обновление представлений

  • Презентер: содержит связанную с UI бизнес-логику (при этом не зависит от UIKit)

    • знает об Интеракторе

      • посылает ему запросы данных

      • получает от него события об обновлении данных

    • знает о Роутере

      • получает от него запросы на отображение Вида

    • влияет на Вид

      • посылает ему запросы на обновление представлений

  • Роутер: описывает навигацию между экранами (или VIPER модулями, если они не равны экранам)

    • влияет на Презентер

      • посылает ему запросы на отображение Вида

  • Интерактор: описывает взаимодействие с данными: что откуда взять и куда сохранить

    • влияет на Презентер

      • получает от него запросы данных

      • отправляет ему события об обновлении данных

    • знает о Моделях

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

  • Модель (Сущность, Entity): описывает структуру данных

    • больше ничего не умеет

    • это реально просто описание

Как мы видим, принципиально изменились две вещи:

  1. Модель стала тупым описанием данных, без какой-либо логики обработки или, боже упаси, CRUD

  2. Ответственность сильно поделилась между Презентером и Интерактором:

    1. Мама-Презентер отвечает за UI: просит данные у папы-Интерактора, подготавливает их для малыша-View и говорит малышу когда, как и что показывать

    2. Папа-Интерактор отвечает за данные: когда Презентер просит что-то показать, именно Интерактор идёт в базу, делает всякий CRUD, а потом отдает Презентеру готовый ответ (получилось или нет, вот данные или вот ошибка)

Так вот и выглядят VIPER модули. Если уж быть до конца честным, то в жизни они выглядят скорее вот так:

Интерактор может работать с несколькими Моделями, а Data Access Layer выделен в отдельный компонент, например сервис.

Глядя на диаграммы, несложно заметить, что собирать всё это дело так, чтобы соблюсти правило зависимостей непросто. Настолько, что проще всего выделить под сборку еще один, отдельный компонент, который знает все обо всех (похоже на MPV+C, как и весь VIPER похож на MVP) и где можно легко подставить вместо старого, например, интерактора новый. Такие компоненты называются Builder [6] (или Assembly [3]).

Рисовать это довольно страшно, давайте я просто покажу пример кода:

Тем временем в роутере другого модуля по имени Main:

Не идеальный, но показательный пример из https://github.com/theswiftdev/tutorials

Можно вместо этого сделать полноценный ServiceLocator или использовать уже готовый в составе Swinject и других библиотек. Подробнее про DI можно почитать в этой крутой статье.

Если полазить по репозиториям с VIPER кодом (особенно по шаблонизаторам и тем, которые описывают туториалы, например [3, 6, 7, 8]), можно больно напороться на кучу протоколов, классы-интерфейсы и все вот это вот ООП-шно абстрактное.

С одной стороны, все это велосипед, прикрывающий проблему сборки и неспособность VIPER соответствовать парадигме UIKit. С другой, каждый такой протокол и наследование очередной непокрытый участок кода, который придется тестировать отдельно. А значит, хоть VIPER и testable out of the box но тестов придется написать в X раз больше, чем хотелось бы.

Источники:

[1] Architecting iOS Apps with VIPER objc.io

[2] iOS Architecture Patterns and Best Practices for Advanced Programming - 2021

[3] strongself/The-Book-of-VIPER: the one and the only

[4] Getting Started with the VIPER Architecture Pattern

[5] The Good, The Bad and the Ugly of VIPER architecture for iOS apps.

[6] The ultimate VIPER architecture tutorial

[7] https://github.com/BinaryBirds/swift-template

[8] https://github.com/infinum/iOS-VIPER-Xcode-Templates

RIBs

Описанная выше вариация VIPER с билдером на самом деле очень близка к другому архитектурному паттерну, который придумали в Uber и назвали RIBs Architecture.

И если VIPER пытается привнести в Android какие-то iOS-специфичные проблемы (например высокую связность View и ViewController), то RIBs наоборот, привносит Android-специфичные заморочки в iOS :) Впрочем, и то и другое позволяет нам с наименьшими потерями переписывать код с одной платформы под другую, и, если верить Uber, RIBs с этой задачей справляется лучше.

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

RIBs заключается в том, что существуют определенные RIB-блоки, которые взаимодействуют между собой.

Router осуществляет навигацию между RIB-блоками

Interactor содержит бизнес-логику RIB-блока

Builder конструктор, который собирает RIB-блок

Вид и Презентер в этой иерархии опциональны: если в RIB-блоке нет необходимости рисовать UI, то Вид не нужен; если нет необходимости переводить данные из одного формата в другой Презентер не нужен. Формально тут Презентер как правило является протоколом, по которому Интерактор общается с Видом.

Еще есть Компонент это такая хитрая штука, которая управляет зависимостями RIB-блока. У RIB-блока есть определенные зависимости: такие вещи, которые спускаются ему указом сверху от родительского RIB-блока и хочется, чтобы они были корректно сформулированы. RIB Dependency это протокол, описывающий такие зависимости. А RIB Component это реализация такого протокола. (Если вы знакомы с Android и Dagger, то уже знаете о каких компонентах идёт речь ;))

То есть в Builder дочернего RIB-блока благодаря Component получаются от родителя все зависимости, которые этому ребёнку необходимы (и на шторы скинуться не забудьте!)

Выглядит немного запутанно, но на самом деле всё довольно просто. Presenter и View это одна целая штуковина, при необходимости опущенная или разделённая. Связь Builder с Component отображает процесс Dependency Injection на этапе сборки RIB-модуля. Router просто делает своё навигационное дело, к нему вопросов нет.

В итоге мы получаем возможность строить дерево из RIB-блоков не так, как захочет Navigation Controller и левая пятка UIKit, а так, как того требует бизнес-логика. Это удобно, прозрачно и понятно, к тому же сохраняется чистота наследований: дети не знают ничего о своих родителях, а родители знают о своих детях.

Вот дурацкий пример приложения-будильника-с-погодой:

  • Корневой RIB может включить в себя RIB с флоу будильника либо RIB с флоу погоды

  • RIB будильника умеет добавлять новый будильник и редактировать существующий

  • а RIB погоды показывать мою погоду и новости о погоде вообще

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

Основная фича этого конструкта в том, что каждый RIB может управлять состоянием (навигироваться) только внутри своей ветки: к примеру из Alarm RIB нельзя попасть в News RIB. И он не принимает никаких решений, как только мы попали в Add new alarm RIB.

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

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

Источники:

[1] uber/RIBs: Uber's cross-platform mobile architecture framework.

[2] iOS Architecture: Exploring RIBs. Uber mobile architecture in details | by Stan Ostrovskiy | The Startup

[3] Как мы внедряли архитектуру RIBs. Доклад Яндекс.Такси

CleanSwift

CleanSwift это хорошая альтернатива VIPER и ещё один способ переложить концепцию Чистой Архитектуры на iOS разработку.

В отличие от VIPER, в CleanSwift парадигма UIKit с центральным элементом в виде UIViewController остается нетронутой, что позволяет нам сделать чистую архитектуру, не выдумывая велосипеды, а естественно вырастая из MVC.

CleanSwift ориентируется на VIP-модули: это тройка View-Interactor-Presenter, которая общается друг с другом посредством специальных структур данных, привязанных к взаимодействию одной компоненты с другой.

Так, например, ViewController запрашивает данные для отображения у Интерактора с помощью структуры Request, Интерактор передает данные в Презентер через Response, а Презентер преобразует полученные данные в вид, удобный для отображения Контроллером Вида, то есть собирает ViewModel и отправляет в ViewController:

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

Так, благодаря Request и Response, Интерактор ничего не знает о том как устроен изнутри Контроллер Вида. Ему нужны работники в виде массивов со сквозным индексированием, или в виде множества объектов? Интерактору все равно! Он отдаст Презентеру данные в том виде, в котором Презентер сможет их понять (Response), а уже Презентер приведет их в вид, нужный Контроллеру Вида (ViewModel).

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

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

  • Контроллер Вида: делает всякие UIViewController штуки

    • знает об Интеракторе

      • посылает ему действия пользователя

      • запрашивает у него данные (с помощью Request)

    • знает о Роутере

      • запрашивает у него логику навигации, когда необходимо перейти с текущего экрана на другой

    • знает о Презентере:

      • получает от него запросы на отображение данных (via Viewmodel)

  • Интерактор: осуществляет логику приложения, знает как действовать в ответ на действия пользователя

    • знает о Презентере:

      • посылает ему запросы на отображение данных (с помощью Response)

    • знает о Воркере:

      • запрашивает у него данные из Data Storage (Persistence или Network API)

    • влияет на Контроллер Вида:

      • получает от него запросы данных (via Request)

      • получает от него действия пользователя

  • Презентер:

    • влияет на Интерактор:

      • получает от него данные для отображения

    • влияет на Контроллер Вида

      • передает ему данные, полученные от Интерактора (Response) в виде, удобном для отображения (ViewModel)

  • Роутер: осуществляет общение с другими модулями

    • влияет на Контроллер Вида:

      • получает от его запросы на навигацию и/или передачу данных другим модулям (другим ViewController)

  • Воркер: прослойка между Интерактором и Data Access Layer

    • влияет на Интерактор

      • получает от него запросы на получение данных из Data Storage (Persistence или Network API)

Такая структура позволяет нам полностью разделить непосредственно работу с UI (ViewController), адаптацию данных для вывода (Presenter), логику приложения (Interactor), работу с хранилищами данных (Worker), а также навигацию и сообщение между модулями (Router).

В итоге получаем в определённой степени лаконичные и понятные MVC-новичку классы-сателлиты UIViewController, которые он сам же и создает, когда Роутер из другого модуля создаёт его, чтобы отобразить на экране.

Источники:

[1] The Clean Swift Handbook

[2] Общее представление об архитектуре Clean Swift / Хабр

[3] Clean Swift GitHub

И?

Глядя на паттерны чистой архитектуры очень легко обмануться и решить, что вот только эти паттерны ТРУ, а остальные так, самописное что-то на коленочке. Это, разумеется, не так. И надо всегда четко понимать каких именно целей вы хотите достичь, выбирая архитектурный паттерн для своей кодовой базы (возможно что в разных частях приложения вы и вовсе захотите использовать разные паттерны?)

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

С другой стороны, если команда действительно большая, то следить за соблюдением выбранного паттерна становится тяжелее (какой бы вы ни выбрали, если честно). Но с паттернами Чистой Архитектуры это доставляет особенное неудобство, связанное с тем, что при добавлении одного экрана надо проревьюить не один класс, а в среднем около пяти. А при недостаточном контроле выходит так, что каждый разработчик понимает паттерн по-своему и каждый модуль оказывается описан по-разному. И тогда весь смысл теряется :С

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

P.S. В своем предыдущем посте я рассмотрела MV(X) архитектуры - http://personeltest.ru/aways/habr.com/ru/company/croc/blog/549590/

Подробнее..

Как мы построили гибридное облако и сняли с ручника разработку

25.05.2021 10:11:06 | Автор: admin

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

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

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

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

Подготовка к проекту

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

Выбор решения: open source против корпораций

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

  • open source или OpenStack с последующей доработкой;

  • сугубо коммерческое решение от VMware.

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

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

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

Как строился гибрид

На первом этапе инфраструктура не очень большая, но это компенсируется количеством работающих на ней сервисов. Здесь мы развернули все необходимое для облака, в том числе ряд продуктов vRealize: Automation, Operations Manager, Log Insight и NSX-T для сети.

Позже сюда добавился NSX Cloud: он позволяет удобно управлять сетями в публичных облаках, в том числе и в Azure, через NSX. Мы подключили подписку заказчика Azure к vRealize Automation и vRealize Operations Manager последнее нужно, чтобы отслеживать потребление ресурсов.

Общая архитектура гибридного облака

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

  • между виртуальными машинами;

  • на выходе из облака;

  • на входе в сеть заказчика.

На стороне облака развернуты виртуальные аплайнсы для инспекции трафика.

Что касается связанности сегментов облака и локальных машин здесь существует два глобальных варианта. Первый оверлейные сети через NSX. Этим путем мы пойти не смогли, так как между площадкой заказчика и Azure стоит VPN от CheckPoint.

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

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

  • Automation оркестрация и автоматизация, плюс портал самообслуживания;

  • Operations Manager помимо мониторинга сервисов и использования ресурсов, он осуществляет постбиллинг, определяет стоимость потребленных ресурсов в рамках проекта или конкретного сервиса.

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

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

Сервисы

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

Каталог сервисов облака

Надо сказать, кое-что стало для нас серьезным челленджем: во время написания ТЗ актуальной была версия vRealize Automation 7.6. К моменту, когда пришло время приступать к работе, появилась новая версия 8.

Минутка истории: вплоть до седьмой версии vRealize Automation развивался так же, как и любой другой продукт. Одни функции добавлялись, другие переходили в статус deprecated и заменялись более совершенными. Фактически, это решение VMware еще в 2012 году приобрела у компании DynamicOps и развивала его под своим брендом. 8-я версия vRA это не логическое продолжение старой версии, а принципиально новый внутри продукт. Да, он стал функциональнее и гибче, но часть функций, присутствовавших в 7.6, попросту исчезла.

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

Биллинг

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

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

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

Предбиллинг позволяет в момент заказа сервиса рассчитать стоимость ресурсов (это может быть ВМ, MS SQL Server и т.п.) как на локальной площадке, так и в облаке. Изначально vRA не позволял делать расчеты для Azure. Конечно, можно было бы докупить SaaS-продукт CloudHealth, который позволяет считать постбиллинг для Azure. Однако он все равно не обеспечивает функционал предбиллинга, да и по бюджету уже не проходил. Пришлось дописывать.

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

Мы сделали так, чтобы можно было рассчитывать не только базовые вещи а-ля IaaS, но и произвольные.

Биллинг работает по двум классическим схемам: Pay-as-You-Go и prepaid.

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

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

Следующие на очереди стандартные для облаков сервисы.

IaaS

Здесь речь идет о развертывании ВМ с определенными ОС и набором базовых настроек. В наборе заказчика присутствуют и различные версии Windows Server, и Linux (CentOS и RedHat).

Используемые версии Windows Server 2019, 2016 и 2012 R2. Часть систем заказчика до сих пор работают в 2012 R2. Это вызвало некоторые накладки: в Azure готовых образов этой ОС нет, т.к. Microsoft больше ее не поддерживает. Пришлось загружать свой образ. Так как речь идет о гибридной модели, сервисы предоставляются зеркально: можно создавать их как внутри локальной площадки, так и в Azure. При заказе пользователь сам определяет площадку размещения.

Дополнительно была реализована автоматическая регистрация в DNS. Соответственно, сразу после создания виртуальная машина становится доступна по DNS-имени.

Что касается развертывания машин здесь возможны два подхода:

  • пользователь сам определяет параметры ВМ CPU, RAM, дисковое пространство;

  • предварительно заданные конфигурации, между которыми может выбирать пользователь.

После обсуждения с заказчиком мы пришли к выводу, что использование заготовленных конфигураций удобнее. Во-первых, можно четче спланировать инфраструктуру. Мы четко знаем, что можно создать 10 машин типа А или, например 5 машин типа Б. Если давать пользователю полную свободу выбора, никакой стандартизации не выйдет. В конфигурации Ингосстраха изменить можно только объем дискового пространства: есть нижняя граница, есть верхняя, есть размер по умолчанию. Единственный нюанс в Azure минимальный объем диска составляет 127 Гб. Соответственно, и на vSphere нам пришлось в целях унификации сделать такой же нижний порог.

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

Форма заказа сервиса IaaS

У заказчика в облаке есть три контура безопасности, каждый со своим уровнем защиты: test, dev и prod. Соответственно, тот или иной сервис размещается в своем контуре по выбору заказчика, независимо от того, локальная ли это площадка или Azure.

PaaS

Переходим к PaaS, здесь тоже немало интересных моментов. В основе PaaS лежит IaaS, используются заранее подготовленные ОС. Все Windows-сервисы (SQL, Active Directory, IIS) могут быть развернуты в любой версии этой ОС, которая требуется пользователю. Кроме, разве что, Exchange.

Основная заточка сделана под версию 2012: более свежие версии включают новый функционал, но из соображений обратной совместимости ничего из legacy не удаляется. А если бы мы ориентировались на 2019, не исключено, что пришлось бы писать разные скрипты под разные типы ОС.

Веб-сервер как услуга

Заказчик использует IIS от Microsoft. Он представлен в нескольких вариантах, в том числе есть версия с балансировкой, которая автоматически настраивается на NSX.

Чтобы сильно не углубляться, выделим следующие конфигурации, доступные пользователям:

  • одноузловая конфигурация сервис с IIS.

  • ферма множество веб-серверов IIS.

Пользователь может создать сразу множество серверов IIS и обеспечить балансировку подключений на базе NSX. Можно использовать стандартные порты, можно переопределить их вручную. Всё взаимодействие происходит в веб-интерфейсе.

Active Directory

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

Сервис можно развернуть в двух вариантах:

  • standalone одноузловая конфигурация, когда контроллер домена и DNS совмещены;

  • отказоустойчивая конфигурация два контроллера домена, между которыми в рамках развертывания настроена репликация (и самого домена, и DNS-зон).

СУБД как сервис

  • MS SQL Server можно развернуть по двум типам: standalone и кластерная конфигурация always on, от 2 до 4 узлов. Присутствует возможность выбора версий. Под разные версии СУБД написаны разные скрипты установки.

Exchange как сервис

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

Казалось бы, зачем нужна вторая почтовая система в рамках облака? У заказчика была конкретная цель тестировать актуальную конфигурацию на предмет установки обновлений, масштабирования и прочих изменений. Мы сделали фактически полную (с точки зрения конфигурации) копию боевой почтовой системы. Важный момент продуктив работал на базе сразу 2-х ЦОДов. Мы сымитировали и это.

Часть дизайна сервиса Exchange

Автоматизация предоставления сервисов

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

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

Всего для этой цели используется 4 связанных сервиса:

  • создание проектной области;

  • изменение можно добавлять облачные ресурсы к локальным или увеличивать их пул;

  • удаление если проект больше не нужен, его можно удалить в целях экономии средств;

  • архивация временная деактивация проекта и перенос его на самые бюджетные ресурсы.

Всем, кто задумывается о собственном облаке

В заключение хотелось бы поделиться некоторыми мыслями по итогам проекта:

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

  • Коммерческий продукт (в нашем случае VMware) это отличная возможность для коммерческих заказчиков быстро увидеть первые результаты от внедрения облака без взращивания собственной экспертизы в течение многих лет.

  • Облако позволяет существенно оптимизировать ИТ-процессы в компании за счет их понимания, переосмысления, описания и только потом уже автоматизации.

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

  • Автоматизация, инструменты самообслуживания, возможности интеграции через API позволяют существенно оптимизировать процессы предоставления ресурсов ИТ-инфраструктуры и, как следствие, сократить time-to-market ИТ-продуктов компании как для внутреннего, так и для внешнего потребления.

На этом все! Если у вас есть какие-то вопросы, буду рад пообщаться в комментариях.

Подробнее..

Категории

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

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru