Постановка задачи: получать данные о заказах из базы данных 1С: Предприятие в формате JSON для отображения на сайте. Запросы должны обрабатываться максимально быстро, по возможности, не мешать работе пользователей в базе.
Задача, конечно, надуманная, но хорошо отражает целый класс задач из реального мира – обслуживание большого количества мелких запросов на чтение данных. Обработка с максимальной скоростью, потому что никто не любит, когда сайт тормозит. И поисковые роботы тоже. Они за такое могут понизить сайт в выдаче результатов. При этом локальные пользователи тоже должны как-то работать в базе, проводить документы, формировать отчёты.
Про прямой доступ к данным на сервере SQL написано много. Но практических результатов замеров никто не приводит. Попробуем собрать испытательный стенд и померять.
Хост (он же будет выступать клиентом):
Intel(R) Core(TM) i7-7500U CPU @ 2.90 GHz, RAM 16 ГБ
Windows 11 Pro 22H2
Apache JMeter 5.6.3
Oracle VM VirtualBox 7.0.14
Виртуальная машина (сервер):
2 процессора, 6 ГБ оперативной памяти
Windows Server 2022 Standard 21H2
SQL Server 2022
Платформа 1С, 8.3.24.1467
1С: Управление Торговлей, 11.5.16.97
Kraxe 0.3.3
Рассмотрим 2 варианта решения – использование встроенных в платформу HTTP-сервисов с публикацией на IIS и прямое чтение данных из SQL. Первый вариант реализуем как расширение для конфигурации. Для второго используем Кракен – веб-сервер для MS SQL.
Расширение для конфигурации
Сначала подготовим небольшое расширение конфигурации 1С, в котором реализован HTTP-сервис. Сервис получает в качестве параметра номер заказа. По номеру находит документ и возвращает этот номер с датой и статусом. В запросе учтём, что в базе могут быть заказы с одинаковым номером. Для простоты будем возвращать данные самого позднего из заказов.
Расширение для конфигурации 1С
Конфигурацию публикуем на IIS с настройками по умолчанию. Важный момент для анализа производительности - отладка на сервере 1C отключена.
В демонстрационной базе из комплекта поставки есть полсотни документов «Заказ клиента». В большинстве из них поля НомерПоДаннымКлиента и ДатаПоДаннымКлеинта пустые. Заполним номер значениями от 01 до 58, а дату – датой документа. В процессе теста будем запрашивать не один документ, а произвольный из этого диапазона.
Открываем из браузера на клиенте адрес публикации:http://192.168.100.10/trade_11/hs/dds/order?Id=33
Всё в порядке, данные сервис отдаёт. Теперь можно настраивать второй вариант – прямые запросы в SQL.
Настройка Кракена
Бесплатная версия Кракена имеет некоторые ограничения – не более 100 строк в результате запроса, но для тестов и многих реальных задач вполне годится. Качаем, распаковываем, устанавливаем как службу:
c:\kraxe>kraxe.exe -install
Настройки сервера хранятся в файле kraxe.conf. Открываем его и внесём некоторые изменения.
kraxe.conf
Сначала в разделе http_server
нужно указать IP-адрес и порт, на которых сервер будет принимать входящие запросы. Порт, чтобы не мешать IIS с опубликованной 1С, укажем 8080. По умолчанию, этот порт закрыт файрволом. Запускаем firewall.cpl, добавляем правило, разрешающее входящие запросы по этому порту.
В том же файле формируется список пользователей сервиса. Удалим запись, разрешающую анонимную аутентификацию. Оставим одну запись для пользователя Admin.
В разделе sql_server
зададим параметры подключения к SQL Server. Кракен подключается к SQL Server по протоколу TCP. Убедимся, что этот протокол включен в настройках SQL сервера.
SQL Server Configuration Manager
Вернемся к настройкам Кракена. Имя БД, логин, пароль – тут всё очевидно.
Параметр pool_size
– максимальное количество одновременных подключений к SQL серверу, которые может открыть и поддерживать Кракен. Забегая вперед, отмечу, что увеличение этого параметра в моём тесте никак не повлияло на скорость обработки запросов. Вероятно, если запросы будут сложнее и скорость их обработки на стороне SQL будет меньше, тогда понадобится несколько подключений, чтобы уменьшить очередь.
Параметр date_offset
– специфичное для баз данных 1С смещение дат. Подробности можно почитать здесь. Суть в том, что 1С при записи дат может к ним добавлять 2000 лет. Это нужно учитывать при чтении данных напрямую из БД.
В разделе bindings
опишем только один ресурс – “/order”. Этот ресурс будет связан с файлом ./queries/order.sql. У запроса будет один параметр с типом число (I16) и значением по умолчанию равным 0. При обращении к ресурсу /order?Id=33
, в SQL запросе будет установлено значение переменной @ID = 33
.
Раздел parameters
из файла настроек удалим. Он нам пока не понадобится.
Теперь нужен файл с запросом, который получает данные заказа клиента по его номеру. Запустим SQL Server Profiler. Выполняем запрос из браузера к HTTP-сервису, который настроили ранее и найдём похожий на наш запрос:
exec sp_executesql N'SELECT TOP 1
T1._Fld10563,
T1._Fld10564,
T1._Fld10547RRef,
T1._IDRRef
FROM dbo._Document1092 T1
WHERE ((T1._Fld3035 = @P1)) AND ((T1._Fld10563 = @P2))
ORDER BY (T1._IDRRef) DESC',N'@P1 numeric(10),@P2 nvarchar(4000)',0,N'33'
Чтобы сопоставить имена таблиц из запроса с данными 1С: Предприятия нужно получить структуру хранения данных в БД. Готовых обработок для 1С много. Например, «Структура хранения данных».
Действительно, таблица _Document1092 – это документы Заказ клиента. Поле _Fld10563 – НомерПоДаннымКлиента, _Fld10564 – ДатаПоДаннымКлиента, _Fld10547RRef – Статус, а _Fld3035 – ОбластьДанныхОсновныеДанные.
Перепишем запрос. Разделение данных по областям у нас не используется, поэтому одно условие из запроса можно исключить. Если для документов, которые выбираются запросом в 1С включено версионирование, тогда в запросе необходимо учитывать поле _Version. Там будет timestamp, по которому можно отсортировать версии одного документа. В нашем случае это тоже не актуально.
Перечисления в БД 1С хранятся особым образом (подробнее об этом написано здесь). Для сопоставления идентификаторов перечислений с их представлениями необходимо выгрузить конфигурацию в xml файлы (из конфигуратора).
Открываем файл ..\Enums\СтатусыЗаказовКлиентов.xml
СтатусыЗаказовКлиентов.xml
Внимательнее! Идентификаторы в выгрузке имеют другой порядок байтов.
Теперь можем написать запрос и сохранить его в файл ./queries/order.sql
SELECT TOP 1
T1._Fld10563 as Id,
T1._Fld10564 as Date,
CASE T1._Fld10547RRef
WHEN 0xa1675473ecec326649b4b85516d451ca THEN 'НеСогласован'
WHEN 0xb58f438fd9fb9fcb4711d9e217f46797 THEN 'КОбеспечению'
WHEN 0xb2d15805b9177e7845e991dfb027cbd4 THEN 'КОтгрузке'
WHEN 0xb0e8c70f8e9e2b96440ba5356e7c22c2 THEN 'Закрыт'
END as Status
FROM dbo._Document1092 as T1
WHERE T1._Fld10563 = @ID
ORDER BY T1._IDRRef DESC
Адрес второго сервиса для тестирования прямых запросов получился такой:http://192.168.100.10:8080/order?Id=33
Запускаем службу Kraxe и переходим к тестам.
Тестирование производительности
Для тестирования на клиенте настроил Apache JMeter: 100 потоков запускаются в течении 100 секунд и каждый из них отправляет 10 запросов.
Thread Group
Каждый запрос случайным образом выбирает номер заказа от 1 до 58 и подставляет в URL.
Random Variable
Для каждого сервиса выполним по 5 циклов. Для анализа самыми важными будут 3 показателя: среднее время обработки запроса, медианное время, отклонение от среднего времени (разброс значений).
Результаты:
|
Среднее время, мс |
Медианное время, мс |
Отклонение, мс |
1С: Предприятие + IIS | |||
1 |
38 |
28 |
138 |
2 |
27 |
26 |
7 |
3 |
25 |
25 |
6 |
4 |
41 |
40 |
16 |
5 |
40 |
39 |
16 |
|
34.2 |
31.6 |
36.6 |
SQL + Kraxe | |||
1 |
12 |
11 |
8 |
2 |
19 |
15 |
14 |
3 |
11 |
10 |
8 |
4 |
11 |
10 |
5 |
5 |
16 |
11 |
18 |
|
13.8 |
11.4 |
10.6 |
Выводы
Тест без сомнений синтетический. Никак не учтена параллельная работа пользователей в БД, разные профили нагрузки для разных баз. Ну, разве что фоновые задания остались включенными на сервере 1С. Но в целом, порядок цифр и тенденция очевидны. Использование прямых запросов позволяет увеличить скорость получения данных из базы данных в 2-3 раза, повысить отзывчивость сайта.
Отмечу серьёзные недостатки прямого получения данных:
Сложность разработки. Встроенный в платформу HTTP-сервис пишется за полчаса и помещается целиком на один экран. Для подготовки текста SQL запроса нужно выяснить структуру таблиц БД, хорошо понимать особенности хранения данных (например, перечисления). Полученное решение прибито гвоздями к конкретной БД, потому что имена таблиц для аналогичной конфигурации в другой БД будут отличаться.
Сложность поддержания решения в рабочем состоянии. В процессе доработки и обновления конфигурации имена таблиц и полей в таблицах могут изменяться. Это нужно учитывать и отслеживать.
Фирма 1С считает прямой доступ к БД нарушением лицензионного соглашения.
Решение по использованию прямых запросов к БД должно приниматься с учётом этих недостатков. Если можно обойтись штатными средствами – делайте средствами платформы.
Комментарии (5)
mixsture
28.04.2024 17:30+2Отмечу серьёзные недостатки прямого получения данных:
вы забыли еще про блокировки, которые существуют в пространстве сервера приложений. Вы их обходите, а значит получаете грязное чтение.
Зачем вам в запросе упорядочивание? Думаю, оно не несет никакой нагрузки и его можно убрать.Обработка с максимальной скоростью, потому что никто не любит, когда сайт тормозит.
Если вы заботитесь о скорости, то лучше архитектура доставляющая изменения, чем спрашивать много-много раз (исключения могут быть). Чем ближе будут лежать данные к клиенту, тем обычно быстрее их получается доставить, поэтому считаю лучше хранить актуальную копию данных на сайте, поддерживать ее актуальность доставкой изменений.
Kuzmin_R Автор
28.04.2024 17:30+1Упорядочивание нужно для того, чтобы получить последний документ с указанным в отборе номером. В БД может быть несколько документов с одинаковым номером, например, за разные годы.
С доставкой изменений полностью согласен - это гораздо лучшее решение. Рассмотренная ситуация - это только упрощённый пример. Суть исследования в том, чтобы понять, насколько прямой доступ даст ускорение.
Грязное чтение возможно, но оно далеко не всегда будет проблемой.
mixsture
28.04.2024 17:30Упорядочивание нужно для того, чтобы получить последний документ с указанным в отборе номером. В БД может быть несколько документов с одинаковым номером, например, за разные годы.
Тогда бы было упорядочивание по дате, а у вас по idref (16 байтный UUID) - полагаться на него, что он будет выдавать возрастающие строки с течением времени нельзя (а еще направление сотировки - обратное - убывание desc). Я бы в принципе выкинул отсюда упорядочивание как довольно затратную процедуру, ограничившись диапазоном дат (вроде "полгода назад максимум").
anonymous
НЛО прилетело и опубликовало эту надпись здесь
vis_inet
В каком смысле?
Уже вышло - автор протестировал то, что хотел.