Имплементация системы мониторинга кластеров 1С (и лицензий)





В этой статье мы научимся хранить данные о сеансах консоли кластеров 1С в СУБД, вынимать и агрегировать информацию о лицензиях.
upd. 2024.12.19
обновил главный файл сбора данных — зафиксировал, что регулярное выражение покрывало не все сеансы.
 
Имплементация системы мониторинга кластера 1С (и лицензий).
 
Для успешного приготовления нам потребуются:
  1. 1С Предприятие нужного Вам релиза.
  2. Linux* (я использую CentOS 7.5)
  3. Grafana* ( я использую версию 5.2.4)
  4. Postgres Pro* (у меня сейчас 10.6.1)
  5. Python (у меня 3.6.*)
 
*Вопросы установки LinuxGrafana и Postgre Pro в данной статье не будут рассмотрены.
 
 
Сначала коснёмся . Для сбора данных через RAS нам нужно:
 
  1. Установить(и запустить) службу RAS на серверах приложений 1С под Windows. Через RAS мы будем получать данные от этого СП . Установить службу можно сделать такой командой:
"C:WindowsSystem32sc.exe" create "1C:Remote Administation Serive (RAS)" binPath= ""C:Program Files1cv88.3.12.1685in
as.exe" cluster —service —port=1545 ИМЯ_СЕРВЕРА:1540" start= auto
            Для автоматической установки службы RAS можно воспользоваться скриптом func.install_ras.ps1 из раздела загрузки.
 
  1. Установить необходимые компоненты rac на Linux.
     
    Для CentOS потребуется потребуется скачать с https://releases.1c.ru/  Сервер 1С:Предприятия (64-bit) для RPM-based Linux-систем.
    Порядок установки пакетов, на примере релиза 8.3.12.1685 для моей ОС следующий:
yum install -y 1C_Enterprise83-common-8.3.12-1685.x86_64.rpm
yum install -y 1C_Enterprise83-common-nls-8.3.12-1685.x86_64.rpm
yum install -y 1C_Enterprise83-server-8.3.12-1685.x86_64.rpm
yum install -y 1C_Enterprise83-server-nls-8.3.12-1685.x86_64.rpm
            После этого rac будет доступен из /opt/1C/v8.3/x86_64/rac.
 
  1. Проверить корректность установки можно подключившись к RAS.
/opt/1C/v8.3/x86_64/rac cluster list ИМЯ_СЕРВЕРА:1545
Если всё правильно, то мы увидим подобное:
 
 
Теперь подготовим отдельную базу в Postgre.
 
В ней нам потребуется несколько таблиц:
  1. Таблица для хранения списка серверов RAS, к которым мы будет подключаться за данными.
  2. Вспомогательные таблицы для экономии места
  3. Таблица данных о сеансах.
 
Подключаемся к postgre из консоли:
su postgres
psql
 
Создаём пользователя для работы со своей базой данных:
CREATE ROLE "racer" LOGIN PASSWORD ‘my_evil_password’;
 
Создаём отдельную базу данных:
CREATE DATABASE "racerDB"
WITH
  OWNER = "racer"
  ENCODING = ‘UTF8’
  LC_COLLATE = ‘ru_RU.UTF-8@icu.58.0.0.50’
  LC_CTYPE = ‘ru_RU.UTF-8’
  TABLESPACE = "pg_default"
;
connect racerDB;
 
Создаём таблицу для хранения списка RAS-серверов, к которым будем подключаться:
CREATE TABLE "public"."ras_servers" (
  "id" SERIAL PRIMARY KEY,
  "host_name" varchar(255) NOT NULL,
  "ras_port" int2 NOT NULL
);
ALTER TABLE "public"."ras_servers"
  OWNER TO "racer";
 
И заполняем её списком своих RAS-серверов:
INSERT INTO "public"."ras_servers"("host_name", "ras_port") VALUES (‘ИМЯ_СЕРВЕРА_1’, 1545) RETURNING *;
INSERT INTO "public"."ras_servers"("host_name", "ras_port") VALUES (‘ИМЯ_СЕРВЕРА_2’, 1545) RETURNING *;
INSERT INTO "public"."ras_servers"("host_name", "ras_port") VALUES (‘ИМЯ_СЕРВЕРА_N’, 1545) RETURNING *;
 
Теперь нам нужно создать несколько служебных таблиц, чтобы хранить в них ссылки на данные из главной таблицы соединений.
 
  • Таблица для хранения списка пользователей
CREATE TABLE "public"."users" (
  "id" SERIAL PRIMARY KEY,
  "name" varchar(255) NOT NULL
);
ALTER TABLE "public"."users"
  OWNER TO "racer";
 
  • Таблица со списком информационных баз
