18.4.23

Пример настройки Soft-NUMA

Сегодня получили широкое распространение многоядерные системы. Персональные компьютеры с четырьмя ядрами уже не редкость. Т.о. счастливые обладатели подобных многоядерных систем могут на практическом примере апробировать Soft-NUMA и как можно привязать к Soft-NUMA узлу порт сетевого протокола TCP/IP.

Для этого будем использовать компьютер х86 с четырьмя логическими процессорами. Процессоры в системе нумеруются с нуля до трёх. Воспользовавшись программой SQL Server Management Studio, в свойствах сервера, на закладке Processors, отключается привязка к первому процессору (CPU0) для обоих типов привязки: Affinity и I/O Affinity. Это делается для того, чтобы оставить один процессор операционной системе для привязки к нему других приложений (неравён час, прожорливость SQL Server помешает вам насладиться представленным тут примером). Как вы наверняка знаете, другие процессы можно привязывать к процессорам с помощью Диспетчера Задач Windows. Таким образом, можно снизить влияние на тестируемые процессоры нагрузки от активного во время тестирования программного окружения. Для двух следующих процессоров (CPU1 и CPU2) отменим I/O Affinity, оставив для них только привязку Affinity. Это необходимо, чтобы не совмещать обслуживание процессорами системных дисковых операций с обслуживанием сетевых запросов. И последний процессор (CPU3) мы наоборот замаскируем для Affinity и оставим ему привязку только для I/O Affinity. Этому процессору будет отведена роль обслуживания системного процесса отложенной записи. Нет особых причин, которые меня побудили включить эту настройку в систему, просто хотелось, чтобы вы пощупали и этот параметр глобальной конфигурации сервера.

Внимание! Этот пример не является примером хорошей практике или какой-либо рекомендацией к подражанию в промышленных системах. Целью этого примера является только очень упрощённая демонстрация возможностей Soft-NUMA, которую можно воспроизвести в домашних условиях.

Привязку процессоров и отложенной записи можно выполнить и с помощью системной хранимой процедуры sp_configure, как это показано ниже:

USE master;
GO
EXEC sp_configure 'show advanced option', '1';
RECONFIGURE;
EXEC sp_configure 'affinity mask', 6;
EXEC sp_configure 'affinity I/O mask', 8;
RECONFIGURE WITH OVERRIDE;
GO
EXEC sp_configure 'show advanced option', '0';
RECONFIGURE;
GO

После этого, поскольку было выполнено изменение параметра глобальной конфигурации affinity I/O mask, чтобы все изменения вступили в силу, потребуется перезапуск службы SQL Server.
В данном тестовом примере создаётся два программных узла, каждый должен содержать по одному логическому процессору, первый - CPU1, а второй - CPU2. Каждому из программных узлов будет присвоен свой порт TCP, первому - 20001, а второму - 20002. Для чистоты эксперимента, отключим все используемые SQL Server протоколы, кроме TCP/IP. Это можно сделать, воспользовавшись поставляемой в дистрибутиве утилитой SQL Server Configuration Manager, в разделе SQL Server 200х Network Configuration, если перейти на узел "Protocols for MSSQLSERVER". В правой части появившегося окна будет представлен список выбранных для SQL Server протоколов, и по правой кнопке для них доступна команда отключения или подключения каждого из протоколов.

ВНИМАНИЕ! Для того чтобы привязать порты к процессорам, необходимо вручную выполнить изменения системного реестра операционной системы. Вам необходимо помнить, что ошибочные действия с реестром могут привести к возникновению проблем в работе сервера или его компонент. Прежде, чем приступать к изменениям в реестре, удостоверьтесь, что Вы имеете актуальную копию состояния системы. Для обеспечения возможности быстрого отката неверных или неудачных изменений, сохраните изменяемые ключи или целые ветви реестра в экспортируемых файлах. Все операции с системным реестром Вы делает на свой страх и риск, и не рекомендуются вносить изменения вручную, особенно на промышленных системах без глубокого предварительного тестирования. Кроме того, следует учитывать, что системы x86 и x64 используют разные местоположения веток реестра и пути размещения файлов приложений и служб.

