Статья адресована опытным администраторам баз данных SQL Server, знакомым с архитектурой SQLOS и современными платформами Intel и AMD.

Введение

До недавнего времени, наиболее распространённой архитектурой систем с большим числом физических процессоров являлась архитектура неоднородного доступа к памяти Non-Uniform Memory Architecture (NUMA). В основе этой архитектуры лежит такой способ организации доступа к оперативной памяти сервера, который зависит от её расположения (удалённости) по отношению к процессору. Внутренняя организация такой серверной архитектуры отличается от архитектуры SMP систем набором дополнительных компонент, которые обеспечивают взаимодействие процессорных блоков — узлов между собой. Говоря упрощённо, эти компоненты как бы связывают несколько обычных SMP серверов на одной или на нескольких материнских платах, обеспечивая обращения процессоров из одного узла к памяти на другом узле, если это оказывается необходимо.
Сегодня мы с вами становимся свидетелями смены тенденции в развитии архитектур неоднородного доступа к памяти. Классические типы архитектур, которые запомнились, прежде всего, своей высокой стоимостью решений, заменяются близкими по смыслу, но построенными на более дешёвых компонентах, архитектурными решениями. Если сделать краткий экскурс в историю, то мы увидим, что долгое время наиболее распространённой была архитектура NUMA с обеспечением когерентности процессорных кэшей. Вам должна быть знакома аббревиатура ccNUMA. Существовало несколько протоколов и реализаций поддержки когерентности кэшей, некоторые из них были подробно описаны в работе: Архитектура S2MP — свежий взгляд на cc-NUMA. Если кратко, то суть сводится к тому, что изменение в кэше приводит к удалению копий данных из кэшей других процессоров, а информация о копиях хранится в виде битового вектора, в специальном «оглавлении», которое иногда называют кэшем четвёртого уровня, который, по сути, является кэшем метаданных. Пример реализации и описание подобной архитектуры можно найти в статье: Архитектура серверов HP Superdome. Один из вариантов реализации архитектуры ссNUMA был предложен компанией Sequent, и получил название NUMA-Q (это ссNUMA с кводами). Компания была приобретена IBM, и развитие описываемых в статье технологий можно видеть в современных решениях этого вендора.
В последние годы существенно возросло число физических ядер процессоров на один процессорный разъем — сокет (многоядерные процессоры). Существуют решения, например, IBM X-Architecture, которые позволяют ещё больше увеличить число процессорных ядер, что осуществляется за счёт объединения многоядерных SMP систем в блоки серверов. Такие серверные «бутерброды» способны по числу процессоров и по производительности конкурировать с традиционными NUMA системами. По сути, обычные шасси SMP серверов связываются между собой специальными межсоединениями. Многоядерность сама по себе уже вносит неоднородность в доступ к памяти. В случае же, когда несколько серверов с многоядерными процессорами объединяются в единый серверный блок (управляемый одной операционной системой или гипервизором), доступ процессорных ядер к оперативной памяти другого шасси носит ярко выраженный неоднородный характер. Всё это размывает разницу между классическими NUMA — системами и современными SMP-решениями. Некоторые вендоры даже называют построенную на SMP многопроцессорную архитектуру — NUMA-like Architecture.
В современных массовых процессорных архитектурах тоже используется неоднородный доступ к памяти. Например, такая схема реализована для Intel QuickPath Integrated Memory Controller. Это решение отличается тем, что в нём отказались от архитектуры фронтальной шины. Вместе с процессорами на одном кристалле интегрирован контроллер памяти, посредством которых, по схеме точка — точка, подключаются модули оперативной памяти. Такое решение позволяет сгладить «застарелые» проблемы с поддержкой когерентности NUMA. Кроме того, за счёт применения дополнительных чипсетов (например, IBM eX5), удаётся с ущественно нарастить объём оперативной памяти, выделенной каждому процессорному ядру. Это позволяет очень сильно сократить трафик ввода-вывода через процессорные межсоединения. По сути, межсоединениям останется обслуживание только задач поддержки когерентности процессорных кэшей. О современных шинах межсоединений можно почитать в этих статьях: Intel QuickPath Interconnect и HyperTransport.
Что же дальше? Очень похоже на то, что нелинейность доступа к ресурсам останется головной болью администраторов надолго. Появление таких массовых архитектурных решений, как решения на основе QPI, и их «творческое» воплощение разными вендорами способно породить большое разнообразие топологий NUMA. Но это ещё не всё. Сегодня появляются решения, в основе которых заложена парадигма обратной виртуализации. Очень может оказаться, что изложенные в настоящей статье рекомендации и методики окажутся непригодны для таких нетрадиционных решений. Остаётся надеяться, что таким технологиям, как ScaleMP, не покорятся горизонты платформы Windows, и мне не придётся дополнять эту статью главой о NUMAlink.
Современные операционные системы уже немыслимы без поддержки NUMA. Эта поддержка обретает новые качественные улучшения от версии к версии. Так, например, в Windows 2003 была доработана поддержка NUMA в планировщике потоков и диспетчере памяти, а в Windows 2008 поддержка NUMA была добавлена в диспетчере запросов ввода-вывода и внесены усовершенствования в диспетчере памяти.
Существует утилита, которая позволяет увидеть топологию NUMA вашего компьютера. Эта утилита создана Марком Русиновичем, и скачать её можно с сайта sysinternals.com Название утилиты: «Coreinfo». Она позволяет получить данные о ядрах (параметр -c), о группах (параметр -g) и о NUMA — узлах (параметр -n).
Последние версии SQL Server тоже оптимизированы для работы в архитектуре NUMA. Особенности работы SQL Server в NUMA и способы настройки для оптимальной работы NUMA c нагрузками SQL Server будут разобраны в этой статье, а также вашему вниманию будут предложены ссылки на материалы, которые помогут уточнить или углубить представленные в статье рекомендации и описания.
Для успешного использования многопроцессорных платформ, системным администраторам и разработчикам приложений требуются дополнительные средства и меры, позволяющие влиять на распределение потоков между процессорами и закрепление за процессорами ресурсов сервера. Именно о таких мерах и средствах пойдёт речь в этой статье.

Традиционная архитектура NUMA

В этой статье речь идёт об особенностях работы SQL Server на платформе с архитектурой NUMA. Мы ограничимся в своём рассмотрении только теми компьютерами, на которые устанавливается версия операционной системы старше Windows 2000. Традиционной для использования с этой СУБД и ОС архитектурой NUMA являлась платформа на базе процессоров Intel Itanium. В этой главе вам будет представлен краткий обзор особенностей этой архитектуры. Долгие годы серверы масштаба предприятия строились именно на таких процессорах. В 2010 году было объявлено о выходе новой линейки процессоров Itanium, и в этом же году Корпорация Майкрософт объявила о прекращении поддержки этой платформы в своих новых версиях операционных систем, которые появятся после Windows Server 2008 R2.
В традиционной архитектуре NUMA каждый процессорный NUMA — узел имеет локальную по отношению к нему память, доступ к которой процессоры узла осуществляют симметрично и с минимальными задержками. Процессоры работают с памятью через специализированный контроллер памяти, который имеется у каждого узла. Этот контроллер решает и другие задачи, к числу которых относится организация взаимодействия с устройствами ввода-вывода и доступ к памяти других NUMA — узлов компьютера. Для доступа к памяти других узлов контроллеры использует специальную шину, позволяющую процессорам использовать память других узлов. Память других узлов будет являться для них удалённой, и доступ к ней будет с большей задержкой, чем к локальной памяти. Неоднородность доступа в этой архитектуре главным образом относится к памяти, что является основным отличием этой многопроцессорной архитектуры от SMP, и именно такой метод доступа к памяти определяет её название. Задержки обращения к удалённой по отношению к узлу памяти могут иногда на порядок отличаться от задержек обращения к локальной памяти узла. Современные архитектуры серверов используют механизмы «горячих» страниц, которые позволяют отслеживать наиболее активно используемые NUMA узлом участки удалённой по отношению к нему памяти и переносить располагаемые там данные в локальную память.
Кроме локальной памяти, каждый NUMA узел может иметь собственный канал ввода-вывода. Это позволяет соотносить NUMA узлы портам ввода-вывода и локализовать на этом узле только те задачи, которые поступили по предписанным узлам портам.
В качестве шины поддержки когерентности кэшей часто используются специализированные коммутаторы, которые позволяют масштабировать подключения контроллеров памяти. Контроллер памяти может иметь несколько портов, которые выделенной шиной подключаются к отдельным коммутаторам масштабируемости. Ещё одной задачей таких коммутаторов является обеспечение подключения контроллеров памяти к концентраторам ввода-вывода. Концентратор ввода-вывода через мосты подключается к дисковым устройствам ввода-вывода, а также другим, унаследованным устройствам ввода-вывода.
Основной целью NUMA является масштабируемость. Традиционно, наиболее сложными для масштабируемости являются массовые сетевые запросы. Основным недостатком NUMA — систем является их более высокая стоимость относительно традиционных SMP систем. Кроме того, сервера построенные не на платформе Itanium (NUMA-like системы) по числу ядер уже вплотную подобрались к традиционным NUMA системам. Ну и самой плохой новостью является уже упомянутый отказ Майкрософт поддерживать в будущих версиях семейство процессоров Intel Itanium.
Дополнительную информацию о неоднородном доступе к памяти можно найти в электронной документации Microsoft SQL Server Books Online: «Основные сведения о неоднородном доступе к памяти».

Особенности NUMA-like архитектур

