При проектировании систем, которые должны в режиме реального времени или с высокой частотой (например, раз в 10 минут) собирать данные из десятков или сотен распределенных баз 1С, ИТ-архитекторы сталкиваются с серьезными вызовами. Основная сложность заключается в требовании сохранить конфигурации 1С абсолютно типовыми, избежать их кастомизации и при этом обеспечить стабильную работу под высокой нагрузкой. В этой статье мы подробно проанализируем различные варианты архитектуры взаимодействия приложений на .NET (C#) с базами 1С, разберем их сильные и слабые стороны, а также рассмотрим технические нюансы реализации каждого подхода.
Когда наше приложение на C# пытается самостоятельно «опрашивать» 150 баз 1С по расписанию (классическая модель Pull), мы моментально сталкиваемся с критическим ограничением платформы — лицензированием. Каждое активное соединение через COM-соединение или стандартный REST API (OData) расходует клиентскую лицензию 1С. Если запускать параллельный опрос всех баз, потребуется огромное количество свободных лицензий, что финансово нецелесообразно. Более того, постоянные входящие запросы создают пиковую нагрузку на сервера приложений 1С в удаленных точках.
Для решения этой проблемы мы можем пойти двумя путями:
Проанализируем детально технические варианты реализации обеих моделей.
Начиная с версии платформы 1С:Предприятие 8.3, разработчикам доступен встроенный REST-интерфейс (OData), который позволяет взаимодействовать с объектами базы данных без написания кода в самой 1С. Для его активации достаточно опубликовать базу на веб-сервере (IIS или Apache) и включить соответствующую опцию в настройках публикации.
Давайте разберем, как выглядит работа через OData. Приложение на C# отправляет стандартный HTTP-запрос к сущностям 1С. Однако здесь кроется серьезная проблема производительности. Стандартный механизм OData транслирует запросы в SQL крайне неоптимально, особенно когда дело касается получения виртуальных таблиц, таких как СрезПоследних для регистров сведений или остатков на конкретную дату для регистров накопления. При одновременном запросе остатков из 100+ баз OData может вызвать зависание рабочих процессов 1С.
Тем не менее, этот способ идеален, если нам нужно быстро развернуть систему без программирования в 1С. Для снижения нагрузки мы рекомендуем использовать кэширование на стороне C# и настроить строгую очередь запросов, чтобы не перегружать каналы связи и лицензионный пул.
Если нам необходимо получить высокую производительность, но при этом категорически запрещено менять типовую конфигурацию (вносить изменения в основную ветку метаданных), на помощь приходят Расширения конфигурации. Этот механизм позволяет дописывать логику, которая будет выполняться в контексте базы, не снимая саму конфигурацию с поддержки.
Мы можем создать расширение, в котором опишем собственный HTTP-сервис. Внутри этого сервиса пишется один оптимальный запрос на встроенном языке 1С, который собирает нужные остатки по счетам из регистров и преобразует их в компактный JSON-пакет. Наше C#-приложение будет обращаться к этому эндпоинту. Такой подход решает сразу две проблемы: минимизирует объем передаваемого трафика и выполняет запрос на стороне СУБД максимально быстро, так как запрос пишется разработчиком вручную и оптимизируется под конкретную задачу.
Посмотрим на пример кода, который может быть размещен в модуле HTTP-сервиса в расширении 1С для отдачи остатков по счетам:
Функция ПолучитьОстатки(Запрос)
УстановитьПривилегированныйРежим(Истина);
ЗапросБД = Новый Запрос;
ЗапросБД.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Счет КАК Счет,
| ХозрасчетныйОстатки.Субконто1 КАК Субконто,
| ХозрасчетныйОстатки.СуммаОстаток КАК Сумма
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, , , ) КАК ХозрасчетныйОстатки";
ЗапросБД.УстановитьПараметр("Период", ТекущаяДата());
Результат = ЗапросБД.Выполнить().Выгрузить();
// Сериализация в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Результат);
СтрокаJSON = ЗаписьJSON.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
КонецФункции
Что делать, если базы 1С работают на старых версиях платформы или у нас нет возможности опубликовать веб-сервисы? В этом случае мы можем использовать механизм запуска внешних обработок (файлы формата .epf) через командную строку 1С с параметром /Execute.
Схема выглядит следующим образом: служба на C# или локальный планировщик задач периодически запускает тонкий или толстый клиент 1С, передавая ему путь к внешней обработке. Внутри обработки прописывается процедура ПриОткрытии (или обработчик ожидания), которая собирает необходимые данные, сохраняет их во временный файл (например, XML или JSON) или отправляет по HTTP на центральный сервер C#, а затем принудительно закрывает сеанс 1С командой ЗавершитьРаботуСистемы().
Этот метод хорош тем, что сеанс 1С живет ровно столько, сколько нужно для выгрузки данных, и лицензия освобождается сразу после завершения процесса. Однако частый запуск тяжелого клиента 1С каждые 10 минут на слабом оборудовании может создавать высокую нагрузку на дисковую подсистему и процессор.
Для достижения максимальной производительности без затрат на лицензии 1С мы можем прибегнуть к прямому чтению таблиц базы данных из C# через ADO.NET или Entity Framework. Это самый быстрый способ получения информации, так как он полностью обходит сервер приложений 1С.
Главная сложность здесь — обфусцированная структура таблиц 1С. Платформа генерирует имена таблиц и полей динамически (например, таблица остатков может называться _AccumRegTotals1234). Чтобы решить эту проблему, мы можем один раз получить карту метаданных. В 1С есть встроенный метод ПолучитьСтруктуруХраненияБазыДанных(), который возвращает соответствие объектов метаданных физическим таблицам СУБД. Мы можем запустить этот метод один раз (или выполнять периодически при обновлениях), сохранить структуру в JSON-файл и использовать его в C# для динамического построения SQL-запросов.
Давайте посмотрим, как получить структуру хранения программно в 1С:
ТаблицаСтруктуры = ПолучитьСтруктуруХраненияБазыДанных();
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ОткрытьФайл("C:\temp\db_structure.json");
ЗаписатьJSON(ЗаписьJSON, ТаблицаСтруктуры);
ЗаписьJSON.Закрыть();
Проанализировав этот файл в приложении на C#, мы сможем точно сопоставить класс остатков с физической SQL-таблицей и читать данные напрямую со скоростью работы СУБД. Стоит отметить, что данный подход официально не приветствуется вендором, однако он является стандартом де-факто в высоконагруженных аналитических системах.
Если мы хотим построить действительно масштабируемую и современную систему, нам следует отказаться от постоянных опросов (Pull) в пользу событийной архитектуры (Event-Driven). Вместо того чтобы C# регулярно «дергал» 150 баз, базы должны сами отправлять изменения при проведении документов или изменении остатков.
Мы можем внедрить шину сообщений (например, RabbitMQ). В базах 1С настраивается подписка на события (опять же, через расширение, чтобы не менять типовую конфигурацию). При проведении ключевых документов (расходный ордер, реализация товаров и услуг) код в расширении асинхронно отправляет сообщение в очередь RabbitMQ. Приложение на C#, подписанное на эту очередь, мгновенно получает и обрабатывает данные.
Для крупных инфраструктур отличным решением будет использование специализированного продукта 1С:Шина. Она позволяет настроить интеграцию без изменения кода конфигурации, используя встроенные механизмы планов обмена 1С и транслируя данные во внешние брокеры сообщений.
Так как наши 150 баз могут находиться в разных географических локациях и сетях, критически важно защитить каналы связи. Если мы используем Pull-модель, нам придется открывать порты веб-серверов наружу. В этом случае обязательно использование защищенных VPN-тоннелей (например, WireGuard или IPSec) либо публикация баз через реверс-прокси Nginx с настройкой взаимной TLS-авторизации (mTLS) по клиентским сертификатам.
При Push-модели безопасность организовать значительно проще. Базам 1С не требуются входящие открытые порты, им нужен только исходящий доступ в интернет. На стороне C#-приложения разворачивается единый защищенный шлюз (API Gateway) с HTTPS. Базы 1С отправляют POST-запросы с данными, проходя авторизацию по токенам (например, JWT), что сводит к минимуму риски несанкционированного доступа.
Чтобы C#-приложению не приходилось адаптироваться под особенности метаданных разных конфигураций (например, Бухгалтерия предприятия, Управление торговлей, ERP), мы рекомендуем использовать встроенный стандарт EnterpriseData. Это универсальный формат обмена, основанный на XML/JSON, который поддерживается всеми типовыми решениями 1С. Настроив интеграцию через него, мы пишем на стороне C# один универсальный парсер, который будет корректно обрабатывать остатки и документы независимо от того, из какой именно конфигурации они пришли.
Выбор конкретного решения зависит от требований к задержкам данных и ресурсов разработки. Мы рекомендуем придерживаться следующих правил:
OData, но ограничьте частоту опроса и настройте очередь на стороне C#.Расширение с собственным HTTP-сервисом, отдающим сжатый JSON.