Первым шагом для достижения этой цели является создание Soft-NUMA узлов. Для этого, нужно в системном реестре добавить следующую ветку ключей:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
"CPUMask"=dword:00000002
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
"CPUMask"=dword:00000004

Обратите внимание, что потребуется создать новый подраздел системного реестра NodeConfiguration, в котором описываются программные узлы. Node0 - это подраздел первого узла, в котором указывается ключ CPUMask с шестнадцатеричным значением, соответствующим маске физических процессоров, задействованных для этого узла. В нашем примере заданное значение dword:00000002 соответствует выбору второго физического процессора - CPU1. Подраздел Node1 содержит маску процессоров для второго программного узла. Эта маска соответствует выбору третьего процессора - CPU2.
Таким образом, мы определили для SQL Server два программных узла, и в каждый входит по одному процессору. Задаваемый маской программного узла набор объединяемых процессоров может включать несколько процессоров в произвольном, определяемом маской порядке (с учётом изложенных выше ограничений). Если бы нам потребовалось включить в состав первого программного узла ещё и первый физический процессор, тогда маска должна была бы получить значение dword:00000003, и нам бы ещё потребовалось добавить привязку Affinity для CPU0, от которой мы отказались на подготовительном шаге нашего примера.
Планирование обслуживания сетевой нагрузки процессорами в рамках такого программного узла осуществляется циклическим выбором входящих в программный узел процессоров.
Следующим шагом, является назначение портов программным узлам. Для этого, необходимо откорректировать значение параметров TCP Port, доступные на закладке "IP Addresses" свойств протокола TCP/IP, в узле "Protocols for MSSQLSERVER" утилиты "SQL Server Configuration Manager". В нашем примере, необходимые изменения вносятся непосредственно в системный реестр, путём редактирования тех ключей, в которых SQL Server хранит параметры сетевых протоколов. Ниже представлено содержимое REG - файла, в котором установлены все необходимые для примера параметры протокола TCP/IP.

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp]
"Enabled"=dword:00000001
"ListenOnAllIPs"=dword:00000001
"NoDelay"=dword:00000000
"KeepAlive"=dword:00007530
"DisplayName"="TCP/IP"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll]
"TcpPort"="20001[0x1], 20002[0x2]"
"TcpDynamicPorts"=""
"DisplayName"="Any IP Address"

Здесь представлена ветвь системного реестра для подраздела TCP сетевой библиотеки. Как видно, протокол TCP разрешён, и прослушивание будет вестись по всем IP адресам. Во вложенном подразделе IPAll заданы значения портов, используемых экземпляром SQL Server. Эти порты прописаны в строковом ключе TcpPort.
Вы, наверное, уже обратили внимание, что справа от каждого из номеров портов в квадратных скобках указана маска, которая соответствует номеру (начинающиеся не с нуля, а с единицы) Soft-NUMA узла, определённого нами на предыдущем шаге. Маску можно указывать в десятичном или шестнадцатеричном формате, в нашем примере, формат шестнадцатеричный. Таким образом, поступающие на порт 20001 сетевые запросы пользователей будут исполняться на первом процессорном узле (у нас это процессор CPU1), а запросы к порту 20002 будут обслуживаться на втором программном узле (CPU2).
Чтобы наши изменения в системном реестре были подхвачены сервером, необходимо перезапустить службу SQL Server.
Дополнительную информацию о привязке портов сетевого интерфейса к узлам Soft-NUMA можно получить в электронной документации Microsoft SQL Server Books Online: "Как сопоставить порты TCP/IP порт с узлами NUMA".
Для того чтобы убедиться в том, что всё так и будет происходить, несложно создать сравнительно большую рабочую нагрузку на оба порта. В этом примере, мы будем исполнять на каждом из портов довольно простую, но ресурсоёмкую команду по переиндексации всех таблиц тестовой базы данных AdventureWorks, которую можно взять по этой ссылке: http://msftdbprodsamples.codeplex.com. Ниже показан текст запроса, содержащего эту команду.