Появление архитектуры NUMA-like обусловлено желанием масштабирования недорогих SMP серверов. Выглядит NUMA-like как многоядерный блок из нескольких шасси серверных SMP систем. В NUMA-like неоднородным становится не только доступ к памяти, но и дисковый ввод-вывод, сетевой ввод-вывод, доступ к устройствам на шинах PCI или USB. Такие устройства, как гибкие магнитные диски и приводы CD-ROM могут выборочно отключаться, поскольку классическая архитектура персонального компьютера не предусматривает наличие этих устройств на нескольких шинах.
Когда мы имеем дело с одним шасси сервера, процессоры могут обращаться ко всей его памяти, ко всем присутствующим шинам и адаптерам ввода-вывода. Разницы в производительности у процессоров при работе с памятью практически не будет. Всё меняется, когда шасси соединяются с помощью кабеля/разъёма масштабируемости. В этом случае, та память, шины и адаптеры ввода-вывода, которые будут с процессорами на одном шасси, позволят получать наибольшую операционную производительность. Аналогичные же устройства во втором шасси будут работать с процессорами первого шасси с издержками, которые могут оказаться весьма значительными. Кроме этих издержек, на производительность системы в целом могут повлиять и другие факторы, косвенно или напрямую зависящие от использования схемы с несколькими шасси.
В отличие от традиционной архитектуры NUMA, для которой выпускались специальные версии ОС и СУБД, архитектурные решения NUMA-like становятся чувствительны к выбору платформы, версий и редакций. Неверный выбор редакции или настроек операционной системы может породить проблемы. Например, возможна неверная оценка лицензий при учёте процессорных ядер, вследствие чего система будет неверно представлять прикладному уровню группировку ядер физических процессоров (сокетов). Неудачные реализации или настройки BIOS, а также драйверов устройств, тоже могут породить проблемы для определения точной топологии ресурсов соединённых межсоединениями серверов. Ещё одним возможным источником проблем могут стать неадаптированные к подобной схеме прикладные программы. Причиной деградации производительности таких программ может стать неправильная нагрузка на несколько шасси, приводящая к большому трафику по межсоединениям. Нужно очень тщательно подходить к планированию таких систем. Тут нет мелочей. Как уже отмечалось, даже выбор редакции операционной системы может сказаться на возможностях и производительности системы. Наиболее полный набор возможностей для многопроцессорных систем имеет редакция Datacenter. Проконсультируйтесь у вендора по поводу планируемой конфигурации и выбору версий и редакций её компонент.
В NUMA-like системе физическая память каждого из подключённых в одну систему серверов объединяется в единое, последовательное адресное пространство. С точки зрения организации доступа к памяти, это очень похоже на традиционную архитектуру NUMA. Физическая память каждого из серверов будет ближе к процессорным ядрам этого же сервера, чем к ядрам процессоров других SMP — серверов. Топология узла NUMA-like может включать в один узел все процессоры, относящиеся к одному шасси. Изменить такое формирование узлов позволяет только настройка Soft-NUMA, о которой речь пойдёт ниже.
У NUMA-like обращение к памяти другого сервера подвержено существенным задержкам, точно так же, как это было в традиционной архитектуре NUMA. Это необходимо учитывать при планировании нагрузки системы. Нужно учитывать и увеличение времени ожидания в процессорных очередях. Как ни странно, но численное увеличение числа ядер провоцирует увеличение числа передач контекста пользовательских запросов с одного сервера на другой. Это увеличивает затраты на исполнение запроса, но делает лучше параллелизм.
Более сложными становятся протоколы работы ядер с локальным кэшем. Например, в стандартном для SMP протоколе MESI (Modified. Exclusive. Shared. Invalid), используемом для определения актуальности состояния находящегося в кэше контекста, могут появиться дополнительные типы состояний. Обработка новых состояний тоже потребует дополнительных ресурсов. Да и сами размеры кэшей должны быть существенно больше, что обусловлено необходимостью снижения нагрузки на фронтальную шину FSB, если речь идёт о старых платформах Intel. Впрочем, одноранговые межпроцессорные соединения тоже не упрощают и не удешевляют такие решения.
Ещё одним отличием от традиционной NUMA является то, что соединяющие шасси серверов шины масштабируемости будут обслуживать не только задачи доступа к удалённой памяти. Межсоединения могут взять на себя ещё и задачи ввода-вывода с устройств, подключаемых по шинам PCI или USB. Такое произойдёт, если запросы ввода-вывода будут направлены с одного шасси на другое. В общем случае, для того, чтобы производительность не страдала от архитектурных особенностей NUMA-like, требуется добиться исполнения следующих трёх условий:

  1. Частота обращений к удаленной памяти должна оставаться существенно ниже, чем к локальной памяти шасси. Тут стоит стремиться к отношению 20% к 80%.
  2. Задержки удаленного доступа должны быть незначительны, т.е. они должны отличаться от задержек обращения к локальной памяти не больше чем в 10 раз.
  3. Пропускная способность межсоединения должна в идеале быть больше, чем та, которая требуется для SQL Server.

Бывают случаи, когда использовать возможности NUMA мешают другие аппаратные возможности. Например, у некоторых многопроцессорных серверов на базе процессоров AMD в BIOS может быть включена опция «Node memory interleave», которая фактически перетасовывает адресное пространство разных узлов и делает невозможным использование возможностей NUMA. Для обеспечения поддержки NUMA эта опция должна быть заблокирована.

Поддержка NUMA в операционной системе

Поддержка NUMA реализована в Windows Server 2003/2003R2/2008/2008R2 Enterprise Edition и Datacenter Edition. Для того чтобы операционная система могла задействовать предоставляемые NUMA и NUMA-like возможности, ей должно быть передано с аппаратного уровня описание физической топологии системы. Для этого задействуется специальный интерфейс расширений конфигурации, который определяет спецификацию передаваемой операционной системе таблицы статической привязки ресурсов — Static Resource Affinity Table (SRAT). Если на сервере запущено несколько операционных систем, таблица ресурсов будет включать только выделенные каждой системе ресурсы. Таблица привязки ресурсов может изменяться, при добавлении новых ресурсов, например «горячей» памяти, или вследствие физического изъятия ресурсов.
Во время запуска операционной системы для каждого узла NUMA формируется граф стоимости доступа ядер процессоров к ресурсам. Оценка стоимости основана на величине задержки запросов на доступ к памяти. Подсистема обслуживания листания памяти в Windows Server дополняется новым типом реакции на события доступа к странице памяти — «soft page fault». В отличие от «hard page fault», который показывал, что страницу нужно забрать с диска, этот новый признак говорит о том, что искомая страница находится на дальнем узле.
В спецификацию входит понятие доменов близости, которое позволяет объединить локальные ресурсы с точки зрения NUMA-узла в одну, прикреплённую к этому узлу логическую группу. Операционная система использует информацию из таблицы привязки ресурсов для того, чтобы выбрать используемую по умолчанию привязку процессора, процессов и потоков. Механизм доменов близости позволяет системе преимущественно планировать потоки одного процесса на процессоры одного и того же узла NUMA. Кроме того, система старается распределять для такого процесса локальную по отношению к выбранному узлу память. Таким образом система старается минимизировать дорогостоящие обращения процессоров одного узла к ресурсам других узлов. Каждый новый процесс будет планироваться на следующий по порядку NUMA узел.
Алгоритм работы с ближней и дальней памятью развивается вместе с появлением новых версий Windows. Мы затронем только те особенности, которые присутствовали в Windows 2003 и проследим некоторые изменения и улучшения этих алгоритмов в последующих версиях.
Для управления памятью система создаёт видимые и скрытые пулы для каждого домена близости, которые сопоставляются узлам NUMA. Аналогичным образом распределяется и расширенная для процесса память, доступная через окно трансляции адресов AWE. После первоначального выделения участков памяти для каждого из узлов, система не может динамически перераспределять для нужд приложения уже выделенные участки локальной по отношению к узлу памяти. В Windows 2003 это приводило к тому, что распределение памяти происходило за счёт ресурсов других узлов. Такое наблюдалось в тех случаях, когда поток, которому уже была выделена локальная память, нуждался в дополнительном распределении памяти, и такое распределение уже не возможно было сделать из локальных ресурсов NUMA-узла. Вследствие такого поведения, увеличивались задержки доступа к памяти, поскольку память являлась удалённой по отношению к работающему с ней процессору. Работа с удалённой памятью приводила к снижению производительности за счёт увеличения времени доступа примерно на 100ns. Фактически, по некоторым оценкам, стоимость доступа к удалённой памяти оказывается от 40% до — 300% больше, чем стоимость доступа к локальной памяти. Хотя эта стоимость существенно ниже стоимости доступа к физическим дискам. SQL Server очень часто используется в таких приложениях, которым свойственно большое число потоков. В этом случае, память должна делиться между большим числом потоков или процессов. Операционная система не способна самостоятельно оптимально распределить память, потоки и процессы. Это приводит к тому, что сервер баз данных на системе NUMA будет страдать от частого обращения к удаленным страницам памяти. Ещё одной проблемой становилась такая ситуация, когда процесс короткое время работал на неоптимальном по удалению от памяти узле, мог получать дальнейшее распределения памяти на этом же, неоптимальном узле. Такое распределение тоже снижало эффективность выполняемых операций.
В Windows Server 2003 необходимо особое внимание уделить настройке параметров устройств ввода-вывода и управляющего ими программного обеспечения. Это обусловлено тем, что в этой операционной системе возможности обслуживания ввода — вывода с учётом специфики NUMA были реализованы ещё не в полной мере. Если подсистема ввода — вывода постоянно взаимодействует с одним и тем же NUMA — узлом, снижение нагрузки на дисковую подсистему может быть достигнуто за счёт использования механизмов прямого доступа к памяти — DMA. Если же NUMA — узел должен взаимодействовать с внешней дисковой подсистемой, которая подключена к серверу посредством нескольких адаптеров, схема в вода — вывода будет многоканальной. Это потребует такой настройки программного уровня поддержки ввода — вывода, которая обеспечит обслуживание запросов на ввод — вывод по каждому каналу на тех узлах, которые располагают необходимыми для этих запросов ресурсами. В такой конфигурации прямой доступ к памяти не будет разделяться между несколькими узлами. В операционной системе реализованы возможности оптимизации многоканального ввода — вывода для многопроцессорных систем, но эти возможности должны быть предусмотрены производителем внешней дисковой подсистемы, который должен обеспечить необходимую поддержку для программного уровня.
Дисковая подсистема пока ещё является одним из ключевых компонентов производительности. Поскольку NUMA-like узел потенциально может иметь прямой доступ к дисковому вводу-выводу, операционная система может получить преимущество, обслуживая прерываниями локальных для узла устройств на локальных процессорах. В Windows Server 2003, операционная система умела получать топологию NUMA, но это ограничивалось получением числа узлов и памяти в каждом из узлов. В следующих версиях ситуация стала существенно лучше.

Windows 2008 и NUMA

В Windows Server 2008 алгоритмы распределения памяти были существенно доработаны и улучшены. Операционная система теперь старается распределять память на идеальном с точки зрения близости узле. Этот выбор будет сделан даже в том случае, если процесс начал выполняться на узле неоптимальном с точки зрения близости ресурсов. Если у оптимального узла нет свободной памяти, по таблице SRAT будет выбран наиболее близкий к идеалу узел. Такая политика распределения ресурсов повышает вероятность того, что процесс и его ресурсы будут обслуживаться на одном и том же узле или будет выбрана наиболее оптимальная альтернатива. Наверное, самым важным преимуществом Windows Server 2008 по отношению к Windows Server 2003 в поддержке NUMA является то, как оптимально они управляют близостью ресурсов. Улучшения планировщика в этом направлении позволили заметно оптимизировать размещение ресурсов в узлах NUMA.
Имеющиеся в операционной системе программные интерфейсы позволяют получать информацию о топологии NUMA из прикладных программ. Кроме того, через эти интерфейсы разработчики могут управлять привязкой задач к NUMA узлам. Приложения Windows могут получать информацию о NUMA через специализированный программный интерфейс (API). Вот несколько доступных для этого функций:

  • GetNumaHighestNodeNumber — возвращает число узлов;
  • GetNumaProcessorNode — возвращает номер узла данного процессора;
  • GetNumaNodeProcessorMask — возвращает бинарную маску процессоров данного узла;
  • GetNumaAvailableMemoryNode — возвращает размер доступной узлу памяти.