CREATE TABLE "public"."infobases" (
  "id" SERIAL PRIMARY KEY,
  "uuid"  varchar(36) NOT NULL,
  "name"  varchar(255) NOT NULL,
  "descr" varchar(1024)
);
ALTER TABLE "public"."infobases"
  OWNER TO "racer";
 
  • Таблица со списком клиентских ПК
CREATE TABLE "public"."hosts" (
  "id" SERIAL PRIMARY KEY,
  "name" varchar(255) NOT NULL
);
ALTER TABLE "public"."hosts"
  OWNER TO "racer";
 
  • Таблица со списком лицензий
CREATE TABLE "public"."licenses_db" (
  "id" SERIAL PRIMARY KEY,
  "name" varchar(255) NOT NULL,
  "type" varchar(4)   NOT NULL,
  "max"  int2         NOT NULL
);
ALTER TABLE "public"."licenses_db"
  OWNER TO "racer";
 
  • Таблица со списком приложений
CREATE TABLE "public"."apps" (
  "id" SERIAL PRIMARY KEY,
  "name" varchar(255) NOT NULL,
  "description" varchar(255)
);
ALTER TABLE "public"."apps"
  OWNER TO "racer";
—и сразу заполним её
INSERT INTO "public"."apps"("name", "description") VALUES (‘1CV8’, ‘Толстый клиент’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘1CV8C’, ‘Тонкий клиент’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘WebClient’, ‘Веб-клиент’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘Designer’, ‘Конфигуратор’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘COMConnection’, ‘COM-соединение’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘WSConnection’, ‘Сессия веб-сервиса’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘BackgroundJob’, ‘Фоновое задание’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘SystemBackgroundJob ‘, ‘Системное фоновое задание’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘SrvrConsole’, ‘Консоль кластера’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘COMConsole’, ‘COM-консоль кластера’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘JobScheduler ‘, ‘Планировщик’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘Debugger’, ‘Отладчик’) RETURNING *;
INSERT INTO "public"."apps"("name", "description") VALUES (‘RAS’, ‘Сервер администрирования’) RETURNING *;
 
  • Таблица со списком процессов сервера . В ней будет храниться неизменяемая информация о процессах СП (она нужна нам для получения имени рабочего сервера для сессии)
CREATE TABLE "public"."processes" (
  "id" SERIAL PRIMARY KEY,
  "uuid" varchar(36) NOT NULL,
  "host" varchar(255),
  "port" int4,
  "pid"  int4,
  "started_at"  timestamp
);
ALTER TABLE "public"."processes"
  OWNER TO "racer";
 