USE AdventureWorks;
GO
EXEC sp_MSforeachtable "DBCC DBREINDEX ('?')";
GO

Для того чтобы направить этот запрос на заданный порт, создаём два псевдонима нашего SQL Server, которые будут отличаться только портами TCP. Псевдонимы также можно создавать с помощью утилиты SQL Server Configuration Manager, перейдя к разделу псевдонимов в узле SQL Native Client Configuration. Поскольку псевдонимы также хранятся в системном реестре, давайте посмотрим, как они там могут выглядеть:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo]
"Node1"="DBMSSOCN,SQLRU,20001"
"Node2"="DBMSSOCN,SQLRU,20002"

Из представленных выше ключей реестра видно, что созданы два псевдонима, каждый из которых подключается по имени к серверу SQLRU, но для каждого из них для протокола TCP задан свой порт. Для псевдонима Node1 задан порт TCP 20001. А для псевдонима Node2 задан порт TCP 20002.
Теперь запустим программу SQL Server Management Studio, зарегистрируем там оба наших серверных псевдонима и, создав новое окно T-SQL запроса с подключением к псевдониму сервера Node1, введём в нём сценарий представленной выше команды. Чтобы наблюдать утилизацию процессоров во время исполнения запроса, в нашем случае удобно воспользоваться системной программой из комплекта поставки операционной системы - Диспетчер Задач.
Запустив исполнение запроса на переиндексацию всех таблиц тестовой базы данных AdventureWorks, и обращаясь к серверу через псевдоним Node1, автор наблюдал следующую картину:

Рис. 1. Подача нагрузки на первый программный узел

Как видно на Рисунке 1, основная доля рабочей нагрузки попала на второй процессор, чего мы и добивались. Теперь, давайте запустим эту же рабочую нагрузку через псевдоним Node2. В этом случае, закладка Быстродействие в оснастке Диспетчер Задач во время исполнения запроса приобретёт вид, который представлен на следующем рисунке:



Рис. 2. Подача нагрузки на второй программный узел

Из рисунка 2 видно, что рабочая нагрузка переместилась на третий процессор как мы и планировали. В итоге, мы получили такую схему привязки, что в зависимости от избираемого клиентским подключением порта, создаваемая им рабочая нагрузка может посылаться на один из двух процессоров, доступных в системе для клиентских подключений.
В случае NUMA, привязка портов сетевых интерфейсов осуществляется так же, как и для SMP серверов, только может понадобиться добавить ключи реестра, определяющие протоколы сетевых интерфейсов для нескольких сетевых адаптеров. В нашем примере, в варианте использования одного адаптера, понадобились бы следующие ключи системного реестра Windows:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP1]
"Enabled"=dword:00000001
"Active"=dword:00000001
"TcpPort"="20001[0x1]"
"TcpDynamicPorts"=""
"DisplayName"="Specific IP Address"
"IpAddress"="127.0.0.1"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP2]
"Enabled"=dword:00000001
"Active"=dword:00000001
"TcpPort"="20002[0x2]"
"TcpDynamicPorts"=""
"DisplayName"="Specific IP Address"
"IpAddress"="127.0.0.1"