Приложения, адаптированные для использования возможностей предоставляемых интерфейсами NUMA , могут в полной мере воспользоваться масштабируемостью современных архитектур, и демонстрировать высокие показатели производительности. К таким приложениям относится SQL Server. Используя упомянутые выше API, высокопроизводительные приложения могут самостоятельно задавать или изменять привязку потоков к процессорам, чтобы они использовали ресурсы домена близости одного узла. Это особенно полезно, когда потоки сильно зависимы от одних и тех же структур памяти. Адаптированные приложения могут создавать множество потоков, и для этих потоков разработчики приложений смогут использовать возможности оптимизации распределений неоднородной памяти. За счёт этого, адаптированные приложения будут более эффективны в системах с числом процессоров более четырёх, и повышение числа процессоров будет позитивно сказываться на общей производительности.
В Windows 2008 добавилась возможность получения не только топологии процессоров, но и ввода-вывода. Например, можно узнать, на каких шасси NUMA-like системы размещены адаптеры шины (HBA). Имея такую расширенную информацию, можно заметно оптимизировать использование процессоров, настраивая привязку прерываний устройств к ближним процессорам. Это позволяет оптимизировать использование процессоров для обслуживания запросов ввода-вывода. Можно привязать обслуживающие ввод-вывод прерывания к наиболее оптимальным для производительной работы процессорам. В Windows 2003 ввод-вывод мог обслуживаться не тем процессором, который инициировал ввод-вывод. Таким образом данные могли попадать в память не того узла, через который к ним был получен доступ. Поэтому Windows 2008 старается обслуживать ввод-вывод и процедуры отложенного вызова (DPC) на процессорах того узла, где они были инициированы.
Кроме того, в Windows Server 2008 появился новый способ управления прерываниями. В Windows Server 2003 использовались прерывания в виде строки. Прерывание инициировалось устройством, путём подачи электрического сигнала на нужном штырьке (строка прерывания). Такая схема сильно затрудняла привязку нужного процессора к заданному устройству. В Windows Server 2008 устройство генерирует прерывание в виде сообщения, записывая значения данных по специальному адресу. С помощью MSI можно менять приоритет прерывания и для обслуживания прерываний стало возможно указывать конкретные процессоры. Мало того, если система оснащена PCI шиной с поддержкой расширения стандарта MSI-X, управлять обслуживанием прерываний ввода-вывода можно на уровне драйверов устройств. Делается это через специализированные программные интерфейсы Windows 2008. Т.о. прерывание ввода-вывода может быть сразу привязано к тому процессору, который инициировал этот ввод-вывод. Получить дополнительную информацию о поддержке NUMA операционной системой и специализированных функциях можно на сайте Майкрософт, в статье: «NUMA Support».
Диспетчер памяти операционной системы Windows 2008 при размещении невыгружаемого пула, т.е. тех участков оперативной памяти, которые распределяются для ядра и драйверов, учитывает топологию NUMA узлов. Он старается распределять их так, чтобы эти участки памяти выделялись на том NUMA-узле, на котором было инициировано это выделение памяти. Так, например, в случае возникновения необходимости распределения новой страницы PTE (таблица распределения страниц), она окажется на том узле, который инициировал распределение, а не на любом узле, как это было в Windows 2003.
В Windows 2008 диспетчер памяти всегда пытается распределять память потоку из пула наиболее подходящего узла, даже если поток в это время обслуживается другим узлом. Если же на идеальном узле недостаточно памяти, диспетчер проанализирует задержки доступа к другим процессорам и узлам, и на основании полученной информации выберет для распределения тот узел, задержки к которому меньше всего. Кроме того, если поток переходит в состояние ожидания доступа к данным или коду, диспетчер памяти переместит соответствующие страницы в список ожидания наиболее удачного для этого потока NUMA-узла.
Операционная система Windows Server 2008 выбирает оптимальный процессор на основе приоритетов, и если идеальный процессор недоступен, поток планируется на ближайшем к идеальному процессоре локального узла. Если все процессоры локального узла недоступны, операционная система планирует поток на самом ближнем к локальному узлу процессоре. Такая привязка потока к неоптимальному процессору называется мягкой. Привязку потока к процессору можно сделать жёсткой, чтобы впоследствии этот поток не мог быть привязан к другому NUMA узлу. В случае мягкой или жёсткой привязки, операционная система не может просигнализировать приложению, чтобы оно самостоятельно изменило привязку потока. Кроме того, операционная система не сможет самостоятельно перемещать данные из локальной памяти одного узла в локальную память другого узла. Такое перемещение можно осуществить из приложения. Кроме этого, данные могут быть перемещены естественным путём, за счёт механизма листания, который позволяет выгружать давно неиспользуемые страницы данных и по мере необходимости распределять их снова. В последнем случае высока вероятность того, что данные после повторного распределения окажутся в локальной памяти того узла, к которому относится запрашивающий данные поток.
Хотелось бы обратить внимание на то, что вполне вероятна ситуация, когда поток привязан к одному из процессоров NUMA узла, и ему необходимо выполнить распределение памяти, но для этого ему недостаточно локальной памяти этого узла. Важно понимать, что у администратора нет возможности повлиять на распределение памяти в рамках этого узла, и воспрепятствовать распределению потоку дальней по отношению к его узлу памяти. Только в самом приложении, за счёт использования соответствующих программных интерфейсов операционной системы, можно препятствовать тому, чтобы для потока кэшировалась дальняя память. Однако, при таком подходе велика вероятность того, что не занятая приложением дальняя память может быть помечена, как свободная, и будет задействована для других нужд. Вендоры не отмечают каких-либо существенных отличий в адаптации операционной системы к NUMA-like системе, относительно традиционной NUMA. Может возникнуть необходимость в изменении привязки ввода-вывода SQL Server к процессорным ядрам. Например, IBM для своих серверов серии «System x» рекомендует устанавливать адаптеры ввода-вывода (HBA) равномерно распределив их по всем шасси (как вариант: по 2 в каждом шасси). Если адаптеры ввода-вывода устанавливаются не во все шасси, то с помощью параметра глобальной конфигурации сервера «affinity I/O mask» лучше настроить привязку ввода-вывода для ядер тех узлов, в домене близости которых расположены имеющиеся адаптеры, т.е. в тех шасси серверов, куда физически адаптеры были установлены. По поводу привязки сетевых интерфейсов из разных шасси инженеры из IBM рекомендуют при планировании использования для нужд SQL сервера нескольких IP-адресов (например, для балансировки нагрузки или для обеспечения гарантированной производительности передачи данных пользователей и серверов приложений), и привязывать эти адреса к разным NUMA-узлам. Если планируется использовать только один IP-адрес, то никакой привязки делать не надо.

Windows 2008 R2 и NUMA

Начиная с Windows Server 2008 R2 добавлена возможность работы сервера с числом процессорных ядер больше 64-х. Это изменение напрямую повлияло на поддержку операционной системой многопроцессорных архитектур NUMA и non-NUMA. Наиболее заметным новшеством стало добавление ещё одной сущности — групп процессорных узлов. Если процессорных ядер больше 64 — число групп становится больше одной. По существу, с помощью механизма групп разделяются зоны планирования потоков, концентрируя в каждой группе возможности предыдущей версии Windows Server 2008. Это означает, что процесс может работать с несколькими группами одновременно, а поток может исполняться только в рамках одной группы. Кроме того, прерывание может вызываться только для процессоров той же группы. В рамках одной группы работа драйверов и приложений происходит точно так же, как это было в системах, где число процессоров не превышало 64. Это позволяет сохранить обратную совместимость для приложений, которые не были рассчитаны на работу с числом процессоров больше 64. Кроме этого, с помощью групп можно локализовать те аппаратные компоненты, работа которых зависит от места запуска связанных с ними программ, что может положительно сказаться на работе таких программно-аппаратных комплексов.
Каждая группа представляется статическим набором ядер, число которых не превышает 64. В Windows Server 2008 R2 администратору не предоставлено возможности влиять на формирование групп. Принадлежность ядер группе устанавливается во время начальной загрузки Windows, и каждое процессорное ядро может включаться только в одну группу. Операционная система старается минимизировать число групп. Кроме того, все логические процессоры ядра, и все ядра одного физического процессора тоже помещаются в одну и ту же группу. В одной и той же группе оказываются те процессоры, которые физически близки друг к другу. Группа может содержать процессоры одного или нескольких узлов архитектуры NUMA. Если в одном узле ядер больше 64-х, этот узел может быть поделён между несколькими группами. Если сервер non-NUMA, формирование групп основано только на ограничении в 64 ядра, а ядра по группам распределяются равномерно. Концепция групп процессорных ядер допускает горячее добавление процессоров. Если в системе есть сокеты, куда можно будет добавить процессоры, это будет учтено при создании групп, чтобы горячее добавление процессоров не привело к нарушению уже изложенных выше принципов формирования групп.
Каждый процесс или порождённые им процессы могут быть привязаны к неограниченному числу групп, однако в каждый момент времени одиночный процесс может принадлежать только одной группе. Разработчики операционной системы старались обеспечить наилучшую производительность приложений, потоки которых обслуживаются в одной группе (прежде всего, в целях поддержки унаследованных приложений). Кроме того, выбор процессорной группы для приложения может быть обусловлен близостью к тем аппаратным компонентам, к которым приложение обращается. Если приложение явно распределяет свои потоки по нескольким группам, потери производительности не произойдёт только при условии, что работа потоков из разных групп независима, например, приложение умеет выделять независимые секции данных для этих потоков. Иначе, производительность может оказаться существенно ниже варианта с обслуживанием потоков в одной группе.
В прежних версиях Windows, процесс или поток могли быть привязаны к указанному процессору, что гарантировало их исполнение на этом процессоре. В Windows Server 2008 R2 это стало немного сложнее, добавилась концепция групп. Вначале процессы не распределяются последовательно между процессорами групп. Процесс начинает исполняться в рамках только одной группы. Первый поток процесса будет исполняться в той группе, которую ему назначила Windows, если это не изменить из приложения (такая возможность существует и реализуется посредством интерфейсов). Каждый новый поток будет по умолчанию назначен в ту же группу, где обслуживается создавший его поток. Однако, при создании потока, приложение может определить группу, на которую он назначен.
В начале, все потоки процесса создаются в одной группе. Получить назначение в несколько групп может только системный процесс во время запуска системы. Все другие процессы должны быть явно назначены в несколько групп. Это им нужно для того, чтобы использовать все присутствующие в системе процессоры. Т.о. процесс может разрастись, и его потоки будут присутствовать во всех группах, но каждый поток единовременно может исполняться только в одной группе, хотя и может потом сменить её на другую. Смена группы потока отдаётся на откуп приложению, которое будет ответственно за привязку потока к правильной группе, считается, что разработчик может сделать это лучше. Если ничего не предпринимать, то каждое приложение будет удерживаться в рамках одной группы.
Системный пул потоков тоже был доработан и поддерживает теперь привязанную к узлу очередь. Это означает, что Windows будет планировать задачи из очереди узла для потоков этого узла. Если процесс в этом узле недоступен, Windows гарантирует, что задача будет обслужена в той же группе, из которой она попала в очередь. Такой механизм облегчает сохранение близости задачи приложения к её ресурсам. Однако есть несколько документированных исключений из последнего правила, которые выходят за рамки темы этой статьи.

