Тема оформления
Схемы реляционных баз данных
1. Концепция Database-per-Service в архитектуре платформы
Микросервисная платформа «UrFU HeatBalance» строго следует паттерну Database-per-Service (изолированная база данных для каждого микросервиса). В качестве основной системы управления базами данных используется PostgreSQL 16.
Ключевые преимущества архитектурного решения:
- Полная независимость развёртывания и миграций: изменение схемы таблиц
IoTServiceне требует остановки или блокировки базыDatasetService. - Исключение распределённых взаимоблокировок (Deadlocks): аналитические выборки и фоновые очереди не влияют на скорость записи телеметрических пакетов.
- Изоляция сбоев: аварийное переполнение журнала логов телеметрии не препятствует аутентификации пользователей через
AuthService.
2. Комплексная ER-диаграмма реляционных моделей
3. Спецификация схем баз данных и SQL DDL
3.1. База данных heat_balance_datasets
Хранит нормализованные описания агрегатов и сохранённые технологические карты.
Структура таблицы InputDataSets:
| Колонка | Тип данных | Nullable | Ограничения / Индексы | Описание |
|---|---|---|---|---|
Id | UUID | Нет | PRIMARY KEY | Уникальный идентификатор датасета |
OwnerId | VARCHAR(450) | Нет | Индекс IX_InputDataSets_OwnerId_Name | Идентификатор владельца (пользователя) |
Name | VARCHAR(200) | Нет | Индекс IX_InputDataSets_OwnerId_Name | Пользовательское название датасета |
CalculationType | INTEGER | Нет | — | Тип печи: 1..4 |
Comment | VARCHAR(4000) | Нет | DEFAULT '' | Описание технологического режима |
SchemaVersion | INTEGER | Нет | DEFAULT 1 | Версия схемы сериализованного JSON |
InputJson | TEXT | Нет | — | Сериализованные входные физические параметры |
CreatedAt | TIMESTAMPTZ | Нет | — | Метка времени создания записи (UTC) |
UpdatedAt | TIMESTAMPTZ | Нет | — | Метка времени последней модификации (UTC) |
Сценарий генерации DDL (PostgreSQL):
sql
CREATE TABLE IF NOT EXISTS "InputDataSets" (
"Id" uuid NOT NULL,
"OwnerId" character varying(450) NOT NULL,
"Name" character varying(200) NOT NULL,
"CalculationType" integer NOT NULL,
"Comment" character varying(4000) NOT NULL DEFAULT '',
"SchemaVersion" integer NOT NULL DEFAULT 1,
"InputJson" text NOT NULL,
"CreatedAt" timestamp with time zone NOT NULL,
"UpdatedAt" timestamp with time zone NOT NULL,
CONSTRAINT "PK_InputDataSets" PRIMARY KEY ("Id")
);
CREATE INDEX IF NOT EXISTS "IX_InputDataSets_OwnerId_Name"
ON "InputDataSets" ("OwnerId", "Name");3.2. База данных heat_balance_runs
Обеспечивает долгосрочный аудит выполненных теплотехнических вычислений.
Структура таблицы CalculationRuns:
| Колонка | Тип данных | Nullable | Индексы | Описание |
|---|---|---|---|---|
Id | UUID | Нет | PRIMARY KEY | Идентификатор запуска вычисления |
InputDataSetId | UUID | Нет | IX_CalculationRuns_InputDataSetId_ExecutedAt | Логическая ссылка на базовый датасет |
OwnerId | VARCHAR(450) | Нет | IX_CalculationRuns_OwnerId | Идентификатор пользователя |
ExecutedAt | TIMESTAMPTZ | Нет | IX_CalculationRuns_InputDataSetId_ExecutedAt | Точное время выполнения расчёта |
ResultJson | TEXT | Нет | — | Полный результат теплового баланса (JSON) |
Notes | VARCHAR(2000) | Да | — | Заметки оператора к результатам |
Сценарий генерации DDL:
sql
CREATE TABLE IF NOT EXISTS "CalculationRuns" (
"Id" uuid NOT NULL,
"InputDataSetId" uuid NOT NULL,
"OwnerId" character varying(450) NOT NULL,
"ExecutedAt" timestamp with time zone NOT NULL,
"ResultJson" text NOT NULL,
"Notes" character varying(2000) NULL,
CONSTRAINT "PK_CalculationRuns" PRIMARY KEY ("Id")
);
CREATE INDEX IF NOT EXISTS "IX_CalculationRuns_InputDataSetId_ExecutedAt"
ON "CalculationRuns" ("InputDataSetId", "ExecutedAt");
CREATE INDEX IF NOT EXISTS "IX_CalculationRuns_OwnerId"
ON "CalculationRuns" ("OwnerId");3.3. База данных heat_balance_iot
Содержит конфигурации полевого оборудования, токены безопасности, входящую телеметрию и историю групповых вычислений.
Таблица Devices (Реестр датчиков):
sql
CREATE TABLE IF NOT EXISTS "Devices" (
"Id" uuid NOT NULL,
"OwnerId" text NOT NULL,
"Name" text NOT NULL,
"CalculationType" integer NOT NULL,
"DatasetId" uuid NOT NULL,
"SensorType" integer NOT NULL DEFAULT 0,
"AccessToken" text NOT NULL,
"CreatedAt" timestamp with time zone NOT NULL,
"LastSeenAt" timestamp with time zone NULL,
CONSTRAINT "PK_Devices" PRIMARY KEY ("Id"),
CONSTRAINT "AK_Devices_AccessToken" UNIQUE ("AccessToken")
);Таблица DeviceGroups (Технологические группы):
sql
CREATE TABLE IF NOT EXISTS "DeviceGroups" (
"Id" uuid NOT NULL,
"OwnerId" text NOT NULL,
"Name" text NOT NULL,
"CalculationType" integer NOT NULL,
"DatasetId" uuid NOT NULL,
"DeviceIds" uuid[] NOT NULL,
"CreatedAt" timestamp with time zone NOT NULL,
CONSTRAINT "PK_DeviceGroups" PRIMARY KEY ("Id")
);Таблица TelemetryLogs (Журнал телеметрии датчиков):
sql
CREATE TABLE IF NOT EXISTS "TelemetryLogs" (
"Id" uuid NOT NULL,
"DeviceId" uuid NOT NULL,
"Timestamp" timestamp with time zone NOT NULL,
"PayloadJson" text NOT NULL,
"Status" integer NOT NULL DEFAULT 0,
"CalculationRunId" uuid NULL,
"Efficiency" double precision NULL,
"ResultJson" text NULL,
"ErrorMessage" text NULL,
CONSTRAINT "PK_TelemetryLogs" PRIMARY KEY ("Id"),
CONSTRAINT "FK_TelemetryLogs_Devices_DeviceId"
FOREIGN KEY ("DeviceId") REFERENCES "Devices" ("Id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "IX_TelemetryLogs_DeviceId_Timestamp"
ON "TelemetryLogs" ("DeviceId", "Timestamp");Таблица GroupTelemetryLogs (Журнал групповых балансов):
sql
CREATE TABLE IF NOT EXISTS "GroupTelemetryLogs" (
"Id" uuid NOT NULL,
"GroupId" uuid NOT NULL,
"Timestamp" timestamp with time zone NOT NULL,
"Status" integer NOT NULL DEFAULT 0,
"MergedPayloadJson" text NULL,
"ResultJson" text NULL,
"Efficiency" double precision NULL,
"ErrorMessage" text NULL,
CONSTRAINT "PK_GroupTelemetryLogs" PRIMARY KEY ("Id"),
CONSTRAINT "FK_GroupTelemetryLogs_DeviceGroups_GroupId"
FOREIGN KEY ("GroupId") REFERENCES "DeviceGroups" ("Id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "IX_GroupTelemetryLogs_GroupId_Timestamp"
ON "GroupTelemetryLogs" ("GroupId", "Timestamp");4. Регламент миграций и резервного копирования
Автоматическое применение миграций (Code-First)
Каждый микросервис при инициализации в контейнере Docker запускает автоматическое создание и обновление таблиц через механизм Entity Framework Core:
csharp
using var scope = app.Services.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<IoTDbContext>();
await dbContext.Database.MigrateAsync();Резервное копирование баз данных
Для обеспечения катастрофоустойчивости на сервере настраивается автоматическое резервное копирование с использованием утилиты pg_dump:
bash
pg_dump -h localhost -U postgres -d heat_balance_datasets -F c -b -v -f "/backup/datasets_$(date +%Y%m%d_%H%M%S).dump"
pg_dump -h localhost -U postgres -d heat_balance_runs -F c -b -v -f "/backup/runs_$(date +%Y%m%d_%H%M%S).dump"
pg_dump -h localhost -U postgres -d heat_balance_iot -F c -b -v -f "/backup/iot_$(date +%Y%m%d_%H%M%S).dump"Глубина хранения инкрементальных и полных бэкапов в цеховом архиве составляет 90 календарных дней.