На представленных выше рисунках 1 и 2, ваш интерес, возможно, привлекла некоторая активность, которая наблюдается в виде загрузки узла, на который по идее не должна была поступать никакая нагрузка. Давайте попробуем разобраться в её природе.
Первое предположение, которое приходит в голову, что процесс повторного создания индексов может быть распараллелен и нагрузка распределяется на нескольких процессоров. Другая гипотеза, это выполнение ресурсоёмких сортировок с промежуточной материализацией в tempdb, которая выполняется в другом потоке.
Системная процедура sp_MSforeachtable пересоздаёт индексы таблиц базы данных последовательно и трудно предугадать, какие из этих индексов будут пересоздаваться с использованием распараллеливания или потребуют промежуточной материализации. Поскольку мы наблюдаем активность на программном узле, который не нагружался запросом, можно предположить, что с помощью программных узлов можно указать только те группы процессоров, которые должны быть нагружены в первую очередь. Получается, что если для сервера будет существовать возможность создания такого числа потоков, которое превышает число процессоров выбранного для запроса программного узла, то нагрузка будет размещена и на процессоры, которые не входят в число процессоров выбранного программного узла. В общем случае, вывод такой, что наш тестовый сценарий не очень "чисто" демонстрирует возможности Soft-NUMA.
Из документации следует, что механизмы планирования задач операционной системы и SQL Server устроены таким образом, что планирование потоков не привязывается жёстко к схеме процессорных узлов. Если в системе есть свободные процессоры, и не наложено никаких ограничений на число потоков, обслуживающих запрос, то нет препятствий задействовать под подаваемую на программный или NUMA-узел нагрузку столько процессоров, сколько доступно для экземпляра SQL Server.
Имея в виду вышесказанное, давайте немного изменим условия нашего предыдущего примера, преследуя цель более наглядно и приближённо к реальным задачам продемонстрировать работу Soft-NUMA. Мы будем посылать определённым для примера псевдонимам сервера такую нагрузку, которая больше похожа на реальную работу пользователей. Как вы помните, используемые в примерах псевдонимы отличаются только прослушиваемыми сервером баз данных портами, которые привязаны к заданным программным узлам. Нам потребуется нагрузка, которая лучше поддаётся распараллеливанию, чем использованная нами ранее переиндексация таблиц.
В следующей демонстрации, что бы получить распараллеливаемую нагрузку, на тестовом компьютере был развернут стандартный набор инструментов и шаблонов эталонного теста TPC-H. Для простоты, размер исходной информации базы данных был выбран в один гигабайт. Спецификацию и подробное описание теста TPC-H, базы данных и запросов можно найти на сайте tpc.org. Была создана и проверена тестовая база и необходимый набор запросов. Наиболее удобным для демонстрации представляется запрос Q13, исполнение которого не занимало на сервере много времени, хорошо утилизировало процессоры и требовало распараллеливания задач. Все большие таблицы и индексы базы данных были размещены в отдельных файловых группах, каждая из которых состояла из нескольких файлов.
Поскольку, в нашем примере для каждого программного узла выделялось по одному процессору, то чтобы не было перехлёста рабочей нагрузки на другие узлы, в глобальных параметрах конфигурации SQL Server были выполнены следующие изменения:

USE master;
GO
EXEC sp_configure 'show advanced option', '1';
RECONFIGURE;
EXEC sp_configure 'max degree of parallelism', '1';
RECONFIGURE WITH OVERRIDE;
GO
EXEC sp_configure 'show advanced option', '0';
RECONFIGURE;
GO<

Предложенный Вашему вниманию сценарий включает режим установки расширенного набора глобальных параметров конфигурации SQL Server и устанавливает предельное число используемых для исполнения параллельного плана запроса процессоров в единицу. Этим фактически было отменено распараллеливание любых запросов.
Выполнено это было именно для того, чтобы посылаемые на программные узлы запросы исполнялись в одном потоке и, как следствие, эксплуатировали только один процессор, на основе которого был определён программный узел.
На следующем рисунке представлена диаграмма утилизации второго процессора, который составляет по условиям нашего теста первый программный узел.


Рис. 3. Подача нагрузки на первый программный узел