NUMA I/O

Для настройки привязки прерываний устройств ввода-вывода к процессорам или узлам используется специализированный инструмент Майкрософт, который называется Interrupt-Affinity Policy Tool (IntPolicy). Привязка прерывания к одному процессору или группе в документации называется «Interrupt Affinity». Ранее для аналогичных целей использовался Interrupt-Affinity Filter (IntFiltr). Для устройства ввода-вывода IntPolicy позволяет выбрать одну из политик доступности данного устройства или задать маску привязки процессоров. Но даже без такой искусственной привязки, Windows Server 2008 будет стараться обслуживать ввод-вывод на тех процессорах и распределять для него память того узла, который является локальным для этого устройства ввода-вывода. Всё это стало возможно из-за усовершенствования механизма прерываний в Windows Server 2008. Пример использования утилиты IntPolicy для привязки прерываний сетевых интерфейсов можно найти в статье Майкрософт: We Loaded 1TB in 30 Minutes with SSIS, and So Can You. Следует помнить, что неверный выбор привязки прерываний может привести к деградации производительности.
Прерывание может применяться к процессорам только одной группы. В Windows Server 2008 R2 появилась возможность для PCI-адаптеров систем хранения динамически переадресовать прерывания и отложенные вызовы процедур. В документации эта функциональность названа соответственно: «Dynamic interrupt redirection» и «DPC redirection», где DPC это аббревиатура: «Deferred Procedure Call». Такой функционал получил название «NUMA I/O». Задача NUMA I/O — помочь многопроцессорной системе лучше секционировать рабочую нагрузку, повысить норму удачного попадания в кэш, и высвободить встроенные аппаратные средства межсоединений от передачи большого трафика ввода-вывода.
Windows Server 2008 R2 из коробки поддерживает работу сетевых адаптеров по протоколу Receive Side Scaling (RSS). Эта реализация RSS также адаптирована к NUMA. Данные из сетевых пакетов, которые посредством RSS распределяются между процессорами, будут обслуживаться теми же процессорными ядрами, которые обслуживают это TCP-подключение. Пакеты будут переданы на обслуживание физическим процессорам, без учёта гиперпоточности. Операционная система, балансируя средствами RSS входящие пакеты между процессорами, учитывает близость ресурсов узлов NUMA. Причём, при запуске адаптеры с более высокой пропускной способности получают больше процессоров, а несколько равноценных адаптеров поделят имеющиеся процессоры поровну. В системном реестре, в ветке «HKLM\system\CurrentControlSet\Control\class\{XXXXX72-XXX}\<номер сетевого адаптера>\», можно найти несколько ключей, которые показывают закрепление процессоров за адаптерами:

  • RssBaseProcNumber — номер первого процессора из диапазона выделенных RSS адаптеру процессоров.
  • MaxRSSProcessors — максимальное число процессоров для этого адаптера.
  • NumaNodeID — NUMA узел на котором адаптер может распределять память.

Hard-NUMA

В SQL Server поддержка архитектуры NUMA появилась, в ограниченном виде, начиная с SQL Server 2000 SP4. После этого, разработчиками следующей версии SQL Server 2005 была проделана очень большая работа по совершенствованию механизмов взаимодействия с аппаратной платформой и операционной средой. Были выполнены необходимые доработки компонентов ядра сервера баз данных, для того чтобы обеспечить поддержку новшеств, появившихся в SQL Server 2005. Одной из первостепенных задач при разработке компонентов ядра было повышение масштабируемости сервера за счёт использования возможностей, заложенных в современные аппаратные платформы многопроцессорных серверов. В SQL Server 2005 поддержка NUMA была добавлена без каких-либо оговорок. Эта поддержка подразумевает, что планировщики непривилегированного режима (UMS) автоматически группируются точно так же, как группируются в NUMA узлы физические процессорные ядра. Необходимую для этого информацию получает специальный программный слой ядра сервера баз данный — SQLOS. Для этих целей используются описанные ранее программные интерфейсы операционной системы.
Операционная система передаёт в SQL Server аппаратную конфигурацию NUMA, которую принято называть Hard-NUMA. SQL Server создает для каждого узла памяти свой логический планировщик, так, чтобы привязка планировщиков соответствовала аппаратной конфигурации. Изменить привязку планировщиков к ядрам процессоров можно с помощью системной хранимой процедуры sp_configure и параметра глобальной конфигурации сервера «affinity mask». Впоследствии SQL Server старается удерживать планировщиков за своими узлами, если только какой-нибудь процессор не выйдет из строя или не будет отключен.
Если с аппаратного уровня передаётся информация о наличии NUMA — системы, но в топологии присутствует всего один процессор, SQL Server поведёт себя так, как будто он имеет дело с компьютером без NUMA (Non-NUMA).
Для администратора баз данных полезным является тот факт, что при запуске службы SQL Server обнаруженная конфигурация NUMA выводится в виде сообщения в журнал ошибок SQL Server. По этим сообщениям администратор может судить о том, какая конфигурация процессорных узлов используется сервером баз данных в настоящий момент.
В случае с Hard-NUMA, при изменении параметра глобальной конфигурации «max server memory», память для экземпляра SQL Server будет равномерно поделена между доступными ему узлами. SQLOS старается так распределить страницы буферного пула между узлами Hard-NUMA, чтобы потом потоки обращались к страницам буферного пула преимущественно в домене близости локального узла, а не из памяти удалённого узла. Однако возникает необходимость контроля равномерности распределения памяти между узлами. Во время отработки сигнала вытеснения памяти в системе с Hard-NUMA на процесс управления буферным пулом SQL Server будет влиять физическое расположение страниц памяти. Т.е. по сути, это повлияет на то, попадут ли страницы в домен близости данного узла. Однако если страница памяти оказалась вне домена близости узла, к которому относится работающий с ней поток, меры к перемещению страниц буферного пула в ближнюю память предприняты не будут. Если для работы SQL Server выделены не все процессоры, это означает, что при запуске будет предпринята попытка равномерного разделения буферного пула между всеми выделенными экземпляру процессорными узлами. Чтобы не допустить использование под буферный пул одного экземпляра всей оперативной памяти, необходимо задать максимальный размер используемой экземпляром памяти.
Встроенный в SQL Server стабилизатор нагрузки может перемещать процессы от одного процессора к другому. Следуя логике доменов близости, привязка процесса подразумевает то, что он не будет перемещён на процессор, который относится к другому узлу, т.е. на процессор вне домена близости первоначального процессора.
Когда сервер баз данных работает с Hard-NUMA, системный процесс отложенной записи (Lazy Writer) будет присутствовать в одном экземпляре на каждом процессорном узле. Сделано это для того, чтобы работа с памятью была локализована внутри домена близости каждого узла, а также это способствует сокращению числа страниц вне домена близости. Процесс отложенной записи будет вызываться для обслуживания каждой явной и неявной контрольной точки, поэтому работа на NUMA-системе приведёт к увеличению частоты появления контрольной точки.
С помощью системной хранимой процедуры sp_configure можно на ходу менять привязку процессоров к экземпляру сервера баз данных. Т.о. можно отключить процессоры, процессорные узлы и обслуживающие их планировщики. В Hard-NUMA, пока хотя бы один планировщик активен, активным считается и весть NUMA узел. Узел может считаться отключенным, только если все приписанные к нему планировщики отключены. Используемая до этого узлом память будет высвобождена и перераспределена между другими узлами. Если перераспределение памяти нежелательно, необходимо соответствующим образом уменьшить максимальный размер выделяемой серверу памяти. Исполнители, которые работали с отключенным планировщиком, перейдут к активным планировщикам.
Есть небольшая хитрость в том, к какому узлу в Hard-NUMA будут привязаны планировщики с самыми первыми идентификационными номерами. Дело в том, что SQL Server учитывает тот факт, что нулевой физический процессорный узел после запуска операционной системы будет загружен сильнее других, и у него будет меньше других свободной физической памяти. Поэтому, SQL Server перемещает узел по умолчанию с нулевого физического узла на другой узел, вследствие чего основные структуры данных для SQL Server будут обслуживаться на узле, который не так сильно обременён задачами операционной системы. Однако это не означает, что нулевому физическому процессорному узлу память SQL Server распределяться не будет, ему достанется примерно одна треть от нормы.

SQLOS и NUMA

Чтобы лучше понять базовые принципы дизайна и взаимодействия компонент SQLOS в многопроцессорной среде, давайте немного углубимся в архитектуру SQLOS. Узлы процессоров являются подмножеством узлов памяти. Для наглядности, этот факт проиллюстрирован на Рисунке 1. Более подробно о месте узлов памяти в архитектуре SQLOS можно узнать в серии переводов статей Славы Окс на сайте sql.ru: Архитектура SQL Server.


Рисунок 1. Вариант упрощённой блок — схемы SQLOS