Теперь создаём таблицу, в которой будем хранить информацию о соединениях и их лицензиях.
CREATE TABLE "public"."sessions" (
    "ras_server_by_id"                  int2        NOT NULL,                               —ссылка на имя RAS-сервера, с которого были получены данные
    FOREIGN KEY("ras_server_by_id")     REFERENCES  hosts(id)       ON DELETE SET DEFAULT,  —ссылка на имя RAS-сервера, с которого были получены данные
    "datetime"                          timestamp   NOT NULL,                               —дата и время получения среза в UTC
    "session-id_nmb"                    int4        NOT NULL,                               —номер сессии
    "infobase_by_id"                    int2        NOT NULL,                               —id информационной базы из таблицы infobases
    FOREIGN KEY("infobase_by_id")       REFERENCES infobases(id)    ON DELETE SET DEFAULT,  —id информационной базы из таблицы infobases
    "process_by_id"                     int4                ,                               —id процесс СП 1C из таблицы processes
    FOREIGN KEY("process_by_id")        REFERENCES  processes(id)   ON DELETE SET DEFAULT,  —id процесс СП 1C из таблицы processes
    "user-name_by_id"                   int2        NOT NULL,                               —id пользователя из таблицы users
    FOREIGN KEY("user-name_by_id")      REFERENCES  users(id)       ON DELETE SET DEFAULT,  —id пользователя из таблицы users
    "host_by_id"                        int2        NOT NULL,                               —id хоста пользователя
    FOREIGN KEY("host_by_id")           REFERENCES  hosts(id)       ON DELETE SET DEFAULT,  —id хоста пользователя
    "app-id_by_id"                      int2        NOT NULL,                               —id приложения из таблицы apps
    FOREIGN KEY("app-id_by_id")         REFERENCES  apps(id)        ON DELETE SET DEFAULT,  —id приложения из таблицы apps
    "started-at"                        timestamp   NOT NULL,                               —дата и время начала сеанса в UTC
    "last-active-at"                    timestamp   NOT NULL,                               —последняя активность
    "hibernate"                         bool        NOT NULL,                               —спящий ли сеанс
    "passive-session-hibernate-time"    int4        NOT NULL,                               —
    "hibernate-session-terminate-time"  int4        NOT NULL,                               —
    "blocked-by-dbms"                   int4        NOT NULL,                               —
    "blocked-by-ls"                     int4        NOT NULL,                               —
    "bytes-all"                         int8        NOT NULL,                               —
    "bytes-last-5min"                   int8        NOT NULL,                               —
    "calls-all"                         int4        NOT NULL,                               —
    "calls-last-5min"                   int4        NOT NULL,                               —
    "dbms-bytes-all"                    int8        NOT NULL,                               —
    "dbms-bytes-last-5min"              int8        NOT NULL,                               —
    "db-proc-info"                      int4        NOT NULL,                               —
    "db-proc-took"                      int4        NOT NULL,                               —
    "db-proc-took-at"                   timestamp           ,                               —
    "duration-all"                      int4        NOT NULL,                               —
    "duration-all-dbms"                 int4        NOT NULL,                               —
    "duration-current"                  int4        NOT NULL,                               —
    "duration-current-dbms"             int4        NOT NULL,                               —
    "duration-last-5min"                int4        NOT NULL,                               —
    "duration-last-5min-dbms"           int4        NOT NULL,                               —
    "memory-current"                    int8        NOT NULL,                               —
    "memory-last-5min"                  int8        NOT NULL,                               —
    "memory-total"                      int8        NOT NULL,                               —
    "read-current"                      int8        NOT NULL,                               —
    "read-last-5min"                    int8        NOT NULL,                               —
    "read-total"                        int8        NOT NULL,                               —
    "write-current"                     int8        NOT NULL,                               —
    "write-last-5min"                   int8        NOT NULL,                               —
    "write-total"                       int8        NOT NULL,                               —
    "duration-current-service"          int4        NOT NULL,                               —
    "duration-last-5min-service"        int4        NOT NULL,                               —
    "duration-all-service"              int4        NOT NULL,                               —
    "license_by_id"                     int2                ,                               —размер ключа (на сколько он пользователей)
    FOREIGN KEY("license_by_id")        REFERENCES licenses_db(id)  ON DELETE SET DEFAULT,  —размер ключа (на сколько он пользователей)
    "license_issued_by_server"          bool                ,                               —признак выдачи лицензии сервером
    "license_net"                       bool                ,                               —сетевая ли лицензия
    "rmngr_by_id"                       int2                ,                               —хост, выдавший лицензию
    FOREIGN KEY("rmngr_by_id")          REFERENCES hosts(id)        ON DELETE SET DEFAULT   —хост, выдавший лицензию
);
ALTER TABLE "public"."sessions"
  OWNER TO "racer";
 
CREATE INDEX "by_date" ON "public"."sessions" USING btree (
  "datetime" "pg_catalog"."timestamp_ops" ASC NULLS LAST
);
 
Так как в таблице хранятся ссылки, а не абсолютные значения, создадим для удобства просмотров, агрегированный view_sessions, содержащий значения всех всех собранных данных:
CREATE VIEW "public"."view_sessions" AS
SELECT
     h1.name                                AS ras_host
   , s.datetime                             AS datetime
   , s."session-id_nmb"                     AS session_id
   , i.name                                 AS infobase_name
   , p.host                                 AS process_host
   , p.port                                 AS process_port
   , p.pid                                  AS process_pid
   , p.started_at                           AS process_started
   , u.name                                 AS user_name
   , h2.name                                AS user_host
   , a.name                                 AS app
   , s."started-at"                         AS started_at
   , s."last-active-at"                     AS last_active_at
   , s.hibernate                            AS hibernate
   , s."passive-session-hibernate-time"     AS passive_session_hibernate_time
   , s."hibernate-session-terminate-time"   AS hibernate_session_terminate_time
   , s."blocked-by-dbms"                    AS blocked_by_dbms
   , s."blocked-by-ls"                      AS blocked_by_ls
   , s."bytes-all"                          AS bytes_all
   , s."bytes-last-5min"                    AS bytes_last_5min
   , s."calls-all"                          AS calls_all
   , s."calls-last-5min"                    AS calls_last_5min
   , s."dbms-bytes-all"                     AS dbms_bytes_all
   , s."dbms-bytes-last-5min"               AS dbms_bytes_last_5min
   , s."db-proc-info"                       AS db_proc_info
   , s."db-proc-took"                       AS db_proc_took
   , s."db-proc-took-at"                    AS db_proc_took_at
   , s."duration-all"                       AS duration_all
   , s."duration-all-dbms"                  AS duration_all_dbms
   , s."duration-current"                   AS duration_current
   , s."duration-current-dbms"              AS duration_current_dbms
   , s."duration-last-5min"                 AS duration_last_5min
   , s."duration-last-5min-dbms"            AS duration_last_5min_dbms
   , s."memory-current"                     AS memory_current
   , s."memory-last-5min"                   AS memory_last_5min
   , s."memory-total"                       AS memory_total
   , s."read-current"                       AS read_current
   , s."read-last-5min"                     AS read_last_5min
   , s."read-total"                         AS read_total
   , s."write-current"                      AS write_current
   , s."write-last-5min"                    AS write_last_5min
   , s."write-total"                        AS write_total
   , s."duration-current-service"           AS duration_current_service
   , s."duration-last-5min-service"         AS duration_last_5min_service
   , s."duration-all-service"               AS duration_all_service
   , l.name                                 AS license_series
   , l.type                                 AS license_type
   , l.max                                  AS license_max
   , s.license_issued_by_server             AS license_issued_by_server
   , s.license_net                          AS license_net
   , h3.name                                AS license_rmngr
