• Базы данных
  • SQL Server
  • Поддержка и разрешение проблем процессорной архитектуры NUMA в SQL Server 2005

Поддержка и разрешение проблем процессорной архитектуры NUMA в SQL Server 2005

ОГЛАВЛЕНИЕ

SQL Server 2005 был разработан с учётом того, чтобы использовать в своей работе возможности и интерфейсы NUMA, которые поддерживаются современными серверными платформами и операционной системой Windows. Есть несколько проблем, о которых Вы должны знать при попытке запуска SQL Server на поддерживающих NUMA платформах.

В этой статье я хотел бы сделать обзор поддержки NUMA в Windows и SQL Server, описать их возможные конфигурации, и дать несколько советов относительно разрешения возможных проблем.

В последнем июньском SQL Server 2005 CTP реализовано большинство из необходимого для поддержки NUMA, так что Вы уже можете опробовать эти возможности и лично убедиться в том, как поддержка NUMA используется на практике. Если Вас больше интересует поиск и устранение проблем, без необходимости вникнуть в причины проблемы, Вы можете сразу перейти к разделу разрешения проблем в этой статье.

Уровень изложения материала: я ожидаю, что Вы имеете представление о классической архитектуре ccNUMA, и поэтому я не буду вдаваться в её подробности и объяснять её принципы.


 

Поддержка NUMA в Windows

Реализующие архитектуру NUMA платформы могут быть построены по-разному. Есть две основные схемы - это NUMA в чистом виде, или многослойная схема NUMA архитектуры. NUMA в чистом виде представляется для операционной системы как набор процессорных узлов, которые иногда называют контейнерами (блоками) с локальной памятью. В зависимости от аппаратной реализации, могут быть разные по времени и производительности потери при обращении одного узла к участку локальной памяти сервера, который принадлежит другому узлу, числящемуся в другом процессорном блоке. Такая архитектура хороша для приложений, для которых характерно не большое число удаленных подключений.

Если же система имеет многослойную архитектуру, построенную на чередовании адресного пространства локальной памяти сервера между узлами, для операционной системы это будет выглядеть как большой SMP блок, в котором строки кэша разных узлов NUMA будут чередоваться в оперативной память. Такая архитектура больше подходит для приложений, которые не оптимизированы для NUMA и поэтому могут создавать проблемы для архитектуры NUMA в чистом виде. Например, если Вы работаете с SQL Server 2000, для которого не установлена вышедшая после SP3 заплатка QFE, которая включаем оптимизацию NUMA, Вам лучше не запускать SQL Server на сервере с архитектурой NUMA в чистом виде. В дистрибутиве SQL Server 2000 не реализованы многие из возможностей по оптимизации NUMA, и поэтому Вам стоит выбирать для него систему с многослойной NUMA архитектурой.

Когда Windows запускается на платформе с NUMA в чистом виде, операционная система распознает систему с множеством узлов и выбирает соответствующий тип загрузки. Из нашего опыта мы заметили, что во время загрузки, система распределяет память в основном для одного узла - имеется в виду, что это в действительности зависит от доступности памяти узлам, так же как это происходит при запуске большинства приложений операционной системы. Такая особенность распределения памяти во время загрузки операционной системы может создать проблемы для адоптированного к NUMA приложения - так как память не распределяется равномерно между узлами и не существует способов узнать о распределении памяти по узлам. После этого, когда система продолжает работать, проблема усугубляется, и свободной памяти, доступной узлам, становится всё меньше. Это может произойти из-за прожорливых по отношению к памяти приложений или из-за кэша файловой системы (SFC) при распределении значительного объема памяти и в некоторых системных конфигурациях. Кроме того, на платформе NUMA, возрастает вероятность того, что для SFC память по узлам будет использоваться неравномерно. Если адоптированное к NUMA приложение попытается распределять локальную память, оно может стать жертвой "зависания" памяти на узлах, которые работают с SFC или с памятью других, прожорливых по отношению к памяти приложений.

В Windows реализован набор API, с помощью которого приложениям могут задействовать возможности NUMA:

    GetNumaHighestNodeNumber
    GetNumaProcessorNode
    GetNumaNodeProcessorMask
    GetNumaAvailableMemoryNode

Есть несколько скользких моментов у некоторых из этих API, о которых Вам стоит знать:

  1. Нет явного способа распределения памяти от заданного узла - распределение памяти потока от выбранного узла памяти происходит за счёт изменения его привязки (афинитизации) к данному узлу, и последующего вызова VirtualAlloc (при работе с файлом подкачки, Вы вначале должны будете затронуть виртуальную адресацию, а затем установить связь с физической страницей) или другого низкоуровнего API, который осуществит физическое распределение страниц. Если у операционной системы нет памяти на этом узле, она задействует память другого узла, не приводя при этом к сбоям в распределении.
  2. Программный интерфейс GetNumaAvailableMemoryNode может возвращать 0 даже при том, что все еще может оставаться память, которую система могла бы задействовать у узла.
  3. Windows обслуживает память в следующем порядке:
    1. Для потока, привязанного к узлу.
    2. Для узла, который имеет свободную память.
    3. Для любого узла - с освобожденной памятью из зарезервированных списков, рабочих множеств или кэша файловой системы.