Как видно из рисунка, основным элементом управления процессорными ресурсами является узел памяти SQLOS. Все процессорные ядра, попадающие в один узел NUMA, объединяются в узел процессора SQLOS, который сопоставляется с одним узлом памяти SQLOS. Т.о. производительность сервера может быть оптимальной, если приложение способно ограничиваться ресурсами одного узла памяти, либо оно физически так секционировано, что каждой секции данных достаточно одного узла памяти. Это достигается за счёт сбалансированной з агрузки доступных экземпляру сервера аппаратных и программных ресурсов. Однако даже если удастся оптимально секционировать нагрузку по процессорным узлам, останется возможность конфликтов за ресурсы памяти для ядер одного процессорного узла. Такие конфликты возможны, когда ядра разделяют в своей работе одну и ту же область оперативной памяти или общий кэш сокета.
В идеале, нагрузка пользовательских приложений должна секционироваться по всем процессорам или узлам NUMA. В реальных условиях этого достичь очень трудно, особенно, если такое секционирование не было заложено на этапе первоначального дизайна приложения. Операционная система и сервер баз данных должны настраиваться таким образом, чтобы каждый поток попадал на отдельный процессор и на этом же процессоре должно обслуживаться прерывание отдельного сетевого интерфейса, а также порта обслуживания дискового ввода-вывода. Т.е. число сетевых плат и дисковых контроллеров (или HBA) должно равняться числу процессорных ядер, или хотя бы числу узлов NUMA. Продвинутые модели сетевых коммутаторов умеют поддерживать работу с множеством сетевых плат одного сервера. В качестве альтернативы большому числу сетевых плат можно использовать современные сетевые адаптеры, которые поддерживают Receive Side Scaling (RSS) и адаптированы для NUMA архитектур.
В реальных системах достичь равномерного распределения нагрузки между ресурсами сервера оказывается очень сложно. Вероятность обращений к ресурсам вне домена близости процессора оказывается достаточно высокой. Однако прогресс не стоит на месте, и современные архитектурные решения позволяют существенно снизить потери от обращений к ресурсам других узлов. В первую очередь это относится к архитектурам, где процессор обращается к памяти посредством собственного контроллера, по схеме точка — точка, а не через общую шину. Чаще всего, приходится жертвовать оптимизацией загрузки узлов и ядер. Это обусловлено не только сложностью такой оптимизации, но и то, что потери на межузловых взаимодействиях с каждым годом становятся заметно меньше, а встроенные возможности операционных систем и адаптированных к NUMA приложений становятся всё лучше и лучше. Однако стоит помнить, что в резерве остаётся возможность повысить эффективность за счёт приближения распределения нагрузки между ресурсами сервера к идеалу.
Некоторые структуры данных, такие как блокировки или планы исполнения запросов, были адаптированы к использованию на NUMA системах. Такие структуры контролируют своё местоположение и стараются оставаться на том же узле, где они были созданы. Например, блокировки связаны со структурами данных, которые используются для обслуживания транзакций. Если бы они не придерживались единого местоположения, это могло бы породить проблемы. К примеру, стала бы возможна ситуация, когда, несколько организованных координатором распределённых транзакций сеансов попадут для обслуживания на разные узлы. Получается, что один из сеансов должен будет завершить всю транзакцию и получить доступ ко всем структурам данных блокировок. Это приведёт к потерям производительности, поскольку структуры памяти блокировок рассредоточены по разным узлам. По той же самой причине контролирует своё местоположение и буферный пул, т.е. обслуживающие блокировки структуры памяти будут возвращены в тот список свободных буферов, который относится к тому узлу, который владеет выделяемой под структуры памятью.
Посмотреть, сколько памяти распределено на каждом узле, можно с помощью команды DBCC MEMORYSTATUS. Описание этой команды можно найти в статье Базы Знаний Майкрософт: «How to use the DBCC MEMORYSTATUS command to monitor memory usage on SQL Server 2005».
Давайте рассмотрим особенности работы SQL Server со страницами памяти и буферами, которые для процессорного ядра считаются удалёнными, т.е. принадлежащими другому узлу процессора SQLOS. Буферный пул SQL Server может находиться в трёх состояниях. Вначале происходит инициализация буферного пула. Следующее состояние некого переходного периода, когда удалённые относительно локальных процессорных узлов буферы возвращаются операционной системе. После переходного периода наступает устойчивое состояние, когда положение буферов в пуле стабилизируется относительно узлов. Восьмикилобайтный буфер относительно узла может быть внешним или локальным. Число внешних буферов можно определить с помощью счётчика производительности: SQL Server: Buffer Node: Foreign pages. Он показывает число страниц, не относящихся к страницам памяти узла процессора SQLOS, т.е. распределённых узлу из дальней о тносительно узла памяти.
В начальном состоянии буферный пул каждого узла увеличивается до достижения расчётного максимума. При этом SQL Server сортирует выделяемые узлу буферы по двум спискам. В лист свободных буферов попадают те буферы, которые в ближней к узлу памяти. Остальные буферы попадают в лист неблизких буферов. Чтобы сократить использование удалённой памяти, SQL Server не использует буферы из второго списка, Увидеть распределение буферов по разным типам можно с помощью команды DBCC MEMORYSTATUS. К сожалению, в административном динамическом представлении sys.dm_os_buffer_descriptors нет информации о том, какими являются буферы, внешними или локальными. После того, как число буферов достигнет требуемого значения, лист неблизких буферов сбрасывается. Буферы, попавшие в лист неблизких буферов, возвращаются системе. Пока этого не произойдёт, дальнейший «захват» памяти под буферный пул не выполняется. После сброса неблизких буферов, процесс повторяется. Когда буферный пул, после завершения переходной фазы, достигнет заданных величин, его состояние стабилизируется. Листы свободных буферов закрепляются за узлами окончательно, а лист неблизких буферов больше не используется. В таком состоянии, SQL Server пытается по возможности распределять местную память из листа свободных буферов. Если будет использована внешняя страница, это будет отражено в значениях представленного чуть выше счётчика Foreign pages. Т.е., несмотря на то, что SQL Server во время запуска пытается оптимизировать выделение буферов в соответствии с их близостью узлу, наличие внешних страниц не исключается. Мало того, все последующие распределения могут включать внешние страницы. Последующие сжатия и рост буферных пулов NUMA узлов также может приводить к увеличению числа внешних страниц. Для решения подобной проблемы, может оказаться полезным установить в параметрах глобальной конфигурации SQL Server одинаковых значений для максимального и минимального объёма оперативной памяти, выделяемой экземпляру сервера.
Дополнительную информацию можно найти в статьях:

Важно также помнить, что SQL Server использует для всех NUMA узлов один и тот же откомпилированный план исполнения запроса, но этот план базируется на использовании локальной памяти узла.
Выделенное Административное Соединение (DAC) тоже зависит от того, используется ли NUMA система. SQL Server просто создает в одном из узлов планировщик и узел памяти, необходимые для DAC, и привязывает порт DAC к этому узлу. Дополнительную информацию о поддержке SQL Server архитектуры NUMA можно найти в электронной документации Microsoft SQL Server Books Online: «Как SQL Server поддерживает архитектуру NUMA».

Soft-NUMA

В SQL Server 2005 появилась возможность создавать программные абстракции физических NUMA-узлов, которые могут переопределять число NUMA-узлов и процессорный состав узлов. Это предоставляет администратору баз данных возможность самостоятельно изменить порядок группировки процессоров, с учётом особенностей архитектуры сервера. Такие абстракции получили название Soft-NUMA. Создавать эти абстракции можно путём добавления специальных ключей в системный реестр операционной системы. Подразумевается, что в каждый такой узел может входить один или несколько процессоров.
Soft-NUMA влияет на компоненты SQLOS, которые адаптированы к NUMA. Ели сервер и платформа поддерживают NUMA, то для расщепления узлов Hard-NUMA можно использовать узлы Soft-NUMA. С помощью узлов Soft-NUMA можно перераспределить планировщики и привязать к узлам порты сетевых интерфейсов. Soft-NUMA позволяет вносить изменения только в работу планировщиков и сетевых интерфейсов SQL Server (то, что в англоязычной документации относится к I/O Completion Threads). Число и привязка узлов памяти остаётся неизменно. Это нужно учитывать, т.к. с помощью Soft-NUMA невозможно изменить привязку памяти к узлам Hard-NUMA. Кроме того, узлы Soft-NUMA не получают свой процесс отложенной записи, как это происходит с физическими узлами.
Убедиться в том, что число потоков отложенной записи не превышает числа узлов Hard-NUMA, позволяет следующий сценарий:

SELECT scheduler_id FROM sys.dm_os_workers AS w
JOIN   sys.dm_os_schedulers AS s
ON     w.scheduler_address = s.scheduler_address
AND    w.last_wait_type LIKE '%LAZYWRITER%'
Важным является также тот факт, что использование Soft-NUMA не изменяет поведение буферного пула (Buffer Pool Locality). Во время инициализации буферного пула происходит его распределение для Hard-NUMA или для Soft-NUMA. В случае с Soft-NUMA, получается, что память узла может резервироваться из локальной и условно удалённой относительно такого узла памяти. Расположение страниц памяти буферного пула не отслеживается, как это делается в Hard-NUMA. Т.е. возможна ситуация обращения к удалённой памяти, что потенциально может привести к снижению производительности. С другой стороны, удалённая для Soft-NUMA узла память может оказаться (и, скорее всего, окажется) локальной для узла Hard-NUMA. Как было описано выше, сервер старается минимизировать работу с удалёнными страницами, что способствует их высвобождению. А поскольку новые страницы распределяются с приоритетом у локальной по отношению к узлу памяти, ситуация с большим количеством страниц в удалённой памяти может постепенно улучшаться.
Если по каким — либо причинам нежелательно разделение буферного пула между узлами Hard-NUMA, есть возможность изменить это поведение. Заставить SQL Server работать со всей памятью, выделенной под буферный пул, как с единственным узлом памяти (плоский доступ), можно включив флаг трассировки 8015, который отключает поддержку NUMA в SQL Server. Подробности о таком режиме использования буферного пула можно найти в статье: How It Works: Soft NUMA, I/O Completion Thread, Lazy Writer Workers and Memory Nodes.
По сути, наиболее важными возможностями Soft-NUMA являются две вещи. С помощью Soft-NUMA можно жёстко задать какие процессорные ядра будут задействованы для обслуживания запроса, направленного на заданный порт сетевого интерфейса. Это будет относиться только к пакетам TDS, и не будет касаться активности базы данных и журналирования этих операций. Каждый узел Soft-NUMA может иметь ассоциированный с ним порт сетевого ввода-вывода. В соответствии с выбранными настройками сетевого протокола, такие порты могут прослушиваться на разных сетевых интерфейсах, что позволяет балансировать не только процессоры, но и сетевой трафик, используя для этого сегментацию локальной сети. Т.е. запросы клиентов будут утилизировать те процессоры, Soft-NUMA узел которых привязан к указанному клиентом порту в строке подключения. Вторая возможность, это увеличение с помощью Soft-NUMA числа потоков завершения ввода-вывода (I/O Completion), о чём пойдёт речь ниже.
Soft-NUMA узлы можно создавать и для систем с обычной архитектурой симметричного доступа процессоров к памяти (SMP). Например, для Non-NUMA серверов, которые оборудованы многоядерными процессорами, характерно совместное, конкурентное использование кэшей второго и/или третьего уровней. Узлы Soft-NUMA можно определять на основе близости процессоров к таким кэшам. В этом случае за счёт объединения в один узел нескольких процессорных ядер оптимизируется использование ими кэша третьего или второго уровня. Также это позволяет частично балансировать загрузку процессоров, распараллеливая рабочую нагрузку среди процессоров Soft-NUMA узла. К слову, можно отметить, что некоторые возможности балансирования нагрузки между процессорами присутствовали и в предшествующих SQL Server 2005 версиях. К таким возможностям можно было отнести: параметры глобальной конфигурации «max degree of parallelism» и «cost threshold for parallelism», подсказку оптимизатору MAXDOP, опцию сервера и запроса — «query governor cost limit», а также методы, подобные описанным в книге Кена Хендерсона «Профессиональное руководство по SQL Server: хранимые процедуры, XML, HTML», и реализованных в виде расширенной хранимой процедуры xp_setpriority.
В случае серверов Non-NUMA, наиболее значительный эффект Soft-NUMA может дать для оптимизации ввода-вывода. Кроме уже упомянутого выше выигрыша от оптимизации за счёт снижения конкурентного доступа к кэшу третьего или второго уровня, дополнительный выигрыш можно получить за счёт увеличения числа потоков ввода-вывода. Увеличение числа потоков происходит потому, что для каждого Soft-NUMA узла будет создан свой поток завершения ввода-вывода. В Non-NUMA сервере существует только один узел с точки зрения NUMA. Современные многоядерные процессоры способны содержать до шести и больше ядер. Т.о. потенциально можно увеличить число потоков ввода-вывода во столько раз, сколько ядер размещено на одном кристалле процессора.
Получить информацию о процессорах и Soft-NUMA узлах, которые доступны SQL Server, можно с помощью специального динамического административного представления (Dynamic Management Views), вызвать которое можно так:

SELECT * FROM sys.dm_os_schedulers;
GO

Это динамическое представление выводит по одной строке для каждого присутствующего в системе планировщика. Каждый планировщик закреплён за одним из процессоров. Представление позволяет диагностировать состояние планировщиков и определять меру их активности, для чего в представлении присутствует множество полей со счётчиками разнообразных событий планировщиков. Принадлежность планировщика к NUMA узлу можно определить по полю parent_node_id, а по полю cpu_id можно определить привязку к процессору. Значение равное 255 в последнем из этих двух полей говорит о том, что планировщик не привязан ни к одному из присутствующих в системе процессоров. Другие поля позволяют определить статус планировщика, т.е. является ли он активным или скрытым, поле is_online позволяет определить используется ли данный планировщик, поле current_workers_count позволяет определить, сколько исполнителей обслуживается этим планировщиком. Более подробную информацию об этом динамическом системном представлении можно получить в комплекте электронных материалов SQL Server 2008 Books Online, поставляемых с дистрибутивом. Ознакомьтесь со статьёй «sys.dm_os_schedulers (Transact-SQL)».
Для того чтобы проверить, обеспечена ли аппаратная или программная поддержка архитектуры NUMA (Hard-NUMA или Soft-NUMA) можно воспользоваться сценарием из блога Славы Окс (blogs.msdn.com/b/slavao), одного из разработчиков подсистем SQLOS:

SELECT CASE COUNT (DISTINCT parent_node_id)
WHEN 1 THEN 'Поддержка NUMA отключена'
ELSE 'Поддержка NUMA включена'
END
FROM   sys.dm_os_schedulers
WHERE  arent_node_id <> 32

Существует ряд ограничений на количество и состав входящих в Soft-NUMA узел процессоров. Эти ограничения зависят от архитектуры сервера и числа процессоров, входящих в аппаратный NUMA — узел. Так, для SMP архитектуры, нельзя допускать, чтобы один и тот же физический процессор входил в состав более одного Soft-NUMA узла. В архитектуре NUMA нельзя включать в один Soft-NUMA узел процессоры из разных NUMA узлов.
Описание Soft-NUMA узла создаётся вручную в системном реестре операционной системы. Для размещения конфигураций узлов необходимо создать специальный раздел:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration]В этом разделе создаются по одному подразделу для каждого Soft-NUMA узла, и эти подразделы должны называться Node0, Node1, Node2 и т.д. Например:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]В каждом разделе создаётся ключ-параметр с названием CPUMask, например:

«CPUMask»=dword:00000002
Последний пример задаёт шестнадцатеричное значение маски второго физического процессора. Значения маски процессоров устанавливается точно так же, как это делалось для глобального параметра конфигурации SQL Server, известного как: Affinity Mask. Значение этого параметра является целым числом размером в 4 байта и может быть установлено в окне редактирования параметров системного реестра в режиме десятичных или шестнадцатеричных значений.
Дополнительную информацию о том, как настраивать Soft-NUMA узлы, можно получить в электронной документации Microsoft SQL Server Books Online: «Как настроить сервер SQL Server на использование программной архитектуры NUMA».
После определения Soft-NUMA узлов, соответственно должен измениться и порядок закрепления планировщиков непривилегированного режима за этими узлами. Новый порядок закрепления планировщиков повлияет на порядок обслуживания этими планировщиками реальных, физических NUMA — узлов. Это может быть полезно, когда системное окружение SQL Server не позволяет равномерно распределить ресурсы узлам памяти и требуется внести коррективы, чтобы сделать такое распределение более равномерным. Администратор, определяя Soft-NUMA узлы, может постараться так перегруппировать процессорные узлы, чтобы сгладить возможные неравномерности распределения системой ресурсов между NUMA узлами.
Для того чтобы было легче понять, какими средствами обладает администратор в случае необходимости переопределения процессорных узлов, давайте рассмотрим жизненный пример, который можно найти в отчётах по эталонному тесту TPC-C. Информацию об этом тесте можно почерпнуть на сайте tpc.org. Речь идёт о результате в некластерной группе, показанном на сервере HP Integrity Superdome. Результат был опубликован 7 июня 2005г. На этом сервере удалось получить 1082203 tpmC.
Изучая полную версию отчёта, которую можно прочитать на странице краткого описания используемой в эталонном тесте аппаратно — программной конфигурации, можно понять как настраивалась Soft-NUMA. В отчёте легко обнаружить следующие дополнения, которые были внесены в системный реестр операционной системы тестируемого сервера, и которые показаны ниже:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
«CpuMask»=hex:0F,00,00,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
«CpuMask»=hex:F0,00,00,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
«CpuMask»=hex:00,0F,00,00,00,00,00,00
* * *
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node13]
«CpuMask»=hex:00,00,00,00,00,00,F0,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node14]
«CpuMask»=hex:00,00,00,00,00,00,00,0F
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node15]
«CpuMask»=hex:00,00,00,00,00,00,00,70
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node16]
«CpuMask»=hex:00,00,00,00,00,00,00,80

Звёздочками в представленном здесь фрагменте ключей системного реестра заменены ключи нескольких программных узлов, алгоритм создания которых можно легко понять, анализируя представленные в отрывке значения CpuMask.
Суть этого решения сводится к тому, что операционная система в процессе загрузки, следуя внутреннему алгоритму очередности использования процессоров, планирует задачи начиная с первого процессора. Если для SQL Server поменять порядок очерёдности выбора процессоров на обратный, тогда SQL Server не будет нагружать во время своего запуска те же процессоры, которые нагружаются операционной системой. Следовательно, после запуска всех служб, процессорные узлы будут более сбалансированно распределять между собой ресурсы, и система быстрее придёт к равновесному их распределению. Для этого, Soft-NUMA узлы переопределяют в представленном выше примере реальные NUMA — узлы таким образом, чтобы последняя четвёрка процессоров последнего NUMA — узла стала первым Soft-NUMA узлом. Следуя этой логике, предпоследний реальный NUMA — узел переопределяется во второй Soft-NUMA узел и так далее, плоть до пятнадцатого узла.
Определение пятнадцатого и шестнадцатого Soft-NUMA узлов немного отличается. Суть этих отличий в том, что первый процессор второго реального NUMA — узла выделен в отдельный программный узел и на этот узел средствами специального скрипта посылается задача исполнения контрольной точки для тестовой базы данных. Это требование определяется спецификой организации тестирования и реализацией, которая была избрана компанией Hewlett-Packard.
Продемонстрированный Вам пример наглядно показывает, как с помощью абстракций процессорных узлов можно повлиять на распределение ресурсов между процессорами и выделить отдельные процессоры или их группы для решения отдельных задач или для обслуживания отдельных процессов, например, процесса контрольной точки.
29 октября 2005 года компания HP представила ещё лучший результат, который был получен путём изменения схемы разбивки и перераспределения физических процессоров на узлы Soft-NUMA. Использовался сервер HP Integrity Superdome 64P c/s, на котором удалось получить 1231433 tpmC. Ниже представлены в сокращённом виде ключи системного реестра, определяющие конфигурацию программных узлов NUMA:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
«CpuMask»=hex:01
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
«CpuMask»=hex:02
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
«CpuMask»=hex:0c
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node3]
«CpuMask»=hex:30
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node4]
«CpuMask»=hex:c0
* * *
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node32]
«CpuMask»=hex:00,00,00,00,00,00,00,c0

Как видно, за исключением первых двух узлов, один из которых был оставлен для контрольной точки, все остальные программные узлы включают в себя по два процессора, чему соответствуют маски 0с и 30. И, как и раньше, избрана реверсивная схема распределения процессоров по узлам. Т.е. SQL Server получает процессоры для своих задач в обратном порядке. Этот подход основан на дроблении NUMA узлов на узлы Soft-NUMA, которые содержат в два раза меньше логических процессоров, чем в начале. Это позволяет сделать распределение ресурсов узлам ещё более равномерным, чем в предыдущем примере, и не нарушает при этом доменов близости аппаратного уровня. Кроме того, такое решение позволяет удвоить число потоков завершения ввода-вывода.

Soft-NUMA для Non-NUMA

Кроме NUMA, сегодня существует ещё несколько архитектур, которые направлены на реализацию масштабируемых многопроцессордер, или на кристалле процессора размещаются другие, общие для всех ядер элементы, например, контроллеры памяти. Такая компоновка сокета тоже вносит неоднородности в доступе к ресурсам, но это не представляется системе, как NUMA архитектура. Т.е. система не получает таблицу SRAT. По сути, Soft-NUMA становится единственным инструментом администратора, позволяющим указать SQL Server на присутствующую неоднородность. Давайте посмотрим, как это делается, на примерах.
22 ноября 2005г. сервер IBM eServer xSeries 460 16P c/s показал результат TPC-C равный 492307 tpmC. Сервер был оснащён двуядерными процессорами Intel Xeon Processor 7040 3.00GHz/2x2MB L2, каждое ядро которых использовало технологию гипертрейдинг. Таким образом, каждый физический процессор в операционной системе представлялся четырьмя логическими процессорами. Для того чтобы обозначить домены близости ресурсов каждого физического процессора, специалисты в IBM объединили четвёрки логических процессоров в Soft-NUMA узлы. Это позволяет учитывать реальное секционирование процессорных кэшей и оптимизировать число потоков завершения ввода-вывода.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
«CpuMask»=hex:00,00,00,00,00,00,00,0f
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
«CpuMask»=hex:00,00,00,00,00,00,00,f0
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
«CpuMask»=hex:00,00,00,00,00,00,0f,00
* * *
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node13]
«CpuMask»=hex:00,f0,00,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node14]
«CpuMask»=hex:0f,00,00,00,00,00,00,00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node15]
«CpuMask»= hex:f0,00,00,00,00,00,00,00