FROM
     sessions         s
LEFT JOIN hosts       h1                    ON s.ras_server_by_id   = h1.id
LEFT JOIN infobases   i                     ON s.infobase_by_id     = i.id
LEFT JOIN processes   p                     ON s.process_by_id      = p.id
LEFT JOIN users       u                     ON s."user-name_by_id"  = u.id
LEFT JOIN hosts       h2                    ON s.host_by_id         = h2.id
LEFT JOIN apps        a                     ON s."app-id_by_id"     = a.id
LEFT JOIN licenses_db l                     ON s.license_by_id      = l.id
LEFT JOIN hosts       h3                    ON s.rmngr_by_id        = h3.id
;
ALTER TABLE "public"."view_sessions"
  OWNER TO "racer";
 
Для выборки данных о лицензиях нам понадобится отдельный View, ибо с использованием лицензий не всё так просто.
утилизирует лицензии полученные клиентом и выданные сервером по разному:
  • при выдаче сервером для каждого сеанса выдаётся одна программная лицензия;
  • при выдаче сервером для каждого сеанса выдаётся одна аппаратная лицензия;
  • при выдаче клиентскому приложению службой HASP LM для каждого пользовательского сеанса(сессия RDP или локальное подключение Windows) на клиенте выдаётся одна аппаратная лицензия. При этом с этой одной лицензией можно работать в разных базах.
  • как считать программные лицензии, полученные локально клиентским приложением я ещё не определился, к ним применяется такой же порядок, как для аппаратных, выданных клиенту.
 
Из-за этих особенностей в отборе применяется три вида группировки:
  • для серверов, не являющихся  терминальными (отбираются через view_not_terminal_ids) агрегируются все подключения с каждого хоста для каждого уникального ключа;
  • для терминальных серверов (view_terminal_ids) применяется дополнительная агрегация и по имени пользователя — применяется допущение, что пользователь, работающий из терминальной сессии в разных базах, будет работать там под одним именем;
  • и наконец, для лицензий, выданных сервером, не применяется никакой группировки.
 
Сначала определимся со списком рабочих станций, не являющихся терминальными серверами:
CREATE VIEW view_not_terminal_ids AS
SELECT h.id from HOSTS h
WHERE
            (UPPER (( h.NAME ) :: TEXT ) !~~ ‘TERM%’ :: TEXT)
            AND
            (UPPER (( h.NAME ) :: TEXT ) !~~ ‘APP%’ :: TEXT)

;

ALTER TABLE "public"."view_not_terminal_ids"
  OWNER TO "racer";
 
Потом — со списком терминальных серверов:
CREATE VIEW view_terminal_ids AS
SELECT h.id from HOSTS h
WHERE
            (UPPER (( h.NAME ) :: TEXT ) ~~ ‘TERM%’ :: TEXT)
            OR
            (UPPER (( h.NAME ) :: TEXT ) ~~ ‘APP%’ :: TEXT)

;

ALTER TABLE "public"."view_terminal_ids"
  OWNER TO "racer";
 
Теперь можно создавать View с группировкой использования лицензий:
CREATE VIEW "public"."view_licenses" AS
SELECT
    s.datetime
  , » :: TEXT                  AS user_name
  , UPPER (( h.NAME ) :: TEXT ) AS user_host
  , » :: TEXT                  AS appid
  , l.NAME                      AS license_series
  , s.license_issued_by_server  AS license_issued_by_server
  , s.license_net               AS license_net
  , l.TYPE                      AS license_type
  , »                          AS license_rmngr                —у клиентских не будет RMNGR
  , l.MAX                       AS license_max
  , COUNT ( * )                 AS seanses_count                —сеансов на эту лицензию
FROM
    sessions    s