Последствиями пунктов A и C является то, что в адаптированных к NUMA приложениях нужно уделять больше внимания специальной обработке ситуаций, когда память может оказаться дальней по отношению к исполняющему задачу узлу. В пунктах A и C возможно такое поведение, что операционная система будет возвращать память случайным образом, то удалённую от узла память, то локальную и т.п. Имейте в виду, что если приложение решает не кэшировать отдаленную для используемого узла память, это может вызвать проблемы, т.к. когда память освобождается, она попадает в список свободной памяти и будет отдана при следующем запросе на распределение.

Последствием пункта B является то, что приложение не может принять абсолютно точное решение, возможно ли распределить память от узла. Пункт B характерен для тех случаев, когда система работает продолжительное время и особенно когда используются большие приложения.


 

Поддержка NUMA в SQL Server 2005

SQL Server 2005 пытается получить максимальные преимущества от архитектуры NUMA, что позволяет усилить производительность SQLOS для больших объёмов информации. В процессе запуска, SQL Server подстраивается под установленную операционную систему и аппаратную конфигурацию. Он организует свою среду так, чтобы задействовать по максимуму возможности имеющихся аппаратных средств, для этого на программном уровне SQL Server создаёт некую абстракцию каждого узла NUMA и его памяти, которую в этой статье давайте просто называть "Узел".

Каждый такой узел в SQL Server имеет менеджера памяти, устанавливающего планировщиков для каждого представленного битовой маской конфигурации сервера процессора, а также устанавливающего порты ввода - вывода и другие компоненты. Этот узел можно абстрагировать как отдельный экземпляр SQL Server с собственным портом I/O, который он слушает. Клиенты или отдельные приложения могут быть настроены на то, чтобы подключаться только к определенному узлу. Узел может быть доступен из сети или работать автономно, не выполняя работы или не обслуживая подключений. Состояние узла можно менять на лету, настраивая его привязку - affinity. Подключения могут осуществляться к выбранному узлу или группе узлов, сетевой порт может привязываться к нескольким узлам. Без дополнительных настроек, каждое новое подключение будет назначено на следующий по порядку узел в задействованной группе узлов. Если подключение работает с группой узлов, оно также назначается следующему узлу по порядку и в зцикле очерёдности в этой группе узлов. В BOL имеется множество информации о настройке подключений для портов SQL Server, узлов и клиентских компьютеров. После создания подключения, оно привязывается к узлу до момента прекращения соединения. Если узел подключения переведён в автономное состояние, его задачи будут запланированы для других узлов. Вся память, которая использовалась для обслуживания выполняемых в подключении работ, распределяется в локальной (ближней) по отношении к задействованному узлу памяти. Страницы базы данных всегда распределяются в ближней памяти узла, который с ними работает, если они не были привнесены в память подключением, назначенным на другой узел.

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

Поддержка различных возможностей NUMA в SQL Server, может настраиваться и на клиенте и на сервере. На сервере DBA может задать объем памяти, активные узлы, число потоков, характер блокировки страниц, конфигурацию сети - какие сетевые адаптеры к каким узлам будут привязаны. На клиенте DBA может выполнить настройки клиентских приложений, чтобы они соединялись с определенными узлами.

