Введение
Одно из требований к специалистам на экзамене «1С:Эксперт по технологическим вопросам». (http://1c.ru/rus/partners/training/expert.htm) — владение методиками и технологиями нагрузочного тестирования систем на платформе «1С:Предприятие 8». Изучим доклад Виктора Богачева о нагрузочном тестировании ООО «Деловые Линии» (Infostart Event 2014).
Здесь краткий конспект.
Попробуем на тестовой базе повторить избранные места доклада:
Ситуация 1. При увеличении числа запросов к базе до 3-4 тысячи в секунду стали наблюдаться pagelatch из-за создания/удаления временных таблиц и индексов
Ситуация 2. При завершении сессий возникает нагрузка на сервер СУБД из-за уничтожения временных таблиц
Оборудование и ПО
Платформа 8.3.12, без совместимости. Управляемый режим блокировок. Сервер приложений – отдельно, 1С:Предприятие запущено на сервере СУБД (MS SQL 2012). Жесткий диск – SSD. В приложении к статье – база данных с обработкой нагрузочного тестирования. Кто захочет – cможет повторить все примеры.
Ситуация 1
Для создания нагрузки, будем запускать несколько потоков, запрос в цикле, например
Запрос1.Текст = "ВЫБРАТЬ
| ""флаг запроса"" КАК Поле2
|ПОМЕСТИТЬ Таб1
|
|ИНДЕКСИРОВАТЬ ПО
| Поле2
|;
|
|////////////////////////////////////////////////////////////////////////////////
|УНИЧТОЖИТЬ Таб1";
Запрос2 – то же без создания временной таблицы и без индексирования, Запрос3 – с созданием временной таблицы, но без создания индекса. Более подробно – смотрите обработку в приложенной базе данных 1С.
Объем доступной памяти не контролируем. Почти отсутствует нагрузка на жесткий диск: задержки возникают из-за того, что разные потоки не могут параллельно писать в одну страницу жесткого диска (памяти). Ниже характерное состояние дисковой системы во время теста.
Количество запросов, latch проверяем с помощью монитора производительности: Мой компьютер — Управление – Производительность — SQL Server, Latches Object. Как и рекомендуют в документации.
Варианты и результаты теста:
- Процедура «ПодключитьОбработчикОжидания». (Запрос1)
- Фоновые задания, ни временная таблица, ни индекс НЕ создаются. (Запрос2)
- Фоновые задания, индекс временной таблицы НЕ создается. (Запрос3)
- Фоновые задания, создается индекс временной таблицы. (Запрос1)
- При подключении обработчика ожидания несколько раз мне не удалось получить больше 1,6 тысяч запросов в секунду. Скорее всего, ПодключитьОбработчикОжидания, не обеспечивает параллельной работы: клиент «подвисает». О том же указано и в описании: …Подключает вызов указанной процедуры модуля управляемого приложения (модуля обычного приложения) или глобального общего модуля через определенный интервал времени. Вызов будет осуществляться только в "состоянии покоя", то есть в тот момент, когда программа не выполняет никаких действий… Поэтому метод «ПодключитьОбработчикОжидания» для нагрузочного тестирования использовать не будем.
- Если в тексте запроса не создавать ни временных таблиц, ни индексов к ним — ожиданий latch не возникает.
- Из-за создания большого числа временных таблиц, появились ожидания latch.
- В случае создания временных таблиц, индексов возникают значительные ожидания latch: время теста 30 секунд, total latch wait time 2.4 секунд.
Еще одно замечание по нагрузочному тестированию нашел на ИТС, Влияние внешних обработок на производительность http://its.1c.ru/db/metod8dev#content:5940:hdoc : Компиляция модулей встроенных в конфигурацию выполняется однократно в процессе инициализации, тогда как для внешних обработок компиляция будет выполняться многократно, отдельно для каждого пользователя. Это приводит как к снижению производительности (компиляция модуля требует времени), так и существенному повышению нагрузки на CPU. Поэтому не рекомендуется выносить во внешние обработки функционал, который может одновременно использоваться большим количеством пользователей.
Итак, для максимальной нагрузки тест будет выполняться в несколько потоков с помощью фоновых заданий (если нужно расписание — используем регламентные задания), будет создаваться индекс временной таблицы, внешние обработки использоваться не будут.
Посмотрим на ситуацию со стороны СУБД. Будем использовать sys.dm_os_latch_stats. Очистить существующую статистику DBCC SQLPERF (‘sys.dm_os_latch_stats’, CLEAR) — запустить нагрузочный тест. Выборка статистики по нагрузке Select * from sys.dm_os_latch_stats where wait_time_ms > 0
latch_class |
waiting_requests_count |
wait_time_ms |
max_wait_time_ms |
ACCESS_METHODS_HOBT_COUNT |
48 |
7 |
1 |
BUFFER |
184436 |
7492 |
309 |
Динамическое представление sys.dm_os_latch_stats указывает, что основной тип latch – BUFFER. Как указано в документации (https://msdn.microsoft.com/ru-ru/library/ms175066%28v=sql.120%29) Используется для синхронизации краткосрочного доступа к страницам баз данных. Кратковременная блокировка буфера необходима перед считыванием или модификацией любой страницы базы данных. Конфликт кратковременной блокировки буферов может указывать на наличие ряда проблем, в числе которых — «горячие» страницы и низкая производительность подсистемы ввода-вывода.
Представление sys.dm_os_wait_stats устанавливает различие между ожиданиями кратковременных блокировок страниц, вызванными операциями ввода-вывода и операциями чтения и записи на данной странице. Очистить существующую статистику DBCC SQLPERF (‘sys.dm_os_wait_stats’, CLEAR) запустить нагрузочный тест. Выборка статистики по нагрузке Select * from sys. dm_os_wait_stats where wait_time_ms > 0
wait_type |
waiting_tasks_count |
wait_time_ms |
max_wait_time_ms |
LATCH_SH |
21 |
1 |
0 |
LATCH_EX |
45 |
6 |
0 |
PAGELATCH_SH |
24552 |
1680 |
280 |
PAGELATCH_UP |
88271 |
3460 |
267 |
PAGELATCH_EX |
115741 |
2012 |
1 |
PAGEIOLATCH_UP |
227 |
14 |
0 |
PAGELATCH и PAGEIOLATCH – соответственно доступ к страницам памяти и жесткого диска. LATCH – доступ к нестраничным ресурсам. Расшифровку типов ожидания можно посмотреть https://www.sqlskills.com/help/waits/ Очень хорошая, подробная статья. Приведу выдержку.
Common causes of PAGELATCH_XX contention are:
- Allocation bitmap contention in tempdb (PAGELATCH_UP for multiple threads trying to change the same bitmap), and under extreme loads, in user databases
- Table/index insert hotspot (PAGELATCH_EX for threads inserting onto the same page and possibly PAGELATCH_SH for threads reading from that page)
- Excessive page splits from random inserts (PAGELATCH_EX for threads trying to insert/update rows on a page and possibly PAGELATCH_SH for threads reading from that page)
Еще одна статья https://habr.com/post/216309/, на русском.
Для системного представления sys.dm_io_virtual_file_stats команда очистки не предусмотрена. Поэтому сначала выгрузим содержимое динамического представления во временную таблицу
use tempdb
go;
select * into MyTempDB01 from sys.dm_io_virtual_file_stats(null,null)
потом выполним нагрузочное тестирование и найдем разницу между старой и новой статистикой с помощью запроса
select tab1.database_id,
tab1.file_id,
tab1.num_of_reads-tab2.num_of_reads AS num_of_reads,
tab1.num_of_bytes_read — tab2.num_of_bytes_read AS num_of_bytes_read,
tab1.num_of_writes — tab2.num_of_writes AS num_of_writes,
tab1.num_of_bytes_written — tab2.num_of_bytes_written AS num_of_bytes_written,
tab1.io_stall-tab2.io_stall AS io_stall,
tab1.io_stall_read_ms-tab2.io_stall_read_ms AS io_stall_read_ms,
tab1.io_stall_write_ms-tab2.io_stall_write_ms AS io_stall_write_ms,
tab1.size_on_disk_bytes — tab2.size_on_disk_bytes AS size_on_disk_bytes
from sys.dm_io_virtual_file_stats(null,null) AS tab1
inner join MyTempDB01 AS tab2
on tab1.database_id = tab2.database_id
and tab1.file_id = tab2.file_id
database_id |
file_id |
num_of_reads |
num_of_bytes_read |
num_of_writes |
1 |
1 |
0 |
0 |
0 |
1 |
2 |
0 |
0 |
0 |
2 |
1 |
0 |
0 |
57 |
2 |
2 |
0 |
0 |
4672 |
Более подробно таблицу можно посмотреть в приложенном файле *.xls. Как видно, запись и чтение происходила только в базу ID = 2. Наверное, это TempDB. Сделаем запрос select DB_ID(‘tempdb’) – получим результат = 2. Так и есть.
Удалим временную таблицу drop table dbo.MyTempDB01
Поскольку мы выяснили, что latch происходят в таблице TempDB, можно попробовать перенести ее на более быстрый (или медленный) носитель. Для этого применяются команды
USE master
GO
ALTER DATABASE tempdb
MODIFY FILE (NAME = tempdev, FILENAME = ‘E: empdb.mdf’)
GO
ALTER DATABASE tempdb
MODIFY FILE (NAME = templog, FILENAME = ‘E: emplog.ldf’)
GO
Имена для файлов, соответствующих tempdev, templog можно посмотреть в свойствах таблицы. После изменения настроек TempDB службу SQL Server необходимо перезапустить. В моем случае тестирование после переноса не выявило изменений.
У системного представления sys.dm_db_index_operational_stats(,,,) первый аргумент ID базы -берем из прошлого примера. DMV не содержит имени таблицы – приходится делать левое соединение с таблицей sys.objects
Select tab2.name, tab1.page_latch_wait_count
from sys.dm_db_index_operational_stats(2,NULL,NULL,NULL) AS tab1
left join sys.objects as tab2 ON tab1.object_id = tab2.object_id
where tab1.page_latch_wait_count > 0
Строки повторяются: одна для таблица, другая – ее индекс. Назначения таблиц – из документации: https://msdn.microsoft.com/ru-ru/library/ms179503%28v=sql.120%29.aspx
name |
page_latch_wait_count |
Назначения таблиц |
sysrscols |
102147 |
Порядок полей таблиц |
sysrowsets |
40659 |
Существует в каждой базе данных. Содержит по строке на каждый набор строк секции для индекса или кучи. |
sysallocunits |
546855 |
Существует в каждой базе данных. Содержит по строке на каждую единицу распределения памяти. |
sysallocunits |
684 |
|
sysschobjs |
57 |
Существует в каждой базе данных. Каждая строка представляет объект базы данных. |
sysschobjs |
1 |
|
syscolpars |
3 |
Существует в каждой базе данных. Содержит по строке на каждый столбец таблицы, представления или табличной функции. |
syscolpars |
2 |
|
sysidxstats |
40 |
|
sysiscols |
1 |
Существует в каждой базе данных. Содержит по строке на каждый материализованный столбец индекса или статистики. |
sysobjvalues |
12 |
Существует в каждой базе данных. Содержит по строке на каждое общее свойство сущности. |
Любопытно, что таблица sysobjvalues в нашем случае производит гораздо меньше latch, чем топовые таблицы, а в докладе она наоборот, входит в топ. Возможно, изменилась архитектура ПО. Более подробно таблицу можно посмотреть в приложенном файле *.xls
Ситуация 2.
Включим замер производительности. Создадим много временных таблиц с помощью 1С. Как известно, при завершении запроса 1С, СУБД использует не DROP TABLE, а TRUNCATE TABLE — оставляет временную таблицу для повторного использования. Чтобы временных таблиц было много — каждая временная таблица должна иметь уникальный набор столбцов. Более подробно – смотрите обработку в приложенной базе данных 1С. У меня временные таблицы выглядят примерно так, их около 10 тысяч.
Посмотрим активные сессии: select * from sys.dm_exec_sessions where program_name = ‘1CV83 Server’
session_id |
login_time |
host_name |
program_name |
status |
51 |
2024-06-19 13:12:34.050 |
U1C01 |
1CV83 Server |
sleeping |
. . . |
|
|||
62 |
2024-06-19 13:12:34.050 |
U1C01 |
1CV83 Server |
sleeping |
При завершении сеанса 1С сессия SQL не завершается, а переходит в спящий режим. Поэтому чтобы уничтожить временные таблицы, принудительно завершим все активные сессии 1С пакетом команд
kill 51
. . .
kill 62
Кстати, чтобы не повторять однообразные строки, можно использовать скрипт, на основе https://ru.stackoverflow.com/questions/733831
Посмотрим результаты замера производительности.
Здесь до 13:04:15 идет создание временных таблиц, между 13:04:45 и 13:04:55 – завершение сессий SQL. Максимальные значения показателей latch более чем в три раза превосходят значения предыдущего эксперимента.
Для сравнения: если запустить запросы без создания временных таблиц, а затем завершить сессии SQL, ожиданий latch наблюдаться не будет. Хотя в момент завершения нагрузка на процессор почти такая же.
Посмотрим еще одно DMV sys.dm_exec_query_stats. Для него тоже нет способа очистки, но события можно выбирать по времени, например
SELECT st.*, qs.*
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
where qs.last_execution_time > DATETIMEFROMPARTS(2024,06,24,13,56,50,0)
—and qs.last_execution_time < DATETIMEFROMPARTS(2024,06,24,13,57,0,0)
ORDER BY execution_count DESC;
Это представление группирует исполняемые запросы по тексту. Видно, как часто встречаются одинаковые тексты запросов. Например, при присваивании имени временной таблицы выполняется запрос типа SELECT 1 WHERE OBJECT_ID(‘tempdb..#tt674’) IS NOT NULL.
Отчеты по DMV dm_os_wait_stats, dm_db_index_operational_stats отличаются от ситуации 1 только в процентном соотношении распределений количества latch.
Флаги трассировки, влияющие на latch
- 8048 – применяется в случае, если в вашей системе более 8 логических процессоров и наблюдается большое число ожиданий CMEMTHREAD и кратковременных блокировок.
- 1117 — позволяет управлять параметрами роста таблицы TEMPDB. в случае, если используется несколько файловых групп.
- 1118 — отключает смешанные экстенды. Влияет на GAM и SGAM. Pagelatch бывают PFS (pafe free space), IAM (index allocation map), GAM (global allocation map), SGAM (shared global allocation map).
Более подробно смотрите на ИТС – новая статья Флаги трассировки для работы с MS SQL Server http://its.1c.ru/db/metod8dev/content/5946/hdoc/_top
Выполним команду DBCC TRACESTATUS (1118), результат ниже
TraceFlag |
Status |
Global |
Session |
1118 |
0 |
0 |
0 |
Выполним команды DBCC TRACEON (1118); DBCC TRACESTATUS (1118), результат ниже
TraceFlag |
Status |
Global |
Session |
1118 |
1 |
0 |
1 |
Проверим, как влияет на количество latch. Запустим нагрузочный тест. Ниже отчет монитора производительности. Длительность latch была значительной, почти 2,6 секунды и ощутимо уменьшилась.
Не знаю, насколько чисто мне удалось выполнить этот эксперимент. Повторял несколько раз — получается. У меня возникло ощущение, что для прекращения использования нового флага трассировки службу сервера иногда приходится перезапускать. Проверьте у себя – поделитесь впечатлениями.
Любопытно, что в стандартных отчетах MS SQL Manager Studio видны изменения флагов трассировки от стандартных установок: Max degree of parallelism и TraceFlag 1118.
Кстати
Свойство SQL request wait — длительность запросов, о котором Виктор рассказывает в докладе на минуте 17, описано https://docs.microsoft.com/ru-ru/sql/database-engine/configure-windows/configure-the-query-wait-server-configuration-option?view=sql-server-2014. Посмотреть список таких свойств свойств можно командой select * from sys.configurations.
Заключение
Уважаемый читатель, если Вы добрались до этой строчки, значит есть интерес. Ищу мотивацию писать дальше, повторить исследование для postgres. Лучше, если это будет нужно не только мне, а кому-то еще. Поэтому я беру на себя супер-обязательство: если тема будет интересна и наберет хотя бы 50 звездочек на Инфостарт, я изучу postgres и дополню статью. Ошибки и неточности этой статьи буду исправлять по мере возможности. Кроме этого, жду Ваших конструктивных замечаний. Все в ваших руках.
Спасибо, интересно. Глубоко копнули. Не хватает итогового резюме: плюсов и минусов каждого из тестов с точки зрения нагрузки.
вместо perfmonitor можно было использовать dm_os_performance_counters
Статья хорошая, но комментариев нет. Возможно потому что тест выполнен абстрактный, коллеги не видят его прикладной пользы.
Думаю многим было бы интересно увидеть результаты теста на типовой конфигурации (например, ERP), с результатами применения флагов трассировок.
Спасибо, интересная статья. Вопрос-может ли как-то отрицательно повлиять флаг трассировки 1118, например раздует размер всех баз в инстансе(насколько я понимаю этот флаг включается глобально для всего SQLServer).
Здравствуйте ! Спасибо за интерес. Флаг трассировки хорошо документирован MS, посмотрите в первоисточник. Это будет надежнее моего ответа )).
(3) Да, возможно. Для меня так тестировать — слишком трудозатратно. Первого шага достаточно.
(4) 1118 — это рекомендация не 1с. Это рекомендация самой МС. А в свои скрипты Гленн Берри включает описания в т.ч. тех же флагов, что и Скворцова в статье на КБ.
В 2016 все включено по дефолту и кажется эти флаги действия уже не имеют.
Юзайте свежее по.
Отличная статья. Звезда.
(7) Да, я заметил что многие флаги, которые есть в MS SQL 2012, в MS SQL 2016 уже включены.