LEFT JOIN hosts       h         ON s.host_by_id        = h.ID
LEFT JOIN licenses_db l         ON s.license_by_id     = l.ID
LEFT JOIN users       u         ON s."user-name_by_id" = u.ID
WHERE
    (s.license_issued_by_server = FALSE)                        —только лицензии, не выданные сервером
    AND
    (s.host_by_id in (select id from view_not_terminal_ids))    —и не с терминальных серверов
GROUP BY                                                        —группируем по
    s.datetime
  , ( UPPER (( h.NAME ) :: TEXT ))                              —имени хоста
  , l.NAME                                                      —серии лицензии
  , s.license_issued_by_server                                  —признаку выдачи сервером
  , s.license_net                                               —является ли лицензия сетевой
  , l.TYPE                                                      —типу — приграммная/аппаратная
  , l.MAX                                                       —размеру ключа
 
UNION ALL
SELECT
    s.datetime
  , UPPER (( u.NAME ) :: TEXT ) AS user_name
  , UPPER (( h.NAME ) :: TEXT ) AS user_host
  , » :: TEXT                  AS appid
  , l.NAME                      AS license_series
  , s.license_issued_by_server  AS license_issued_by_server
  , s.license_net               AS license_net
  , l.TYPE                      AS license_type
  , »                          AS license_rmngr                —у клиентских не будет RMNGR
  , l.MAX                       AS license_max
  , COUNT ( * )                 AS seanses_count                —сеансов на эту лицензию
FROM
    sessions    s
LEFT JOIN hosts       h         ON s.host_by_id        = h.ID
LEFT JOIN licenses_db l         ON s.license_by_id     = l.ID
LEFT JOIN users       u         ON s."user-name_by_id" = u.ID
WHERE
    (s.license_issued_by_server = FALSE)                        —только лицензии, не выданные сервером
    AND
    (s.host_by_id in (select id from view_terminal_ids))        —с терминальных серверов
GROUP BY
    s.datetime
  , ( UPPER (( u.NAME ) :: TEXT ))                              —добавляем группировку по имени пользователя
  , ( UPPER (( h.NAME ) :: TEXT ))                              —имени хоста
  , l.NAME                                                      —серии лицензии
  , s.license_issued_by_server                                  —признаку выдачи сервером
  , s.license_net                                               —является ли лицензия сетевой
  , l.TYPE                                                      —типу — приграммная/аппаратная    
  , l.MAX                                                       —размеру ключа
 
UNION ALL
SELECT
    s.datetime
  , UPPER (( u.NAME ) :: TEXT ) AS user_name
  , UPPER (( h.NAME ) :: TEXT ) AS user_host
  , A.NAME                      AS appid
  , l.NAME                      AS license_series
  , s.license_issued_by_server  AS license_issued_by_server
  , s.license_net               AS license_net
  , l.TYPE                      AS license_type
  , UPPER (( h2.NAME ) :: TEXT )AS license_rmngr                —а здесь RMNGR будет
  , l.MAX                       AS license_max
  , ‘1’ :: BIGINT               AS seanses_count                —сеансов на эту лицензию
FROM
    sessions    s
LEFT JOIN hosts       h         ON s.host_by_id        = h.ID
LEFT JOIN licenses_db l         ON s.license_by_id     = l.ID
LEFT JOIN users       u         ON s."user-name_by_id" = u.ID
LEFT JOIN apps        a         ON s."app-id_by_id"    = A.ID
LEFT JOIN hosts       h2        ON s.rmngr_by_id       = h2.ID    
WHERE
    s.license_issued_by_server = TRUE                           —все лицензии выданные сервером не группируются
;
ALTER TABLE "public"."view_licenses"
  OWNER TO "racer";
 
Подготовка хранилища данных завершена.
 
 
Собираем данные
 
Сначала о командах, используемых для получения информации:
  • /opt/1C/v8.3/x86_64/rac cluster list                                                              ИМЯ_СЕРВЕРА:1545   #так мы будем получать список кластеров из сервера RAS
  • /opt/1C/v8.3/x86_64/rac infobase summary list —cluster=GUID_Кластера ИМЯ_СЕРВЕРА:1545   #здесь мы, используя GUID кластера из первой команды, получим список баз
  • /opt/1C/v8.3/x86_64/rac process list                  —cluster=GUID_Кластера ИМЯ_СЕРВЕРА:1545   #а так мы получим информацию о списке рабочих процессов
  • /opt/1C/v8.3/x86_64/rac session list                  —cluster=GUID_Кластера ИМЯ_СЕРВЕРА:1545    #с помощью этой команды можно получить список сеансов, но здесь есть не вся информация о лицензии
  • /opt/1C/v8.3/x86_64/rac session list —licenses  —cluster=GUID_Кластера ИМЯ_СЕРВЕРА:1545   #а тут мы получаем недостающую информацию о лицензиях
 