Когда SQL Server запущен на многопроцессорной конфигурации без NUMA, это практически единственный способ включить оптимизацию работы с неоднородными ресурсами, без которой работа сервера баз данных в подобной конфигурации могла бы быть неоптимальной и не учитывала бы аппаратные особенности сервера.
Другой пример, это сервер Unisys ES7000 Enterprise Server (8P), на котором была установлена операционная система Microsoft Windows Server 2003, Datacenter x64 Edition и Microsoft SQL Server 2005 Enterprise x64 Edition. 22 февраля 2006г. На этом сервере был представлен результат TPC-C равный: 347854 tpmC. Сервер был оснащён восемью процессорами Intel® Dual-Core Xeon® Processor 7041 3.0GHz, 2x2MB Lvl 2 Cache. Каждый процессор, как и в предыдущем примере, имел по два ядра на кристалл, и каждое ядро работало в режиме гипертрейдинга. Таким образом, на восьми кристаллах было размещено шестнадцать процессоров, которые из-за включения режима гипертрейдинга были представлены в операционной системе, как тридцать два логических процессора.
Для того чтобы сервер баз данных мог учитывать реальное секционирование процессорных кэшей, специалисты из Unisys создали представленную ниже топологию Soft-NUMA узлов, объединив в каждый узел по два процессорных кристалла, т.е. по четыре физических процессора или по восемь логических процессоров. Поскольку они посчитали достаточным число узлов равное четырём, можно привести полный набор соответствующих ключей реестра, которые были представлены в отчёте по тесту:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
«CPUMask»=dword:0xff
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
«CPUMask»=dword:0xff00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
«CPUMask»=dword:0xff0000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node3]
«CPUMask»=dword:0xff000000

К оглавлению

NUMA для большого числа процессоров

До сих пор мы рассматривали примеры, в которых задействовалось сравнительно небольшое количество процессорных ядер. Однако с выходом Windows Server 2008 R2, возможности операционной системы по обслуживанию большого количества процессорных ядер и, соответственно, программных узлов значительно выросли. Есть некоторые особенности настройки Soft-NUMA для систем, число ядер которых превышает 32. С этими особенностями можно ознакомиться в статье блога «SQL Server SQLOS team»: How to configure Soft-NUMA on a system with > 32 processors?
Следуя этим рекомендациям, например, для создания восьми soft-NUMA узлов на 48-ми процессорном сервере потребуется:

  1. Привязать процессоры:EXEC sp_configure 'show advanced options', 1
    RECONFIGURE
    GO
    EXEC sys.sp_configure N'affinity mask', N'-1'
    GO
    EXEC sys.sp_configure N'affinity64 mask', N'65535'
    GO
    RECONFIGURE WITH OVERRIDE
    GO
    EXEC sp_configure
    GO
    EXEC sp_configure 'show advanced options', 0
    RECONFIGURE
    GO
  2. Выполнить необходимые изменения в системном реестре:Windows Registry Editor Version 5.00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration]
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node0]
    «CPUMask»=hex:00,00,00,00,00,fc,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node1]
    «CPUMask»=hex:00,00,00,00,f0,03,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node2]
    «CPUMask»=hex:00,00,00,c0,0f,00,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node3]
    «CPUMask»=hex:00,00,00,3f,00,00,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node4]
    «CPUMask»=hex:00,00,fc,00,00,00,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node5]
    «CPUMask»=hex:00,f0,03,00,00,00,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node6]
    «CPUMask»=hex:c0,0f,00,00,00,00,00,00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node7]
    «CPUMask»=hex:3f,00,00,00,00,00,00,00

В этом примере выбрана реверсивная схема определения программных узлов, т.е. порядок логических узлов — обратный физическому порядку объединения ядер в процессорных сокетах. Есть одно отличие от рекомендаций в указанной только что статье. В статье рекомендуется использовать для ключей реестра тип QWORD, однако, мне удавалось добиться правильной работы узлов Soft-NUMA только при типе ключа: DWORD. Использование именно такого типа подтверждается и той информацией, которая следует далее, а также представлена в статье: «Как настроить сервер SQL Server на использование программной архитектуры NUMA». Более подробный пример можно по настройке Soft-NUMA можно найти в статье: «Пример настройки Soft-NUMA».
В SQL Server 2008 R2 появились возможность работать с числом процессоров больше шестидесяти четырёх. Для этого в этой версии СУБД добавлено понятие группы soft-NUMA узлов. Вот как это выглядит в опубликованном 2 ноября 2009г. компанией UNISYS результате теста TPC-E, выдавшем с помощью сервера Unisys ES7000 Model 7600R Enterprise Server (16s) результат: 2012.77 tpsE. В этой конфигурации использовалось 16 шестиядерных процессоров Intel Hex-core Xeon X7460. 96 ядер были распределены по узлам и сгруппированы следующим образом:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node0]
«CPUMask»=hex:3f,00,00,00,00,00,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node1]
«CPUMask»=hex:c0,0f,00,00,00,00,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node2]
«CPUMask»=hex:00,f0,03,00,00,00,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node3]
«CPUMask»=hex:00,00,fc,00,00,00,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node4]
«CPUMask»=hex:00,00,00,3f,00,00,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node5]
«CPUMask»=hex:00,00,00,c0,0f,00,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node6]
«CPUMask»=hex:00,00,00,00,f0,03,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node7]
«CPUMask»=hex:00,00,00,00,00,fc,00,00
«Group»=dword:00000000
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node8]
«CPUMask»=hex:3f,00,00,00,00,00,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node9]
«CPUMask»=hex:c0,0f,00,00,00,00,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node10]
«CPUMask»=hex:00,f0,03,00,00,00,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node11]
«CPUMask»=hex:00,00,fc,00,00,00,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node12]
«CPUMask»=hex:00,00,00,3f,00,00,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node13]
«CPUMask»=hex:00,00,00,c0,0f,00,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node14]
«CPUMask»=hex:00,00,00,00,f0,03,00,00
«Group»=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node15]
«CPUMask»=hex:00,00,00,00,00,fc,00,00
«Group»=dword:00000001

Тут мы видим две группы, в которых топология Soft-NUMA узлов повторяется.
Есть некоторые особенности привязки процессоров, если число ядер сервера больше 64-х. Для настройки SQL Server становятся неприменимы такие параметры глобальной конфигурации, как: affinity mask и affinity mask 64, поскольку с их помощью можно привязать не больше 64-х логических процессоров. Вместо них в SQL Server 2008 R2 появилась новая опция команды настройки сервера: ALTER SERVER CONFIGURATION SET PROCESS AFFINITY. Она даёт возможность привязать потоки процесса SQL Server к заданным NUMA-узлам или процессорам. Это позволяет управлять тем, какие процессорные группы будут доступны для обслуживания потоков процесса SQL Server 2008 R2. Например, вот так можно ограничить работу только первыми 64-мя процессорами:

ALTER SERVER CONFIGURATION SET PROCESS AFFINITY CPU=0 TO 63;В электронной документации к SQL Server рекомендуется включать автоматическую привязку, как это показано ниже:

ALTER SERVER CONFIGURATION SET PROCESS AFFINITY AUTOВместо логических процессоров можно привязывать сразу NUMA-узлы:

ALTER SERVER CONFIGURATION SET PROCESS AFFINITY NUMANODE=8, 12
Стоит отметить, что в SQL Server 2008 R2 Management Studio изменился интерфейс мастера свойств сервера. На закладке привязки процессоров и ввода-вывода процессоры теперь сгруппированы по NUMA-узлам. Причём, если сервер Non-NUMA, все процессоры группируются в одном NUMA-узле.
Более подробную информацию о привязке большого числа процессоров можно получить в статье: «Рекомендации по использованию SQL Server на компьютерах, которые имеют более 64 ЦП». О поддержке большого числа процессоров операционной системой написано в статье: «Supporting Systems That Have More Than 64 Processors».

Привязка портов сетевых интерфейсов к процессорам

Для обслуживания клиентских сетевых запросов в SQL Server 2000 существовала возможность использования нескольких портов сетевых протоколов TCP/IP или VIA. Эти порты могли открываться на одной или нескольких сетевых платах, а также, транслироваться для прослушивания на прокси-сервере. По умолчанию, использовались порт TCP 1433 и порт UDP 1434. Также, существовала возможность динамического выделения портов экземплярам SQL Server.
Начиная с SQL Server 2005, предлагается более гибкая система закрепления портов сетевых интерфейсов. Порты теперь можно закреплять за процессорами, выделенными для работы экземпляру SQL Server. Порты TCP/IP или VIA можно закрепить за Soft-NUMA узлами. Такая привязка процессорных узлов портам сетевых интерфейсов получила название NUMA affinity. Появление этой возможности позволяет административно балансировать сетевые запросы не только между процессорами разных экземпляров SQL Server, но и между процессорами одного экземпляра. Например, можно предоставить доступ к разным портам клиентам с разными типами запросов (отделить аналитические запросы от коротких транзакций). Этим можно снизить влияние продолжительных, тяжёлых запросов на запросы OLTP приложений.
Можно привязать один порт сетевого интерфейса ко всем узлам Soft-NUMA. Такая привязка используется по умолчанию и подразумевает, что SQL Server будет сам балансировать сетевые запросы между программными узлами. При этом, если запрос принят для обслуживания каким-либо узлом и для его исполнения достаточно процессоров одного узла, он будет обслуживаться на нём до своего завершения, а процессоры других узлов задействованы не будут.
Можно привязать каждому процессорному узлу свой, уникальный порт. Такая привязка позволяет обслуживать получаемые портом узла запросы рабочими потоками этого узла, что позволяет задействовать пары процессорный узел / порт для разных клиентских приложений. Это позволяет развести по разным узлам их рабочую нагрузку. В случае такой привязки портов к узлам, приложения получат возможность частично ограждать локальную память физических NUMA узлов и буферы доступа от использования другими приложениями, которые подключаются к серверу через другие порты. Кроме того, сбои в работе приложения или чрезмерная утилизация приложением процессоров не будет влиять на работу других приложений, которые работают с другими процессорами. Однако привязка портов подобным образом может породить перекосы в утилизации процессоров, входящих в разные Soft-NUMA узлы, а также, если какой-нибудь из узлов захватит большую часть физической памяти, другие узлы могут испытывать её нехватку. Это может привести к существенному падению производительности приложений, обслуживаемых через закреплённые за ним порты сетевых интерфейсов.
Можно комбинировать оба представленных выше способа привязки портов к процессорным узлам (один порт ко всем узлам и индивидуальные порты узлов), а также можно привязать к одному программному узлу несколько портов. Разработчик приложения, зная какие порты к каким программным узлам привязаны, теперь может осмысленно выбирать место подключения для решения разных задач. Важным в этом выборе является то, что программные узлы, привязанные к выбираемому для каждой задачи порту, будут иметь горячий кэш именно для нужной приложению задачи, что может способствовать повышению производительности приложений.
Для создания программной абстракции процессора или нескольких процессоров необходимо в системном реестре операционной системы создать специальный раздел, внутри которого определить ключи для каждой абстракции процессора или группы процессоров. Именно это было продемонстрировано в предыдущем разделе.
Давайте рассмотрим на примере образец использования привязки портов к процессорным узлам. Этот вариант настройки можно было увидеть в подробном описание теста TPC-C, опубликованного компанией Hewlett-Packard 22 мая 2006г. Тест выполнялся на сервере HP ProLiant ML370 G5 SAS 3.0 GHz Dual Core, использовались Microsoft SQL Server 2005 Enterprise x64 Edition SP1 и Windows Server 2003 Enterprise x64 Edition SP1. У сервера было всего два процессорных сокета, и в каждом был двуядерный процессор. Компания HP решила определить два NUMA-узла и привязать к каждому из них по одному порту сетевого интерфейса.
Давайте рассмотрим, как это выглядело в виде ключей системного реестра, подробное описание которого компания предоставила в отчёте. Первый, сокращённый пример ключа показывает, как к сетевому интерфейсу с адресом 130.168.211.101 привязывается порт 2000:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP1