Ниже представлены два параметра настроек, которые меняют поведение SQL Server, работающего на платформе с NUMA архитектурой:

  1. Affinity - Используя sp_configure DBA может легко изменить для SQL Server привязку процессоров. Основное отличие между SQL Server 2000 и SQL Server 2005 для этого параметра состоит в том, что теперь изменения affinity становятся действительными сразу и не требуют рестарта сервера. Как Вы помните по SQL Server 2000, если affinity не задано, SQL Server будет привязывается сразу ко всем процессорам. Для SQL Server 2005, работающего на платформе с NUMA архитектурой, если affinity не задано, SQL Server будет увязывать каждый планировщик с набором процессоров, в соответствии со схемой отображения узлов для SQL Server. Например, для NUMA узла 1 (узлы пронумерованы, начиная с 0), имеющего 4 процессора, планировщики SQL Server этого узла будут иметь affinity равное 0xF0. В действительности, когда DBA задаёт affinity, мы называем это аппаратным affinity, каждому планировщику узла будет привязан его собственный процессор. Например, в упомянутом выше примере первый планировщик будет иметь affinity равное 0x10. Когда планировщик узла отображается на основной процессор, мы говорим, что планировщик является активным. Для планировщика также возможно быть и в автономном режиме. Для примера, давайте рассмотрим случай, когда в системе два NUMA узла; DBA устанавливает для сервера affinity равным 0x1F - только 5 планировщиков отображены на процессоры; четыре для узла 0 и один для узла 1. Последние три планировщика узла 1 в автономном состоянии - т.е. никакие новые задачи ими не будут планироваться. Если все планировщики для какого - нибудь узла будут автономны, тогда весь узел будет автономен - это означает что ему не будет предоставляться какая - нибудь работа или новые подключения.
  2. Max Server Memory - Это один из глобальных параметров настройки сервера. В июльской версии SQL Server 2005 CTP, память по-прежнему распределяется для узла до тех пор, пока узел в ней нуждается или пока объём распределяемой памяти не превысит заданный в max server memory объём. SQL Server не может пока распределять/использовать дальнюю по отношению к узлу память, эта проблема должна быть решена к появлению окончательной редакции SQL Server 2005.


Разрешение проблем, связанных с работой SQL Server на платформе с архитектурой NUMA

Описание проблемы: Запрос выполняется спорадически медленно, даже если план запроса не изменяется, или клиенты замечают, значительную деградацию производительности иного тип.

Это самая распространённая проблема. Основной её причиной является истощение памяти во время исполнения запроса на узле, которое могло произойти по нескольким причинам:

  1. Узел 0 создаёт проблемы, т.к. вся память этого узла использована во время запуска операционной системы. Возможное решение этой проблемы состоит в том, чтобы изменить для SQL Server маску affinity так, что бы узел 0 работал автономно, т.е. не использовался для нужд СУБД.
  2. Проблемы создаёт узел N, т.к. вся память этого узла использована другими приложениями или кэшем файловой системы (также см. ниже Misconfigured System File Cache). Вы можете поискать пути разрешения этой проблемы анализируя размер SFC и потребление памяти другими приложениями, а также объем памяти, используемый SQL Server на каждом узле, исполнив команду dbcc memorystatus. Возможное решение этой проблемы состоит в том, чтобы успеть захватить всю память для SQL Server перед запуском других приложений. Вы можете добиться этого, используя: max server memory, динамическое планирование и клиентское affinity. Идея решения в том, что нужно запустить первый узел, одновременно подключаясь к узлу и нагружая его работой, чтобы память для узла была распределена. Потом запустить следующий узел, нагрузить его, обеспечить распределение памяти и так далее. В довершение ко всему, сделайте минимальный и максимальный объёмы памяти одинакового размера, чтобы SQL Server не сокращал объём памяти при загрузке. Ниже представлена последовательность шагов, которые необходимо для этого предпринять:
    1. Настройте SQL Server для работы с множеством узлов и с портом для каждого узла.
    2. Настройте клиентов для каждого узла.
    3. Подготовьте большой запрос, например, переиндексацию, который будет потреблять не менее DesirableMemory/#Nodes памяти (желательной для работы СУБД объём памяти) и будет выступать в роли рабочей нагрузки.
    4. Запустите SQL Server.
    5. Переведите все узлы кроме узла 0 в автономное состояние, используя для этого sp_configure.
    6. Установить "max server memory" равным DesirableMemory/#Nodes, также используя sp_configure.
    7. Подключитесь к узлу 0.
    8. Запустите на него рабочую нагрузку.
    9. Увеличение "max server memory" на величину DesirableMaxMemory/#Nodes, используя sp_configure.
    10. Сделайте активным следующий узел, используя для этого sp_configure.
    11. Повторите пункты 7-10 для оставшихся узлов.
    12. Установить "max server memory" = "min server memory" = DesirableMaxMemory.
  3. Проблема: Misconfigured System File Cache. Эта проблема связана с проблемой, описанной в пункте B. Если FSC неправильно настроен, он может поглотить всю память сервера. Вы можете проверить наличие этой проблемы, посмотрев на размер FSC через Диспетчер Задач или через Системный Монитор. Устранить проблему можно перейдя к: "My Computer"-> "Properties"->"Advanced"->"Performance Settings"-> "Advanced"->"Memory Usage Programs" ->"Ok" и перезагрузить сервер, если Вы изменили выбор установки приоритета использования памяти с системного кэша на программы. Проблема может возникать у приложений даже в том случае, если система настроена так, как только что было показано, т.е. приоритет памяти для программ, но кэш файловой системы по-прежнему может потреблять очень много памяти. Если это происходит, можно написать специальную утилиту, которая будет периодически урезать размер кэша файловой системы.