Общий порядок работы скрипта такой:
  1. Получаем список кластеров сервера RAS из таблицы ras_servers в базе Postre
  2. Получаем список информационных баз кластера
  3. Получаем список процессов кластера
  4. Получаем список сеансов и их лицензий
  5. Сводим все данные и заносим в целевую таблицу
 
Проверим, что у нас установлен Python 3.6
yum list installed | grep python36
 
Если его нет, то нужно его поставить:
yum install -y https://centos7.iuscommunity.org/ius-release.rpm
yum install -y python36u python36u-devel python36u-pip
 
И, в любом случае, нужно поставить два используемых модуля Python:
pip3.6 install psycopg2
pip3.6 install pytz
 
После этого нужно настроить скрипт сбора данных (см. раздел загружаемых файлов) — отредактировать его и поменять параметры подключения к Postre.
postgre_host                     = "localhost"
postgre_port                     = "5432"
postgre_database                 = "racerDB"
postgre_database_user            = "racer"
postgre_database_user_password   = "password"
 
И проверить корректность всех настроек, запустив его сразу из консоли:
/usr/bin/python3.6 /root/pyrac1c.py
 
Если до этого всё сделано правильно, то можно его в планировщик:
crontab -l | { while IFS= read -ra tasks; do printf ‘%s
‘ "$tasks"; done; echo ‘*/10 * * * * /usr/bin/python3.6 /root/pyrac1c.py > /dev/null 2>&1’;} | crontab #добавляем к списку заданий /usr/bin/python3.6 /root/pyrac1c.py для запуска через каждые 10 минут
 
 
У нас уже начали собираться данные, самое время отправиться в Grafana и настроить графики.
 
Сначала нужно добавить новый DataSource с типом PostgreSQL и данными для подключения к нашему серверу с данными:
 
После этого можно смело создавать новый Dashboard и добавлять на него первый Graph
 
Выбираете свой Datasource на вкладке Metrics и можно редактировать тексты запросов.
 
В качестве первого запроса агрегируем информацию об утилизации лицензий:
—всего утилизировано лицензий
SELECT
  $__timeGroup(DATETIME, ’10m’,0) as "time",
  —DATETIME,
  COUNT(*) AS "Утилизировано лиц. всего."
FROM view_licenses l
GROUP BY l.datetime
ORDER BY l.datetime asc
 
Сделаем отдельный график для лицензий, утилизированный сервером и клиентом :
—утилизировано серверных и клиентских
SELECT  
    $__timeGroup(l.datetime, ’10m’,0),
    —l.datetime,
    CASE
        WHEN l.license_issued_by_server=true THEN ‘Утилизировано серверных’
        WHEN l.license_issued_by_server=false THEN ‘Утилизировано клиентских’
    END,
    COUNT(*)
FROM view_licenses l
GROUP BY l.datetime,l.license_issued_by_server
ORDER BY l.datetime asc
 
Узнаем, сколько же всего у нас сеансов с лицензий:
—сеансы с лицензией
SELECT
    $__timeGroup(s.datetime,10m,0),
    —s.datetime,
    COUNT(*) as "Сеансов с лицензией"
FROM
    sessions s
WHERE s.license_by_id is not null
GROUP BY s.datetime
ORDER BY s.datetime
 
И сколько из них получило лицензию на сервере или на клиенте:
—сеансы с программными или аппаратными лицензиями
SELECT  
    $__timeGroup(s.datetime, ’10m’,0),
    —s.datetime,
    CASE
        WHEN s.license_issued_by_server=true THEN ‘Сеансов с лицензией от сервера’
        WHEN s.license_issued_by_server=false THEN ‘Сеансов с лицензий от клиента’
    END,
    COUNT(*)
FROM sessions s
WHERE s.license_issued_by_server is not null and s.license_by_id is not null
GROUP BY s.datetime,s.license_issued_by_server
ORDER BY s.datetime asc
 
Отдельный график можно сделать и по сеансам с программными и аппаратными лицензиями:
—Сеансы программных и аппаратных лицензий
SELECT  
  $__timeGroup(DATETIME, ’10m’,0),
  —s.DATETIME,
  ‘Сеансов с лицензией ‘||l.type,
  COUNT(*)
FROM
  sessions s, licenses_db l
where l.id = s.license_by_id
GROUP BY s.datetime,l.type
ORDER BY s.datetime asc
 
