Scada Server. Текст (предложение)

Стартовая страница › Форумы › Новые идеи › Scada Server. Текст (предложение)

Просмотр 11 сообщений - с 31 по 41 (из 41 всего)
  • Автор
    Записи
  • #45250
    manjey73
    Участник

    А теперь реалистичный случай: 30 000 каналов, из них 100 текстовых, остальные аналоговые.

    более реалистичный случай — ты просто не сохраняешь в БД эти 100 текстовых каналов в рамках scada. Их нет в записях БД, исключены.

    и пишешь только в свою БД ПО ИЗМЕНЕНИЮ средствами ArcBasicText.dll как хочешь.

    Даже если эти 100 каналов фактически будут массивами

    #45251
    JurasskPark
    Участник

    Так у тебя получится [Timestamp: 8][Quality: 2][Val: 8][ValId: 4] = 22 байта — разве нет?

    Нет. Val и ValueId — это взаимоисключающие поля. В записи присутствует либо одно, либо другое, в зависимости от типа канала.

    Канал числовой (Type = Double):
    [Timestamp: 8][Quality: 2][Val: 8] = 18 байт
    ↑ только Val

    Канал текстовый (Type = TextRef):
    [Timestamp: 8][Quality: 2][ValueId: 4] = 14 байт
    ↑ только ValueId

    Канал текстовый plain (Type = TextPlain):
    [Timestamp: 8][Quality: 2][len: 2][utf8: N] = 12 + N байт
    ↑ строка целиком

    22 байта не получается ни в одном случае. Числовой канал пишет 18 байт — ровно столько же, сколько и сейчас, без изменений.

    Как сервер узнает, что ты добавил id для текста или не добавил?

    Из дескриптора канала. Тип канала — это не свойство сэмпла, а свойство канала. Он хранится в конфигурации (в _meta.dat папки архива, рядом с дескрипторами каналов), и сервер уже сейчас его читает, чтобы понять, как интерпретировать данные.

    Смотри, как это работает при чтении архива:

    
    1. Сервер открывает папку Min/2026-10-03/
    2. Читает _meta.dat → получает список каналов и их типы:
         Cnl 50   Type = Double      → запись 18 байт
         Cnl 51   Type = Double      → запись 18 байт
         Cnl 52   Type = TextRef     → запись 14 байт
         Cnl 53   Type = TextPlain   → запись 12 + N байт
         ...
    3. Открывает data.dat, читает блоки данных,
       зная для каждого канала его размер записи.
    4. Для Type = TextRef дополнительно читает dict.dat
       и подставляет текст по ValueId.
    

    Никакого флага «в этом сэмпле есть текст, а в этом нет» не нужно. Тип известен заранее — на уровне канала, один раз, а не на каждом сэмпле.

    Кто определяет, что из себя представляет канал — числовой он или текстовый?

    Инженер при конфигурировании системы. Ровно так же, как сейчас определяется, что канал 50 — это Double, а канал 51 — это Integer. В RapidScada 6 тип канала уже существует в конфигурации:
    — Double
    — Integer
    — Boolean
    — String (с указанием длины)
    Я предлагаю добавить к этому списку ещё два:
    TextRef — текст через словарь (для типичных SCADA-строк: RUN, STOP, ALARM, названия рецептов)
    TextPlain — текст целиком (для строк с высокой кардинальностью или произвольных)
    Или, ещё проще: оставить существующий String, но дать ему два режима хранения — через словарь и plain. Выбор режима — либо вручную инженером, либо автоматически по кардинальности (адаптивно, как я писал ранее).

    Или ты говоришь о том, чтобы перелопатить весь код Сервера?

    Компонент — Что меняется
    Формат .dat — Новый тип канала в дескрипторе + новый файл dict.dat в папке архива
    Чтение архива (ScadaServerEngine) — Ветвление по типу канала: Double → читаем 8 байт, TextRef → читаем 4 байта и идём в словарь
    Запись архива — Аналогично: пишем либо Val, либо ValueId в зависимости от типа
    DTO CnlDataPoint — Опциональное поле ValueId для передачи текста клиенту (не на диск, а в памяти)
    API сервера — Метод чтения текстового значения по ValueId (или возврат строки сразу из DTO)

    Драйверы, Коммуникатор, ScadaComm, модули сбора данных — не трогаются. Они как присылали строки, так и будут присылать. Меняется только слой хранения и API чтения.

    Аналог: если в PostgreSQL добавить новый тип колонки, это не значит, что весь PostgreSQL переписывается. Меняется парсер, планировщик и слой хранения — но не драйверы и не клиентские библиотеки.

    Числовые каналы не платят ничего. Текстовые — платят меньше, чем сейчас (14 байт против 18 при plain-хранении, плюс колоссальная экономия за счёт того, что сам текст пишется один раз, а не на каждый сэмпл).

    Так что «перелопатить весь код» — нет. Перелопатить слой хранения и API чтения — да.

    #45252
    manjey73
    Участник

    1. Тип строка возможен в устройствах, и читает это Коммуникатор и передаёт Серверу он же.
    2. Это уже другая БД для строк.

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

    И что ещё переписать придется? Для отображения в том числе?

    #45253
    manjey73
    Участник

    Коммуникатор не присылает Серверу полную строку к сожалению 🙁
    Если бы присылал, уже давно бы что-нибудь придумал 🙂

    #45254
    manjey73
    Участник

    з.ы. не экономим на 4-х байтах, а просто их используем, кроме id можно указывать тип Ascii/Unicode (хотя это и так есть) и длину строки — не думаю, что там ‘Войну и Мир’ в юникоде запихнут.

    тут важно, чтобы Коммуникатор и Сервер просто работали с полными строками, а не кромсали их на 8 байт. Без этого, все это фигня на постном масле. Имхо.

    • Ответ изменён 2 дня, 11 часов назад пользователем manjey73.
    #45256
    manjey73
    Участник

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

    #45257
    JurasskPark
    Участник

    Как работает сейчас коммуникатор и как он отдает данные — это отдельная задача, КОТОРАЯ НИКОГО ОТНОШЕНИЯ к моему предложению не имеет отношения. Слона надо есть по кусочкам, а не целиком.

    Даже если Коммуникатор сейчас передаёт строку корректно (через массив каналов, как в v6) — на стороне архива она всё равно:
    — Упаковывается в double (по 8 байт на элемент массива),
    — Пишется на каждый сэмпл,
    — Дублируется между сэмплами, между каналами, между днями.
    Именно эту проблему решает словарь. Независимо от того, как строка дошла до Сервера.

    Словарь живёт между Сервером и Архивом. Он не знает и не хочет знать, как строка дошла — целиком или кусками. Если строка дошла целиком — отлично, словарь её сохранит один раз. Если дошла кусками (массивом каналов) — Сервер склеил её в одну строку до записи в архив, и дальше словарь работает как обычно.

    То есть логика такая:

    
    1. Сервер получил от Коммуникатора сэмпл канала (число или массив для строки).
    2. Если канал текстовый — Сервер собирает полную строку
       (сейчас он это уже умеет делать для отдачи в UI).
    3. Перед записью в архив — Сервер проверяет строку в словаре дня:
       - есть → берёт существующий ValueId
       - нет  → добавляет и получает новый ValueId
    4. В data.dat пишет только ValueId. В dict.dat — текст.
    

    Никакой доработки Коммуникатора на этом шаге не требуется. Он как передавал данные, так и передаёт.

    Если мы хотим, чтобы длинные строки ходили от устройства до Сервера одним куском, то да, нужно смотреть в сторону Коммуникатора и драйверов. Но это отдельная задача, и она не блокирует задачу хранения. Можно сделать сначала словарь (хранение), а потом уже заниматься транспортом (Коммуникатор и драйверы).

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

    не экономим на 4 байтах, а используем их

    Сейчас:
    — Строка упаковывается в double — 8 байт.
    — Если строка длиннее 8 байт — используется массив каналов, и каждые 8 байт пишутся в архив на каждый сэмпл.
    — История изменений длинной строки превращается в поток дубликатов.

    Словарь решает вторую и третью проблему (дубликаты и историю), но не решает первую (транспорт). И это нормально: разные задачи — разные решения.

    Ты прав насчёт Коммуникатора — это реальная проблема. Но она отдельная от хранения. Словарь ValueId можно внедрить до решения проблемы транспорта, и он даст эффект уже на текущих данных.

    Ты пытаешься решить все проблемы сразу: транспорт строк от Modbus-регистров, обрезание в Коммуникаторе, хранение в архиве, отображение в клиентах. И требуешь, чтобы любое предложение закрывало всё это целиком, иначе — «фигня».

    #45258
    manjey73
    Участник

    я вот одного не пойму, куда ты stat потерял ?

    public CnlDataPoint(int cnlNum, DateTime timestamp, double val, int stat, int valueId)
            {
                CnlNum = cnlNum;
                Timestamp = timestamp;
                Val = val;
                Stat = stat;
                ValueId = valueId;
            }

    stat же тоже лежит с каждым каналом отдельно — 4 байта int — у каждого канала свой статус же.

    timestamp 8 байт, значение 8 байт, статус 4 байта. — и 4 байта еще собственно номер канала — как бы 24 байта на канал а не 14.

    то ест переделка только Сервера, чтобы он склеил полученные куски строк и сохранил рядом, не создавая массив каналов для строк. Ну и чтобы Коммуникатор вдруг не упал, так как канала 1,2,3 не будет, а будет только 0-вой у «массива»

    #45259
    manjey73
    Участник

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

    На Н-ное время
    Канал1, данные, статус
    Канал2, данные, статус

    или даже так
    Канал1, время, данные, статус
    Канал2, время, данные, статус

    #45260
    manjey73
    Участник

    в папке Min на каждый час свой файл dat поминутно, то есть в файле по 60-т записей на все каналы.

    • Ответ изменён 2 дня, 10 часов назад пользователем manjey73.
    #45279
    manjey73
    Участник

    Вот хотелось бы от @mikhail услышать, сколько байт занимает каждый канал в БД?

    По варианту 2
    Канал1, время, данные, статус
    Канал2, время, данные, статус

    или meta.dat немного уменьшает размер, не дублирует метку времени, если она одинаковая ?

Просмотр 11 сообщений - с 31 по 41 (из 41 всего)
  • Для ответа в этой теме необходимо авторизоваться.