Игра в наблюдение - одна из самых любимых! Многие сотни охранников ежедневно, 24/7, смотрят в камеры и выявляют инциденты. С развитием нейросетей данный процесс сильно упростился, однако остался на том же уровне. Однако давайте заглянем на тёмную сторону наблюдения (и не только), рассмотрев важный вопрос актуальности данных.
Пример
Скажем, у вас есть какая-то СКАДА система, занимающаяся контролем каких-либо данных. Например, наблюдение за дорожным движением. А это значит, что у вас сразу появляется большое количество различного оборудования: сервера, которые могут греться и зависать, промышленные компьютеры, способные отключаться, терять соединение с оборудованием, которое наблюдают, перегреваться или замерзать, светофоры, метеостанции, шлагбаумы, переключающиеся знаки и многое другое, о чём обычный пешеход или водитель даже не задумывается - есть и есть.
И ведь всё это надо как-то отслеживать, управлять и, если что, знать, что что-то пошло не так.
И ладно бы, если бы всем оборудованием управлял диспетчер из диспетчерской, а то ведь может встать на перекрёстке полицейский, подключиться к системе светофоров и открыть "зелёную волну" для кортежа губернатора, чем нарушить изначальный сценарий работы системы (и похерить актуальность данных).
А ведь на этом сценарии использования отнюдь не исчерпываются. Но ничего, сейчас разберём структуру задачи, там всё несложно, хоть в реализации придётся попотеть.
Описание проблемы
Любое оборудование может и будет иметь состояния (даже если это состояние - "не работает"). Однако, появляется несколько посредников между оператором данных и оборудованием: промышленный компьютер -> сервера -> рабочий терминал.
Мы не можем на 100% гарантировать, что где-то по пути не произойдут искажения. Однако мы можем на уровне серверного программного обеспечения проконтролировать актуальность данных (и пометить их как неактуальные в случае ошибки), а на уровне клиента - обязаны это отобразить.
Однако данных много, а возможностей для потери части данных при передаче их клиенту - предостаточно. При этом любой потерянный пакет данных - может привести к трагедии. Именно поэтому требуется подход, контроллирующий высокую степень актуальности данных, предоставляемых клиенту. Его и рассмотрим.
Состояние оборудования
С него всё начинается. У каждого оборудования - есть состояние. И метаданные. Состояние - набор байт, метаданные - какое-то описание оборудования (например, координаты и высота установки).
Состояние оборудования может быть довольно сложным: это для светофора, кажется, красный, жёлтый или зелёный. Но по факту, данных сильно больше: отвечает ли светофор, не находится ли на ручном управлении, а может быть он переведён в режим ожидания (постоянно мигающий жёлтый) или находится на переходной фазе (зелёный мигает и жёлтый должен включиться).
Короче говоря, не стоит думать, что состояние оборудования - число или строка. Это всегда куча данных, о которых изначально можно не подозревать. К счастью, довольно ограниченный объём.
Метаданные - информация постоянная (потому что в противном случае это было бы состояние). И если состояние оборудования надо постоянно актуализировать, то метаданные загружаются один раз при подключении. На них более не будем останавливаться.
Оборудование - источник данных
Разрабатывая программное обеспечение, мы не можем рассматривать оборудование как оборудование. Пусть этим занимаются инженеры обслуживания. Для нас - это просто источник данных. Однако, источник данных должен периодически обновлять информацию о себе.
Делается это, обычно, двумя способами: система опрашивает оборудования с определённым интервалом (скажем, раз в секунду), уточняет его состояние и актуализирует. Второй способ - это когда оборудование вызывает некоторую функцию, передавая параметры состояния источнику (данный способ предпочтительнее, тем более, что используется он, обычно, через посредничество промышленного компьютера: тот опрашивает оборудование постоянно и, как что-то меняется, вызывает функцию обновления).
К слову, состояние оборудования и состояние источника данных могут отличаться по составу, но не по смысловому содержанию. Проще говоря, источник данных "разворачивает" упакованные данные оборудования и может добавлять к ним что-то своё (например, переводить температуру из 8-битного числа в градусы Цельсия).
Не оборудование, а группа оборудования
Разумеется, в рамках системы, нас мало интересует, например, один светофор или шлагбаум; всё имеет смысл только вместе.
Также, когда оборудования станет довольно много, нам потребуются разные диспетчера для разных задач: один контролирует, например, метеоусловия на дороге, второй - скоростной режим, третий - уборочную технику. Для разных задач требуется разный набор полномочий и содержания экрана: не нужно знать диспетчеру-уборщику про скоростной режим, но нужно знать про метеоусловия. То же самое и для контроля скорости.
Таким образом получаются группы оборудования, доступные для разных пользователей (диспетчеров) с разными уровнями доступа (один может управлять оборудованием, другой - не может); также список отображаемого оборудования различается, чтобы не замусоривать экран.
Это очень важный момент: фактически, мы обновляем состояние не отдельного оборудования, а группы оборудования. Зачем нам это - сейчас проясню.
Актуализация информации на экране
Пользователь должен видеть на экране всегда актуальную информацию. Если на светофоре горит зелёный, а на схеме отображается красный - это может привести к трагедии, т.к. будут приняты неверные решения.
Но тут становится ребром вопрос: а как этого достичь. Он выглядит простым, хотя всё не так тривиально. Пока не исследуешь вопрос:
- Состояние источника данных (считай оборудования) - должно постоянно обновляться и иметь передельное время задержки обновления; если время превышает установленный предел (например, 3 секунды), оборудование помечается как нерабочее;
- Источники данных группируются. Каждая группа - один или несколько источников данных (оборудования). И каждой группе соответствует некоторый счётчик обновлений. Каждое новое обновление любого оборудования группы - повышает счётчик на 1, а также формирует "текстовую дельту" - маленький файл, содержащий изменения данных (подобно тому, как Git хранит свои изменения): и когда клиент синхронизируется с сервером (а он это делает с определённым интервалом, либо постоянно поддерживает открытое соединение с постоянной проверкой), то присылает своё показание счётчика: если величина счётчика клиента меньше показания счётчика группы на сервере - ему высылаются последние "дельты" изменений. В порядке добавлений. Если счётчик клиента больше - значит счётчик группы был сброшен - шлются все данные. Также все данные шлются если клиент давно не обновлялся, либо если хэш его текущих данных отличается от хэша данных той же версии группы.
- Одно оборудование (источник данных) может находиться сразу в нескольких группах.
Контроль доступа
Данная система работает в рамках парадигмы раздельного доступа к данным. То есть это часть "только для чтения". Контроль доступа к управлению оборудованием - это отдельный компонент, который реализуется параллельно, но не вместе. Система групп позволяет создать довольно гибкий подход, группируя оборудование (источники данных) по целям, задачам и вопросам безопасности.
Кроме того, одно оборудование может быть переведено сразу в несколько источников данных. Например, веб-камера может передавать картинку всем, кто входит в группу А, а вот для группы Б - добавлять ещё и слой с ИИ-анализом. Однако усложнение системы безопасности, введение большого количества правил или групп - неизбежно приведёт к снижению эффективности системы: данные просто не будут успевать обновляться, либо появятся существенные задержки.
Источник и приёмник
Последним аспектом данный системы является правило получения клиентом данных. Как уже было сказано выше, для разных источников данных может быть разный уровень актуальности состояний: какие-то меняются очень быстро, а какие-то крайне редко.
По этой причине, необходимо ориентироваться на самый быстроизменяемый источник данных. Что создаёт ряд проблем, если клиент не подключён постоянно.
Но существует ещё два подхода. Первый, наиболее известный, это сокеты: клиент подключается и постоянно находится на связи, обмениваясь с сервером данными.
Второй, односторонний, event-source, когда есть одностороннее соединение, в которое сервер по необходимости шлёт данные. Что-то поменялось - данные отправились. Очень удобно, но появляется проблема с синхронизацией (нужен ещё один канал с указанием значения счётчика группы на клиенте).
Поэтому сокеты тут выглядят наиболее эффективно, позволяя очень держать данные в актуальном состоянии с меньшими временными задержками.