И посмотреть утилизацию ключей по типам (обратите внимание, что многопользовательские ключи на 20, 50 и 100 лицензий обладают одинаковым идентификатором — ORGL8. А ещё для клиентских лицензий мы не может узнать какой HASP LM их выдал, поэтому они агрегируются сразу по всем ключам одного типа и значение для графика таких ключей может быть больше ёмкости одного ключа):
—утилизацию по типам ключей
SELECT
    $__timeGroup(l.datetime,10m, 0) AS "time"
    —l.datetime as datetime
        ,case
            when l.license_issued_by_server then
                    ‘server ‘||l.license_type||’-‘||l.license_series||'(‘||l.license_max||’) by ‘|| l.license_rmngr
            else
                    ‘client ‘||l.license_type||’-‘||l.license_series||'(‘||l.license_max||’)’
    end AS license_data
        ,count(*)
FROM view_licenses l
GROUP BY l.datetime,license_data
ORDER BY l.datetime,license_data asc
 
Напоследок, можем посмотреть и сколько у нас спящих сеансов:
—спящие сеансы
SELECT
    $__timeGroup(s.datetime,10m,0),
    —s.datetime,
    COUNT(*) as "Спящие сеансы"
FROM
    sessions s
WHERE s.hibernate = TRUE
GROUP BY s.datetime
ORDER BY s.datetime
 
На выходе получаются вот такие прекрасные графики.
 
 
 
 
 
 

