«1С тормозит» — это не техническое утверждение, а начало спора. Бизнес говорит «тормозит», подрядчик говорит «у нас всё в норме», и обе стороны правы, потому что меряют разное: пользователь меряет секунды до открытия документа, подрядчик — загрузку CPU на сервере.
Спор заканчивается там, где появляются цифры. Проблема в том, что цифры про 1С живут на трёх разных уровнях, и стоимость доступа к ним отличается на порядок. Половина разочарований в мониторинге 1С — от того, что человек ждал цифр третьего уровня, а поставил инструмент первого.
Я собираю мониторинг 1С в составе своей платформы наблюдаемости и за последние месяцы прошёл все три уровня, включая пару очень неочевидных граблей на Windows. Ниже — разбор по уровням: что видно, чего не видно, чем это ловится и где именно молча ломается.
Дисклеймер: платформа называется Voltir, я её автор. Дальше — только открытые инструменты и грабли из практики: всё описанное собирается из prometheus_1C_exporter, windows_exporter, fluent-bit и Grafana без всякого моего продукта.
Три уровня наблюдаемости 1С
Уровень 1. Операционная система. CPU, память, диск, сеть на серверах 1С и СУБД. Ставится за пять минут, node_exporter или windows_exporter. Отвечает на вопрос «железо ли виновато» и почти никогда — на вопрос «почему тормозит документ».
Уровень 2. Кластер серверов 1С. Сеансы, соединения, лицензии, рабочие процессы, регламентные задания, доступная производительность. Берётся снаружи через службу администрирования RAS/RAC, в базу лезть не нужно. Ставится за час. Отвечает на «что происходит в кластере прямо сейчас».
Уровень 3. Приложение. APDEX по ключевым операциям, ошибки прикладного кода, бизнес-метрики. Живёт только внутри информационной базы, снаружи не достаётся ни при каких условиях. Требует изменений в базе клиента.
Ключевая мысль, ради которой стоит читать дальше: APDEX — это уровень 3. Всё, что вам покажут снаружи и назовут «APDEX», им не является.
Уровень 3, сразу: почему APDEX не бывает снаружи
APDEX (Application Performance Index) считается так: каждый замер операции сравнивается с целевым временем T. Если операция уложилась в T — она «удовлетворяет». Если в интервал от T до 4T — «терпимо». Больше 4T — «раздражает». Итог:
APDEX = (Satisfied + Tolerating / 2) / Total
Число от 0 до 1. У 1С это часть методики оценки производительности, и считается оно подсистемой «Оценка производительности» из БСП: в прикладном коде расставлены замеры ключевых операций («Проведение реализации», «Открытие формы заказа»), у каждой — своё T, замеры копятся в регистре, по ним строится история.
Отсюда два следствия, которые экономят месяцы:
Целевое время T — это бизнес-решение, а не техническая константа. «Проведение реализации за 3 секунды» — норма для одной компании и катастрофа для другой. APDEX без согласованного T не значит ничего, и никакой инструмент не подставит его за вас.
Замер делается внутри операции, вокруг прикладного кода. Ни кластер, ни СУБД, ни ОС не знают, где у вас начинается и заканчивается «проведение реализации». Снаружи видно время серверного вызова — это другая величина: она не включает клиентскую часть и не совпадает с границами бизнес-операции.
То, что снаружи иногда выдают за APDEX, — это либо среднее время серверного вызова, либо «доступная производительность» кластера (см. ниже). Обе метрики полезны. Обе — не APDEX.
Я рассматривал готовое решение с HTTP-сервисом внутри базы, отдающим метрики в Prometheus, и отказался по трём типовым причинам: проект давно не развивается и совместимость со свежими 8.3.2x никто не проверял; в репозитории не указана лицензия, то есть включать его в продукт нельзя, чем бы оно ни было хорошо технически; и оно ломает онбординг — загрузка расширения в базу, публикация веб-сервиса, роль и учётка, то есть час-два ручной работы на базу и страх 1С-ников клиента перед вмешательством в рабочую базу.
Рабочий путь к уровню 3, если он вам действительно нужен, я вижу такой: замеры БСП выгружаются во внешний файл или локальный endpoint на том же хосте, откуда их забирает уже стоящий там агент. Никаких веб-сервисов наружу, никакой новой поверхности атаки. Но это отдельная работа и отдельный разговор с владельцем базы.
Уровень 2: что реально видно через RAS/RAC
Теперь то, что достаётся снаружи и стоит дёшево.
Кластер 1С — это несколько процессов: ragent (агент сервера, порт 1540, запускает остальное), rmngr (менеджер кластера, 1541, управляет, но прикладной код не исполняет) и rphost (рабочие процессы, исполняют код и обслуживают клиентов; их несколько). Отдельного процесса «доступа к СУБД» в кластере нет — rphost ходит в базу сам.
Администрируется всё это через RAS — фоновую службу администрирования (порт 1545), к которой подключается консольный клиент rac:
bash
ras cluster --port=1545 --service localhost:1540 # адрес ragent rac 127.0.0.1:1545 cluster list rac 127.0.0.1:1545 process list --cluster=<uuid> rac 127.0.0.1:1545 session list --licenses --cluster=<uuid>
Дальше есть готовый экспортёр — LazarenkoA/prometheus_1C_exporter (MPL-2.0, что важно, если вы это распространяете). Он и дёргает rac, разбирая вывод. Набор метрик:
Метрика |
Что даёт |
Откуда |
Что нужно |
|---|---|---|---|
|
доступная производительность каждого rphost + средние времена вызовов ( |
|
доступ к RAS |
|
сеансы кластера и их показатели |
RAC |
доступ к RAS |
|
соединения с кластером |
RAC |
доступ к RAS |
|
выданные клиентские лицензии |
|
доступ к RAS |
|
блокировка регламентных заданий по каждой базе |
|
логин и пароль информационной базы |
|
ресурсы хоста и процессов |
локально с машины |
— |
Три практических вывода из этой таблицы:
Первое. cpu, disk, processes снимаются локально с той машины, где запущен экспортёр. Если у вас кластер из нескольких рабочих серверов, экспортёр нужен на каждом — иначе вы видите ресурсы одного из них и думаете, что видите кластер.
Второе. shedule_job требует учётные данные информационной базы (в экспортёре они не пишутся в конфиг, а забираются с внешнего endpoint'а, отдающего JSON с логином и паролем по каждой базе). Если метрика включена, а источник кредов не настроен, экспортёр падает на старте и уходит в рестарт-цикл — то есть вы теряете не одну метрику, а все. Я эту метрику по умолчанию выключаю и включаю точечно, когда клиент готов дать учётку.
Третье, самое обидное. На сервере с лицензией разработчика вы не увидите session, sessions_data и client_lic — и это не поломка: активных сеансов нет, значит summary-метрики не публикуются, серверные клиентские лицензии не выдаются. Я потратил на это время: дашборд выглядел абсолютно мёртвым, включая панели, у которых данные были. Причина оказалась не в метриках, а в дашборде — переменная host строилась через label_values(session, host), без сеансов список хостов пустой, и дашборд схлопывался целиком. Строить переменную нужно по метрике, которая есть всегда:
label_values(up{job="1c"}, host)
Правило шире 1С: переменную дашборда стройте по метрике, существующей при пустой системе, иначе пустая система выглядит как сломанная.
Про «доступную производительность»: как её читать и как не читать
Метрика available_performance (в консоли кластера — «доступная производительность») получается так: кластер периодически прогоняет на каждом рабочем процессе эталонный тестовый вызов, задействующий диск, память и процессор, и усредняет результат за последние несколько минут (в источниках встречается и 5, и 10 минут — не закладывайтесь на точную цифру). Результат — те самые «попугаи», по которым кластер выбирает, куда направить нового клиента: новые подключения идут на процесс с лучшей производительностью, а уже подключённые переезжают, только если сервер отказал или отличается от других в разы.
Что из этого следует для мониторинга:
Это относительная метрика. Сравнивать её между разными серверами и тем более между разными клиентами бессмысленно — она зависит от железа и от характера текущей нагрузки. Осмысленны две вещи: сравнение rphost'ов внутри одного кластера между собой и динамика во времени на одном процессе.
Просадка = процесс перегружен относительно соседей, и кластер уже начал уводить от него новых клиентов. Это ранний сигнал, до того как пользователи начнут жаловаться.
Алертить на абсолютное значение нельзя. Порог, работающий у одного клиента, у другого даст либо тишину, либо шторм. Работает алерт на просадку относительно собственного недавнего уровня.
И одна грабля, стоившая мне дублей алертов. Экспортёр мультиплексирует несколько разных величин в одну метрику, различая их лейблом type (собственно производительность, среднее время вызова, среднее время вызова СУБД и т.д.). Если написать правило без фильтра по type, оно сработает сразу на нескольких рядах, отличающихся только этим лейблом, — и вы получите пачку алертов с разными fingerprint'ами про одну проблему:
yaml
# ПЛОХО: сработает на всех type сразу, дубли алертов - alert: OneCPerformanceDegraded expr: available_performance < 30 # ХОРОШО: фильтр по type обязателен, порог — относительный - alert: OneCPerformanceDegraded expr: available_performance{type="available"} < 0.5 * avg_over_time(available_performance{type="available"}[1d] offset 1d) for: 10m
Имя метрики здесь без префикса — это дефолт экспортёра. Префикс p1c_, который часто встречается в примерах, включается отдельной настройкой MetricNamePrefix; если вы её задали, а правило скопировали без префикса — правило просто никогда не сработает. Молча, разумеется.
Уровень 1: что снимать на сервере 1С и с какими порогами
Главный подозреваемый — диск (и на сервере 1С, и особенно на сервере СУБД). Пороги по времени отклика, устоявшиеся в 1С-сообществе:
< 15 мс — хорошо;
16–50 мс — требует внимания;
> 50 мс — надо что-то делать; для SSD планка строже, там уже 25–30 мс означают проблему.
Плюс длина очереди к диску (ориентир — не больше числа устройств в массиве плюс 2) и % Disk Time выше 90 % как признак упора.
По CPU, памяти и сети официальных «нормативов 1С» нет — берите общую инфраструктурную практику (устойчивая загрузка выше 80–85 % долгое время, постоянный своп) и не выдавайте её за требование вендора.
Отдельно стоит помнить про механику памяти рабочих процессов: кластер сам контролирует объём памяти rphost по нескольким порогам. При превышении «временно допустимого» объёма на сервер перестают назначаться новые соединения; если превышение держится дольше заданного периода — процессы с наибольшим потреблением перезапускаются контролируемо; при достижении критического объёма — завершаются аварийно. Практический вывод: перезапуски rphost — это метрика, а не фон. Если вы видите просадку available_performance, синхронную с перезапуском rphost, вы нашли не две проблемы, а одну.
Техжурнал: когда метрик уже не хватает
Метрики отвечают «когда и насколько плохо». На «почему» отвечает технологический журнал.
Настраивается файлом logcfg.xml в каталоге conf платформы (/opt/1cv8/x86_64/current/conf/ на Linux, C:\Program Files\1cv8\conf\ на Windows). События, которые реально нужны для производительности:
TTIMEOUT — превышено время ожидания блокировки. Тот самый «Превышено максимальное время ожидания предоставления блокировки», таймаут по умолчанию 20 секунд;
TLOCK — операции с управляемыми блокировками;
TDEADLOCK — взаимоблокировки;
DBMSSQL / DBPOSTGRS — реальные запросы к СУБД с текстом и временем выполнения;
SDBL — запросы на внутреннем языке 1С;
CALL / SCALL — клиент-серверные и межпроцессные вызовы;
EXCP — исключения со стеком;
MEM, LEAKS — память процессов и утечки по соединениям.
Классическая методика расследования «зависаний»: находим TTIMEOUT (жертва), идём назад к её TLOCK, ищем конфликтующий TLOCK по тем же ресурсам — это виновник, дальше по объекту метаданных.
Но включать это постоянно нельзя. Полный журнал без фильтров на нагруженной системе пишет столько, что сам становится источником тормозов; в сообществе разбирают кейсы журналов за сотню гигабайт. Рабочий компромисс:
xml
<config xmlns="http://v8.1c.ru/v8/tech-log"> <log location="/var/log/1c/logs" history="24"> <!-- Постоянно: только дорогое и редкое --> <event><eq property="name" value="TTIMEOUT"/></event> <event><eq property="name" value="TDEADLOCK"/></event> <!-- Запросы к СУБД — только длиннее 3 секунд (duration в мкс) --> <event> <eq property="name" value="DBPOSTGRS"/> <ge property="duration" value="3000000"/> </event> <property name="all"/> </log> </config>
history здесь — срок хранения архивных файлов в часах; ротация по времени, не по объёму, так что за размером раздела следите сами. И связка, которая работает лучше всего: метрики держим постоянно, полный ТЖ включаем на час по алерту — метрика говорит «в 14:20 просела производительность», журнал за этот час говорит, какой запрос и на каком объекте.
Четыре места, где мониторинг 1С молча ломается на Windows
Самое ценное из практики — не архитектура, а вот эти четыре штуки. Все они дают не ошибку, а тишину: агент установлен, служба запущена, данных нет.
1. Путь к rac.exe в YAML — только в одинарных кавычках. В двойных обратный слэш — escape-последовательность, и C:\Program Files\1cv8\8.3.27.1000\bin\rac.exe разваливается на разборе ещё до старта экспортёра. На Linux этой проблемы нет вовсе, поэтому она приезжает сюрпризом.
2. Файл настроек, записанный PowerShell 5.1 с -Encoding utf8, получает BOM — а BOM в начале YAML ломает разбор. Пишите в ascii (и, соответственно, без кириллицы внутри), либо utf-8 без BOM.
3. Логи Windows не доезжают до хранилища — с кодом 200. Самая дорогая из четырёх. fluent-bit с json_date_format iso8601 пишет таймзону без двоеточия (+0300), это не RFC3339 — и хранилище логов отвечает HTTP 200, а строку выбрасывает. Из всех форматов времени отвергался ровно этот: epoch, числа, отсутствие поля времени — проходило всё. Лечится одной строкой: json_date_format epoch.
Методологическая яма рядом: curl -d без явного Content-Type: application/json отправляет form-urlencoded, и тело так же молча игнорируется с кодом 200. Час экспериментов по поиску причины оказался у меня невалидным именно из-за этого. Проверяя приём логов руками — всегда указывайте Content-Type явно.
Вторым слоем там же: у записей Windows Event Log нет поля уровня в привычном виде, а лог-дашборд жёстко фильтрует по нему — то есть даже доехавшие записи были бы отрезаны. Нужен маппинг уровней Windows в syslog-числа, единый со всеми остальными источниками.
4. Все Windows-хосты сливаются в один пункт дашборда. windows_exporter скрапится локально, и instance у каждого хоста получается 127.0.0.1:9182. А типовые дашборды построены по instance целиком. Лечится relabel'ом на этапе сбора:
yaml
relabel_configs: - target_label: instance replacement: '<имя_хоста>' # подставляется установщиком агента
Что алертить: минимальный набор
Если начинать с нуля, я бы взял такой набор — он покрывает большинство реальных обращений:
rphost перезапустился — сам по себе и особенно синхронно с просадкой производительности.
available_performanceпросела относительно собственного суточного уровня (не абсолютный порог!),for: 10m.TTIMEOUT/TDEADLOCK появились в журнале — на любом ненулевом количестве, это всегда конкретная боль конкретного пользователя.
Клиентские лицензии подошли к лимиту — иначе про это узнаёте от пользователя, который не смог войти.
Время отклика диска на сервере СУБД выше 20 мс устойчиво — раньше, чем это станет заметно в 1С.
Регламентные задания идут в рабочие часы — кросс-проверка времени запуска фоновых заданий с пиком пользовательской активности.
Экспортёр 1С не отвечает (
up{job="1c"} == 0) — иначе тишина в дашборде читается как «всё хорошо».
Итог
Снаружи кластера 1С доступно больше, чем принято думать: сеансы, лицензии, соединения, рабочие процессы, доступная производительность, регламентные задания, ресурсы серверов, техжурнал. Этого хватает, чтобы перевести спор «тормозит / не тормозит» в цифры и найти виновника в большинстве обращений — за час установки и без единого изменения в базе.
Чего снаружи не будет никогда — настоящего APDEX по бизнес-операциям. Он живёт в замерах внутри прикладного кода, и путь к нему лежит через разговор с владельцем базы и согласованное целевое время T для каждой ключевой операции. Инструмент здесь — последняя проблема; первая — договориться, за сколько секунд документ должен проводиться.
И, пожалуй, главный практический вывод: в мониторинге 1С самые дорогие дефекты не кричат. Они выглядят как пустой дашборд, как HTTP 200 на выброшенной строке лога и как один пункт в списке хостов там, где их должно быть пять.
Если у вас уже настроен мониторинг 1С — проверьте прямо сейчас две вещи: что переменная дашборда не строится по метрике сеансов, и что в правилах алертов на available_performance есть фильтр по лейблу type. Это две минуты и два самых частых способа получить тихо неработающий мониторинг.