Как видно из рисунка 3, уже не наблюдается активности на других процессорах, как это было в варианте запроса на переиндексацию таблиц. Используя абстракцию процессорного узла и ограничение MAXDOP = 1, мы смогли локализовать нагрузку только на заданном по условиям теста процессоре. В реальных условиях уровень максимальный уровень параллелизма, который исходит из требований бизнеса, может стать одним из определяющих факторов выбора числа ядер в одном узле.
Если запрос Q13 направить посредством соответствующего псевдонима на второй программный узел, мы увидим ожидаемую в этом случае картину, которая представлена на рисунке 4.


Рис. 4. Подача нагрузки на второй программный узел

Если же немного изменить условия теста и установить MAXDOP = 2, то при отправке запроса на порт TCP/IP:20001, мы увидим, что нагрузка распараллелится на всех процессорах, выделенных для используемого в тесте экземпляра SQL Server. Т.к. всего у нас два логических процессора, загружены будут оба Soft-NUMA узла, как это показано на рисунке 5.


Рис. 5. Влияние MAXDOP = 2

Правила, по которым нужно настраивать параметры глобальной конфигурации для SMP сервера с программными узлами фактически такие же, как для неадаптированных к NUMA приложений. Если целью является исключение передачи части рабочей нагрузки одного Soft-NUMA узла на другие узлы, то SQL Server должен иметь такую конфигурацию, которая не позволяла бы создавать больше потоков, чем количество процессоров, которое определено для одного программного узла.
Одним из полезных свойств описанного в последнем примере способа управления планированием нагрузки является то, что можно разнести на разные процессоры одного экземпляра SQL Server запросы от разных клиентов в сети. Это может дать заметный выигрыш в производительности экземпляра, если из-за негативного влияния нагрузок клиентов друг на друга нежелательно обслуживать их на одних и тех же ресурсах. Негативное влияние может проявляться в виде очень долгого использования процессора одним из потоков или конкуренцией исполняемых на одном узле потоков за локальные ресурсы узла. SQL Server предоставляет в распоряжение администратора баз данных средства управления планированием потоков. С помощью этих средств администратор может существенно снизить подобное негативное влияние потоков друг на друга.
Кроме того, продемонстрированные в последних тестах результаты позволяют рекомендовать подобное управление планированием потоков для приложений, код которых недоступен для модификации собственными силами. Этот подход применим, если требуется балансировка порождаемой приложениями нагрузки в рамках одного экземпляра SQL Server, а возможности реализовать это на стороне клиента нет. Все изменения, которые потребуется внести администратору - это определить в системном реестре Soft-NUMA узлы, привязать к ним порты сетевых интерфейсов, создать необходимые псевдонимы, а потом прописать соответствующие строки подключения в конфигурации приложения. В итоге, используя новые возможности планирования потоков, можно выделить разные группы процессоров для клиентов, которые посылают серверу "тяжёлые" аналитические запросы, и для тех клиентов, которые посылают серверу короткие транзакции или выборки. Выполнив необходимые для этого настройки, можно практически свести к минимуму возможное негативное влияние таких разнотипных запросов к одной и той же базе данных. Дополнительные возможности регулирования нагрузки может дать комбинирование средств и возможностей Soft-NUMA с возможностями регулятора ресурсов SQL Server 2008.
Сама возможность балансировки нагрузки между процессорами одного экземпляра SQL Server позволяет экономить лицензии и не приобретать дополнительные сервера только для того, чтобы на одном сервере балансировать нагрузку между процессорами, т.е. фактически выделяя и закрепляя ресурсы за приложениями или группами приложений. В предыдущих версиях SQL Server это достигалось только за счёт установки дополнительных именованных экземпляров сервера баз данных, а потом, процессоры распределялись между установленными экземплярами (что можно было делать динамически или можно было задать в глобальной конфигурации экземпляров жёсткую привязку процессоров экземплярам).
Другие сценарии привязки портов к процессорным узлам можно найти в электронной документации Microsoft SQL Server Books Online: "Сценарии NUMA". 

Комментариев нет:

Отправить комментарий