Отдельный пул запросов
Glossary Item Box
Общие сведения
Некоторые тяжелые запросы к базе данных (БД) могут нагружать ресурсы сервера БД на 100% в течение продолжительного времени и тем самым затруднять или сделать невозможной работу других пользователей. Среди таких запросов можно выделить:
- Неоптимально составленные запросы в динамических группах, блоках итогов.
- Сложные аналитические выборки в блоках итогов.
Очевидно, что для решения проблемы необходимо ограничить ресурсы выделяемые сервером БД на обработку таких Select-запросов, — вынести их в отдельный пул. Это позволит уменьшить их влияние на работу других пользователей и частей системы.
В отдельный пул можно направлять только запросы Select и только если они не являются частью транзакции.
Реализация отдельного пула запросов
MS SQL Server позволяет ограничивать выделяемые ресурсы с помощью встроенного инструмента — Resource Governor. Однако, его возможности по ранжированию базируются на информации о подключении, а не о конкретном запросе. Поскольку приложение Creatio для любых запросов использовало подключения из единственного пула, все подключения были одинаковыми и не пригодными для ранжирования.
Чтобы разделить легкие и потенциально тяжелые запросы была добавлена возможность отправлять запросы через специальное соединение, в котором к свойству App (или Application Name) строки соединения дописывается суффикс "_Limited".
Например, если в ConnectionStrings.config указать в строке соединения свойство “App = сreatio”, то в соединении для отдельного пула запросов оно будет заменено на “сreatio_Limited”. Если в ConnectionStrings.config не указано свойство App (или Application Name), то для общего соединения устанавливается значение по умолчанию: “.Net SqlClient DataProvider”, а в соединении для отдельного пула запросов — “.Net SqlClient DataProvider_Limited”.
Пример настройки строки соединения с пользовательским свойством App:
<add name="db" connectionString="App=сreatio; Data Source=dbserver\mssql2016; Initial Catalog=BpmonlineSolution; Persist Security Info=True; MultipleActiveResultSets=True; Integrated Security=SSPI; Pooling = true; Max Pool Size = 100; Async = true; Connection Timeout=500" />
Таким образом, при загрузке дашбордов или фильтрации разделов с помощью динамических групп приложение создает дополнительные соединения с базой данных, отличающиеся от основных суффиксом "_Limited".
Разделение пулов позволит администраторам баз данных регулировать выделение ресурсов запросам из маркированного соединения.
Никакого ограничения ресурсов при этом не происходит. Приложение лишь предоставляет возможность воспользоваться такой пометкой для ранжировании соединений средствами Resource Governor. Нужно отметить, что работу Resource Governor сложно увидеть на незагруженном сервере и на "коротких" запросах. Эффект от его работы наблюдается, когда сервер БД загружен на 100%, а "тяжелый" запрос выполняется продолжительное время.
Включение функциональности отдельного пула запросов
Для включения функциональности необходимо в файле .\Terrasoft.WebApp\Web.config приложения установить значение true для настройки UseQueryKinds:
<add key="UseQueryKinds" value="true" />
Эта настройка обеспечивает отправку запросов из дашбордов и динамических групп в соединения, помеченные суффиксом "_Limited".
Пример настройки Resource Governor
Настройка групп и пула выполняется с помощью SQL-скрипта. Например:
ALTER RESOURCE POOL poolLimited WITH ( MAX_CPU_PERCENT = 20, MIN_CPU_PERCENT = 0 -- REQUEST_MAX_MEMORY_GRANT_PERCENT = value -- REQUEST_MAX_CPU_TIME_SEC = value -- REQUEST_MEMORY_GRANT_TIMEOUT_SEC = value -- MAX_DOP = value -- GROUP_MAX_REQUESTS = value ); GO --- Create a workload group for off-hours processing --- and configure the relative importance. CREATE WORKLOAD GROUP groupLimited WITH ( IMPORTANCE = LOW ) USING poolLimited GO ALTER RESOURCE GOVERNOR RECONFIGURE; GO
Более детально о настройках можно узнать из документации по Resource Governor.
Для каждого нового соединения выполняется функция классификатор, возвращающая название группы. Например:
USE [master] GO ALTER FUNCTION [dbo].[fnProtoClassifier]() RETURNS sysname WITH SCHEMABINDING AS BEGIN IF(app_name() like '%_Limited') BEGIN RETURN N'groupLimited' END RETURN N'default' END;
Пример использования
Чтобы выполнить запрос в отдельном пуле запросов, для него нужно получить специальный DBExecutor, передав в качестве дополнительного параметра значение Limited из перечисления QueryKind. Подробнее о DBExecutor можно узнать из статьи "Многопоточность при работе базой данных". В примере ниже QueryKind — это аргумент метода EnsureDBConnection(), значение которого приходит в клиентском EntitySchemaQuery-запросе (ESQ-запросе), и устанавливается в серверный ESQ-запрос и далее в запрос Select.
using (DBExecutor executor = userConnection.EnsureDBConnection(QueryKind)) { // ... };
Вызов EnsureDBConnection(QueryKind.General) эквивалентен вызову EnsureDBConnection() без указания QueryKind.
Таким образом, если в клиентской части приложения при создании экземпляра класса Terrasoft.EntitySchemaQuery установить признак QueryKind.Limited, то это значение будет передано на сервер и запросу будет обеспечен специальный DBExecutor, использующих маркированное соединение с БД.
Пример установки признака QueryKind.Limited клиентскому ESQ-запросу в схеме ChartModule:
... getChartDataESQ: function() { return this.Ext.create("Terrasoft.EntitySchemaQuery", { rootSchema: this.entitySchema, queryKind: Terrasoft.QueryKind.LIMITED }); }, ...
Если в программном коде присутствуют вложенные вызовы userConnection.EnsureDBConnection(QueryKind), следует убедиться, что на всех уровнях вложенности используется одно и то же значение QueryKind.