SIM: Движок цифрового симулятора (Simulation Engine)
В открытом доступе представлена демонстрационная версия метода. В настоящей публичной документации отображены не все шаги, технические сценарии и приватные эндпоинты для системы цифровых симуляторов бизнес-процессов.
- Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).
1. Концепция Движка (Simulation Engine)
Движок симулятора — это изолированный архитектурный компонент (микросервис на языке Go), который обеспечивает жизненный цикл симуляции, оркестрацию потоков времени, управление конкурентностью, интеграцию с базами данных и шинами сообщений.
Движок спроектирован по принципу Pluggable Architecture (подключаемые модули). Он ничего не знает о специфике бизнес-логики (будь то кухня, логистика или финансы) и оперирует абстрактными интерфейсами процессов.
Общая топология системы:
2. API Управление и Жизненный цикл Симуляции
Управление симуляциями осуществляется через EngineController посредством HTTP REST API. Контроллер обеспечивает неблокирующий запуск и безопасную принудительную остановку процессов.
2.1 Асинхронный запуск (StartHandler)
При получении запроса POST /start движок выполняет следующие шаги:
Декодирование и валидация: Извлекается
ProcessID,ProcessTypeи глубина симуляции в часах (Hours).Динамическое извлечение возможностей (Interface Assertion): Движок берет абстрактный процесс из реестра (
processRegistry) и приводит его к интерфейсуDBProfileLoader. Это позволяет изолировать логику чтения параметров конкретного процесса от ядра симулятора.Инициализация контекста: Создается отменяемый контекст выполнения:
ctx, cancel := context.WithCancel(context.Background()) ec.activeSims.Store(req.ProcessID, cancel)Offloading в бэкграунд: Тяжелый цикл вычислений запускается в отдельной горутине, а клиент мгновенно получает ответ
202 Acceptedс числом активированных цифровых двойников.
2.2 Принудительная остановка (StopHandler)
Позволяет досрочно погасить симуляцию по process_id. Из потокобезопасной карты sync.Map извлекается соответствующий context.CancelFunc, вызов которого каскадно останавливает все связанные горутины воркеров.
3. Масштабирование и Конкурентность (High-Throughput Execution)
Для обеспечения одновременной симуляции десятков тысяч цифровых двойников (агентов) в рамках одного виртуального часа, SimulationEngine реализует паттерны Fan-Out и Concurrency Throttling.
3.1 Ограничение пула через Семафор (Bounded Concurrency)
Прямой запуск горутины под каждого агента без контроля ресурсов может привести к исчерпанию дескрипторов ОС, перегрузке планировщика Go и падению RAM. Движок блокирует это за счет буферизированного канала-семафора внутри каждого временного тика:
var wg sync.WaitGroup
sem := make(chan struct{}, 5000) // Жесткий лимит на 5000 параллельных воркеров
for _, userID := range userIDs {
wg.Add(1)
go func(id int64) {
defer wg.Done()
sem <- struct{}{} // Захват слота
defer func() { <-sem }() // Освобождение слота
se.processAgentTick(ctx, id, staticProfiles[id], currentVirtualTime)
}(userID)
}
wg.Wait() // Барьер синхронизации: время не пойдет вперед, пока все не завершат тик4. Двухуровневое управление состоянием (State Hydration & Fallback)
Метод processAgentTick выполняет сборку (гидратацию) состояния агента перед передачей его в математическую модель. Движок использует гибридную схему: Локальный кэш (Redis) -> Внешняя сеть (gRPC) -> Безопасный дефолт.
flowchart TD
A[Начало тика агента] --> B{Запрос в Redis}
B -->|Найдено| C[Передача стейта в Модель]
B -->|Cache Miss / Пусто| D{Бизнес-логика реализует StateWarmer?}
D -->|Да| E[gRPC вызов Login + GetFridgeState]
E -->|Успешно| F[Сохранить в Redis] --> C
E -->|Сбой сети| G[Загрузить Default State] --> C
D -->|Нет| G
4.1 Пакетный конвейер (Redis Pipeline) и Оптимизация памяти
- Lazy Loading: Состояние прогревается только в момент реальной необходимости.
- Zero-Allocation приведение типов: Вместо использования рефлексии (
reflect), движок применяет конструкциюswitch-caseдля сырых интерфейсов из Redis, преобразуя их в примитивы без аллокаций в куче (Heap). - Пакетная запись: При инициализации больших процессов (
InitStateInRedis) используетсяrdb.Pipeline(), группирующий команды записи для минимизации сетевых задержек (RTT).
5. Схемы интеграционных данных (Примеры Payloads)
Движок не сохраняет результаты деятельности агентов в доменные базы напрямую. Взаимодействие со смежными сервисами и собственным контуром планирования происходит асинхронно через топики Apache Kafka.
После выполнения расчета поведения, движок отправляет два типа событий в Apache Kafka. Разработчикам транспортного уровня необходимо закладываться на следующие JSON-схемы:
5.1 Топик twin-history-events (Снимок состояния для аналитики)
Отправляется на каждый тик каждого агента (даже если он бездействует). Служит для сквозного логирования динамических параметров и верификации гипотез в аналитических хранилищах (например, ClickHouse).
{
"user_id": 48291,
"process_id": "proc-food-2026-v1",
"virtual_time": "2026-09-28T14:00:00+03:00",
"action": "COOKING",
"metrics": {
"current_state": "COOKING",
"current_hunger": 0.65,
"current_stress": 0.21,
"time_since_last_shop": 2,
"cached_fridge": "{\"items\":[{\"item_id\":\"a9c2-4bbf\",\"name\":\"Молоко\",\"category\":\"Молочные продукты\",\"portions\":1.5,\"weight_grams\":300,\"price\":90}]}"
}
}5.2 Топик agent-intents (Транзакционное намерение совершить действие)
Генерируется только тогда, когда действие агента отличается от IDLE. Содержит смещенное виртуальное время (Virtual Time + Delay), указывающее, когда именно в будущем действие будет совершено. Данный топик вычитывается внутренним планировщиком симулятора. Когда маркер глобального цикла currentVirtualTime догоняет время интента, Движок извлекает его и инициирует физический вызов сначала ИИ-сервиса, затем продуктового микросервиса (например, отправляет чек с продуктами в FoodTracker)
{
"user_id": 48291,
"process_id": "proc-food-2026-v1",
"action_type": "COOKING",
"virtual_time": "2026-09-28T14:45:00+03:00"
}