Value 2
Name: TcpPort
Type: REG_SZ
Data: 2002

Value 5
Name: IpAddress
Type: REG_SZ
Data: 130.168.211.101

Ко второму интерфейсу с адресом 130.120.211.100 был привязан порт 2001:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP2

Value 2
Name: TcpPort
Type: REG_SZ
Data: 2001

Value 5
Name: IpAddress
Type: REG_SZ
Data: 130.120.211.100

Стандартный порт общения с SQL Server привязывался к адресу-заглушке 127.1:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP3

Value 2
Name: TcpPort
Type: REG_SZ
Data: 1433

Value 5
Name: IpAddress
Type: REG_SZ
Data: 127.0.0.1

Следующий ключ системного реестра указывает привязку портов к существующим NUMA-узлам:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll

Value 0
Name: TcpPort
Type: REG_SZ
Data: 2001[0x1],2002[0x2]


Такая привязка портов к процессорным узлам позволила очень простыми средствами балансировать нагрузку внешних клиентов между процессорами системы. Она позволяет более равномерно нагружать процессоры запросами от большого числа клиентов. В этом тесте, компания очень близко следовала рекомендациям из блога одного из разработчиков SQLOS Славы Окс, которые он изложил в статье: Тюнинг SQL Server 2005 для программной поддержки NUMA.
Ещё один интересный пример можно найти в описании теста TPC компании IBM, который был опубликован 12 июня 2006г., и для которого использовались сервера IBM System x3950. Для восьми узлов в системном реестре было определено девять разных портов, а один порт — 1433 был привязан ко всем NUMA-узлам:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll]

«TcpPort»="1433,1434[4],1436[2],1438[1],1440[8],1442[16],1444[32],1446[64],1448[128],1450[256]«

29 августа 2008г. компаний INSPUR Group был опубликован результат теста TPC-E, в котором использовалась система с сервером INSPUR NF520D2, использовавшая Microsoft SQL Server 2008 Enterprise x64 Edition на платформе Microsoft Windows Server 2008 Enterprise x64 Edition. В описании конфигурации можно обнаружить использование для указанных выше ключей системного реестра следующей привязки портов к четырём NUMA-узлам: 1433,2001[0x1],2002[0x2],2003[0x4],2004[0x8].
И напоследок, давайте вернёмся к описанному в предыдущей главе результату UNISYS от 2 ноября 2009г. Вот какую привязку узлов к портам использовали они в TPC-E для SQL Server 2008 R2.

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQLServer\SuperSocketNetLib\Tcp\IPAll]
„TcpPort“=»1401[0x1],1402[0x2],1403[0x4],1404[0x8],1405[0x10],1406[0x20],1407[0x40],1408[0x80],1409[0x100],1410[0x200],1411[0x400],1412[0x800],1413[0x1000],1414[0x2000],1415[0x4000],1416[0x8000],1433"
«TcpDynamicPorts»="«
„DisplayName“=»Any IP Address"

Чтобы убедиться, что порты сетевого интерфейса были успешно привязаны к процессорным узлам, можно открыть журнал ошибок SQL Server, в котором должны появиться строки, подобные этим:

2010-03-23 16:37:16.57 Server Server is listening on [ 'any' <ipv4> 1433].
2010-03-23 16:37:16.62 Server Server is listening on [ 'any' <ipv4> 2433].
2010-03-23 16:37:16.62 Server SQL Network Interfaces initialized listeners on node 0 of a multi-node (NUMA) server configuration with node affinity mask 0×0000000000000001.
This is an informational message only. No user action is required.
2010-03-23 16:37:16.59 Server Server is listening on [ 'any' <ipv4> 3433].
2010-03-23 16:37:16.59 Server SQL Network Interfaces initialized listeners on node 1of a multi-node (NUMA) server configuration with node affinity mask 0×0000000000000002.
This is an informational message only. No user action is required.

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

Максимальный уровень параллелизма

Само по себе разделение ресурсов по узлам NUMA ещё не гарантирует, что каждый отдельный запрос будет ограничиваться ресурсами только одного узла. Вполне возможна ситуация, когда в силу хороших возможностей для распараллеливания запроса, он может исполняться на процессорах нескольких NUMA узлов. Т.е. если для сервера будет существовать возможность создания такого числа потоков, которое превышает число ядер выбранного для запроса узла, то нагрузка будет размещена и на процессоры, которые не входят в число процессоров выбранного процессорного узла. Механизмы планирования задач операционной системы и SQL Server устроены так, что планирование потоков не привязывается жёстко к схеме процессорных узлов. Если в системе есть свободные процессоры, и не наложено никаких ограничений на число обслуживающих запрос потоков, то нет препятствий задействовать столько процессоров, сколько доступно для экземпляра SQL Server. Это поведение одинаково относительно Soft-NUMA или NUMA-узлов.
Если запрос распараллеливается на число ядер, превышающие число ядер в одном узле NUMA, это может стать причиной обращений к ресурсам из домена близости соседних узлов. Чтобы исключить такие проявления, можно ограничить уровень параллелизма на уровне запроса (используя подсказку оптимизатору) или на уровне сервера, задав отличное от нуля значение параметру глобальной конфигурации сервера: max degree of parallelism.
Пример использования ограничений параллелизма для локализации запроса в рамках одного узла представлен в статье: «Пример настройки Soft-NUMA».
В большинстве случаев, особенности реализации архитектур NUMA-like заставляют искусственно ограничивать параллелизм до числа потоков, не превышающего числа ядер одного шасси, или даже одного сокета. Однако некоторые нагрузки, характерные для задач обслуживания SQL Server, потенциально получают большой выигрыш от распараллеливания. Очень часто, хорошо распараллеливаемые задачи обслуживаются сервером одновременно с задачами, которым выгодна меньшая степень параллелизма. Если максимальная степень параллелизма не ограничена, может оказаться, что такие задачи, как например построение индексов, могут исполняться на процессорах из нескольких шасси. В таком случае, за счёт потерь на межсоединениях, подобные задачи могут работать на большом числе процессоров хуже, чем, если бы они исполнялись на меньшем числе процессоров одного шасси.
Есть уловка, позволяющая временно ограничить число выделенных экземпляру SQL Server процессоров на время выполнения операций обслуживания данных. Для этого можно с помощью системной хранимой процедуры sp_configure изменить маску привязки процессоров (affinity mask), оставив привязку экземпляра только к процессорам одного шасси. Изменение привязки не требует перезапуска службы. После завершения операций обслуживания, можно вернуть исходное состояние привязки.
Высокие показатели производительности и масштабируемости достигаются не только путём использования предоставляемых NUMA возможностей. В приложении баз данных необходимо уделять внимание секционированию кэшей данных и управляющих структур, чтобы их было легче распределять из локальных ресурсов NUMA-узла. Кроме того, необходимо учитывать негативное влияние блокировок больших областей данных, т.к. эти запрашиваемые приложением данные могут обслуживаться несколькими потоками, исполнение которых возможно на разных узлах.

Выводы

В SQL Server 2005 был добавлен новый, усовершенствованный и более приспособленный для работы на современных серверных платформах механизм планирования потоков и распределения ресурсов. В последующих версиях SQL Server 2008 и SQL Server 2008 R2 эти новшества получили дальнейшее развитие. Также, наиболее выигрышны по уровню поддержки NUMA версии операционных систем: Windows 2008 и Windows 2008 R2 Datacenter Edition. Последние версии СУБД и ОС позволяют использовать до 256 процессорных ядер. Всё это делает выбор этих версий более предпочтительным, чем их предшественники. Сегодня, разработчикам и администраторам приложений SQL Server для многопроцессорных архитектур предоставляются следующие выгоды:

  1. Обеспечен учет аппаратных особенностей современных многопроцессорных архитектур. Внутренняя оптимизация SQL Server позволяет в большинстве случаев обойтись без дополнительных настроек сервера и операционной системы для работы на многопроцессорных системах.
  2. Обеспечена возможность перераспределения нагрузки и процессорных ресурсов для достижения более высоких показателей производительности или для изоляции ресурсов разных приложений. Для этого не требуется программирования.
  3. Разработчики баз данных и приложений баз данных могут использовать программные интерфейсы операционной системы и сервера баз данных для исполнения операций манипуляции данными или операций модификации данных на заданных процессорах или процессорных узлах. Это могут быть реальные Soft-NUMA или NUMA-узлы.
  4. Секционирование памяти по NUMA узлам позволяет управлять актуальностью данных в кэше, причём, приложение может выбирать такой NUMA узел, кэш которого наиболее оптимален для текущего запроса.
  5. Привязка к узлам Soft-NUMA портов сетевых интерфейсов позволяет балансировать сетевую нагрузку и трафик в сегментах сети. Увеличение числа потоков завершения ввода-вывода за счёт увеличения числа узлов Soft-NUMA для многих типов рабочей нагрузки также позволяет поднять производительность исполнения запросов.
  6. Богатая коллекция административных динамических представлений позволяет организовать оперативную диагностику работы планировщиков непривилегированного режима, менеджеров памяти и других внутренних сущностей и объектов ядра сервера баз данных. Результаты этой диагностики могут использоваться для выбора наиболее удачной схемы утилизации процессорных ресурсов, чтобы наиболее равномерно распределять нагрузку между процессорами и добиться максимально равномерного распределения памяти.
  7. Абстракции процессорных узлов или групп процессоров, позволяют оптимизировать распределение задач по процессорам и балансировать сетевые запросы не только на серверах со специализированной процессорной архитектурой, такой, как NUMA, но и на массовых, бюджетных серверах с SMP архитектурой.

Ваши отзывы, пожелания и замечания направляйте, пожалуйста автору на адрес mssqlhelp@rambler.ru

Благодарности

В первую очередь, хочу сказать спасибо Ирине Наумовой, критические замечания и рекомендации которой помогли сделать материал понятней, а текст более «читабельным». Хочу поблагодарить сотрудников Майкрософт, Славу Окс — за то что вдохновил меня и помог с написанием первых вариантов этой статьи в 2006 году. Алексея Халяко — за экспертизу и продуктивную критику, а также за мудрые советы при написании этого варианта статьи. Владислава Щербинина — за то что он как крот искал в тексте плагиат и непростительные ошибки.