15 Comments

  1. asved.ru

    Весь процесс сбора данных есть в ЦКК. Немного его допиливаем, а логику аггрегации лицензий выносим в отчет. Или в алгоритм заполнения мониторинговой БД, если используется сторонняя система мониторинга. В частности, я шлю в Zabbix посредством ВК, реализующей Zabbix sender.

    Reply
  2. Mortum

    Хороший, навороченный, но сложный велосипед.

    Reply
  3. tvm

    (1) а зачем через ВК в Zabbix слать? Он может сам дергать агента и получать инфу

    Reply
  4. MrWonder

    (2) Спасибо за оценку. Я поэтому и описал подробно, чтобы самому всё уложить в голове )))

    Reply
  5. capitan

    Может это и велосипед, не знаю.

    Но велосипед боевой )

    Как совет — по хорошему надо просто серверам ограничить доступ к аппаратным лицензиям.

    Уберете путаницу и количество свободных лицензий увеличите

    Reply
  6. asved.ru

    (3) Так экономнее: агент сам по себе в 1С ходить не умеет, типовое решение — агент читает stdout дочернего процесса. Который еще нужно запустить, потратив на это системные ресурсы.

    Reply
  7. tvm

    (6) если агентом дергать rac- не сильно то и затратнее

    Reply
  8. bforce

    У в качестве центра мониторинга — Zabbix. Он сразу избавляет вас от 2,4,5 пукнта. Плюс есть агент, который сам отправляет данные серверу.

    Мониторинг «железных» лицензий прямо на хосте, где они установлены. Так честнее и проще.

    Ну и графана для красоты (sql-запросы пилить не надо, так как есть интеграция с заббиксом, — достаточно выбрать показатель/item).

    Reply
  9. MrWonder

    (8) Мониторинг железных ключей — это хорошо. Но он работает у Вас только под Win.

    И ещё — если выдаёте железные ключи сервером, то вы не знаете, сколько их выдано. Ибо эти данные не получить из ключа, увы.

    Буду рад, если опровергните меня по любому из пунктов.

    В конце хочу добавить, что данный мониторинг не ограничивается только лишь ключами 😉

    О разнообразии применений собираемых данных, по мере накопления UseCases, напишу ещё одну статью.

    Reply
  10. bforce

    (9)

    И ещё — если выдаёте железные ключи сервером, то вы не знаете, сколько их выдано. Ибо эти данные не получить из ключа, увы.

    Буду рад, если опровергните меня по любому из пунктов.

    Здесь у многих заблуждение. Да, в списке сессий будет видна только одна запись самого сервера 1С, но ключ же как-то понимает сколько ключей он раздал. Эта цифра (без детализации по хостам) видна и в аладдиновском мониторе, и может быть получена программно, используя dll-ку.

    Но он работает у Вас только под Win.

    Кросплатформенность сейчас, конечно, в моде, но не настолько, чтобы фанатично первым делом переходить на линукс. Впрочем, это Ваши предпочтения и требования.

    Я за более взвешенный подход: использовать то, что лучше и удобнее для каждой конкретной задачи. Возможно, у Вас так, но из статьи этого не видно.

    В конце хочу добавить, что данный мониторинг не ограничивается только лишь ключами 😉

    Аналогично.

    Reply
  11. MrWonder

    (10)

    Здесь у многих заблуждение. Да, в списке сессий будет видна только одна запись самого сервера 1С, но ключ же как-то понимает сколько ключей он раздал. Эта цифра (без детализации по хостам) видна и в аладдиновском мониторе, и может быть получена программно, используя dll-ку.

    Либо я чего-то не знаю, либо Вы.

    Я утверждаю (и мои слова подкреплены ответом из 1С) о том, что получить количество утилизированных СП 1С лицензий из аппаратного ключа средствами, в первую очередь, Alladdin Monitor, нельзя.

    Можете показать как вы получаете количество выданных СП 1С лицензий из многопользовательского ключа HASP?

    По поводу остальных выводов и заключений:

    1. Для меня перспектива — кроссплатформенность. Делать сейчас одно, а потом переделывать в другое можно. Но это не мой выбор.

    2. Расскажите о том, как сделано у Вас. Мне очень интересно.

    Reply
  12. bforce

    (11)

    Я утверждаю (и мои слова подкреплены ответом из 1С) о том, что получить количество утилизированных СП 1С лицензий из аппаратного ключа средствами, в первую очередь, Alladdin Monitor, нельзя.

    Конечно, оно так. Но нужно помнить один нюанс. Занятые лицензии не увидеть, если Ваш ключ воткнут непосредственно в сервер 1С. Тогда получение лицензии идет мимо службы HASP.

    А, вот, если для ключа выделить отдельную машину (мы, например, по серверам СУБД распихали), то правильное количество лицензий начнет показывать даже Alladdin Monitor. Собственно, так используем и мониторим.

    (11)

    2. Расскажите о том, как сделано у Вас. Мне очень интересно.

    Так я уже написал в первом посте. Zabbix используются для мониторинга железа, операционной системы, а мы туда еще простенькими PowerShell коммандлетами пропихиваем свои метрики бизнес-приложения.

    Я тут америку не открыл и рекламировать это смысла не вижу. Это все равно что запилить статью, например, о том как здорово я установил платформу на 50+ пользовательских компьютеров при помощи простеньких команд.

    Свои собственный решения хороши тем, что в них у Вас полная уверенность. Но передать другому специалисту их нельзя. Он их выбросит и напишет свои скрипты. На Заббикс в данном случае нужно смотреть как на универсальный и мощный инструмент, своего рода Платформа, которая уже из коробки может очень многое. Плюс всегда есть Агент, который сам выполнит скрипт и будет сообщать об ошибках. А если машина ушла в небытие, то о недоступности Агента сообщит уже Сервер. И, если не прикручивать к нему для красоты Графану, то одного Заббикса будет уже достаточно.

    Reply
  13. MrWonder

    (12)

    Конечно, оно так. Но нужно помнить один нюанс. Занятые лицензии не увидеть, если Ваш ключ воткнут непосредственно в сервер 1С. Тогда получение лицензии идет мимо службы HASP.

    А, вот, если для ключа выделить отдельную машину (мы, например, по серверам СУБД распихали), то правильное количество лицензий начнет показывать даже Alladdin Monitor. Собственно, так используем и мониторим.

    Я знаю о трёх способах выдачи лицензий сервером приложений 1С:

    1. Выдачи из ключа под сервером. Этот способ используется всегда первым. Есть ли служба nethasp, нет ли её, СП 1С всегда начинает выдавать лицензии из ключа под собой.

    2. Программные лицензии. Здесь всё просто и очевидно. Нечего и добавить.

    3. Лицензии из сетевого ключа (прописанного в nethasp.ini). И вот здесь, увы, Alladdin Monitor бессилен. Он показывает корректно только лицензии, полученные клиентом. А лицензии, выданные СП 1С он не покажет верно. Можете проверить. Это так. И 1С это подтверждает.

    А если машина ушла в небытие, то о недоступности Агента сообщит уже Сервер. И, если не прикручивать к нему для красоты Графану, то одного Заббикса будет уже достаточно.

    Zabbix я тоже использую. Но не для метрик работы 2000 сеансов. Это чрезвычайно избыточно — хранить все эти данные в Zabbix. Совершенство в многообразии.

    Reply
  14. bforce

    (13)

    Можете проверить. Это так. И 1С это подтверждает.

    Все уже проверено до Вас. Просто Вы неверно поняли то, что написала 1С и корректировать свою точку зрения не хотите.

    Reply
  15. MrWonder

    (14) То, что Вы видите соединения от сервера в ключе, не значит, что Вы видите количество утилизированных ключей ))

    И да, я действительно не хочу корректировать свою точку зрения. Просто потому, что я проверял внимательней — сравнивал количество записей в Alladdin Monitor с количеством лицензий, утилизированных в консоли администрирования.

    Мдаа, а ещё с Вашей стороны в высшей степени неразумно делать выводы о понимании мною письма, содержимого которого Вы даже не знаете. Ну что ж, давайте посмотрим вместе:



    Если захотите проверить нормально, а не на отъ…сь, то пишите, если посчитаете нужным.

    Удачи с математикой 😉

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *