17.1.23

Менеджер памяти SQLOS и SQL Server Buffer Pool

По материалам статьи Slava Oks: SQLOS's memory manager and SQL Server's Buffer Pool


В SQL Server 2005 менеджер памяти SQLOS состоит из нескольких компонент, таких как: Узлы памяти (Memory Nodes), Клерки памяти (Memory Clerks), Кэши памяти (Memory Caches) и Объекты памяти (Memory Objects). На Рисунке 1 изображёны компоненты менеджера памяти и их связи:

---------------- | Memory Object | ---------------- | | V ---------------- | Page Allocator | ---------------- / \ / \ \/ \/ --------------- --------------- | Memory Clerk | | Caches | --------------- --------------- \ / \/ \/ ---------------- | Memory Node | ---------------- Рис. 1


Memory Node

Узлы памяти (Memory Nodes) не являются клиентами Memory Manager. Это внутренние объекты SQLOS. Главная задача Memory Node в том, чтобы предоставить место для распределения памяти. Такие узлы состоят из нескольких программ, отвечающих за распределение памяти. Существует три основных типа таких программ. Первый тип - это программы распределения страниц памяти. Второй тип - программы распределения виртуальной памяти, использующие интерфейсы Windows VirtualAlloc API. Третий тип - это программы распределения Shared Memory (распределяемой памяти), которые полностью основаны на интерфейсах Window's file mapping API.
Чаще всего SQLOS использует программы страничного распределения памяти. Причина, по которой их называют программами распределения страниц, состоит в том, что они распределяют память из подмножества страниц SQLOS. Размер страницы - 8 КБ, такой же, как и размер страниц в базах данных SQL Server. Как Вы поймёте далее, это не простое совпадение.
Существует четыре программы для распределения страниц. Программа для распределения одиночных страницы, программа для распределения нескольких страниц, программа для распределения больших страниц и программа для распределения зарезервированных страниц. Программа распределения одиночных страниц может единовременно работать только с одной страницей. Программа распределения нескольких страниц, как Вы могли догадаться, обслуживает единовременно целый набор страниц. Программа распределения больших страниц используется для больших страниц. SQLOS и SQL Server используют большие страницы, чтобы минимизировать TLB (translation look aside buffer) присутствующий при доступе к активным структурам данных. В настоящее время большие страницы поддерживаются только в архитектуре IA64 или x64, если в системе не менее 8GB оперативной памяти. Размер большой страницы на IA64 равен 16 МБ. Программа последнего типа предназначена для распределения зарезервированных страниц, и может использоваться для распределения специального набора страниц, зарезервированных для критических положений, то есть когда SQLOS испытывает недостаток памяти. Рисунок 2 показывает узел памяти и его программы распределения.

-------------------- ------------- ----------------------- |Large Page Allocator|<------| Memory Node |----->|Reserved Page Allocator| -------------------- /-------------\ ----------------------- / | \ / | \ / | \ / | \ \/ \/ \/ -------------------- ---------------------- -------------------- | VM & SM Allocator | | Single Page Allocator| |Multi Page Allocator| -------------------- ---------------------- -------------------- Рис. 2

В настоящее время SQL Server не имеет динамически управляемого представления (DMV), которое показало бы набор всех узлов памяти и информацию об их программах распределения. DBCC memorystatus, о котором мы поговорим ниже, кажется наиболее близким по смыслу, но он представляет информацию об узлах центрального процессора, а не об узлах памяти. Но если вспомнить, что узлы процессоров являются подмножеством узлов памяти, станет ясно, что представленная DBCC memorystatus информация достаточна для понимания того, как распределяется память в системе.


Memory Clerks

Узлы памяти скрыты от использующих Memory Manager компонент. Если клиенту Memory Manager необходимо распределить память, он должен сначала создать Memory Clerk. Есть четыре типа Memory Clerk-ов: универсальное хранилище, кэш - хранилище, пользовательское хранилище и объектное хранилище. Последний тип несколько замысловат. Наряду со своими стандартными функциональными возможностями, Memory Clerk-и обеспечивают ещё и кэширование данных.
Можно определить понятие Memory Clerk как сборник статистики. Он поддерживает те же типы программ распределения, как и узлы памяти, а так же предоставляет возможность потребителям памяти большого объёма подключиться к инфраструктуре брокера памяти (автор опишет эту инфраструктуру в одной из следующих статей). У Memory Clerk-ов есть несколько глобальных переменных, поддерживаемых SQLOS. В SQLOS для потребителей средних и больших объёмов памяти лучше использовать отдельных, собственных клерков, чтобы облегчить понимание того, как происходит утилизация памяти этим компонентом. Инфраструктура Memory Clerk предоставляет возможность отслеживать и управлять объемом памяти, используемым компонентом памяти. Каждый процессорный узел имеет список Memory Clerk-ов, который мы можем безопасно просматривать во время работы. SQL Server имеет специальное DMV: sys.dm_os_memory_clerks, которое показывает информацию о клерке. Кроме того, сводная информация о клерке может быть получена из состояния памяти посредством DBCC команд.


Объекты памяти

Объект памяти SQLOS - это динамическая память, хип. Для распределения память объекту памяти требуется помощь Memory Clerk. Разработчики поддерживают три типа объектов памяти:

  1. Переменные объектов памяти - это постоянный хип (динамическая память).

  2. Приращение объектов памяти - маркированная и уменьшаемая динамическая память.
    Такая политика распределения очень удобна во время исполнения и трансляции процессов. Обычно оба описанных процесса происходят в две стадии. Первая стадия обрабатывает рост используемой памяти, а вторая обслуживает сокращение использования памяти. Если процесс изолирован, при освобождении памяти не будет вызываться ни один из деструкторов. Это существенно повышает производительность.

  3. Последний тип объекта памяти предназначен для фиксированного размера. Как Вы могли догадаться, компоненты могут использовать такой тип политики, когда нужно распределять объекты заданного размера.

Фиксированным размером для последнего типа объекта памяти является 8 КБ. Это такой же размер, как и у страницы SQLOS. Кроме того, это означает, что объект памяти мог быть создан из Memory Clerk посредством одной из программ распределения страниц (Это еще один чрезвычайно важный момент! Его нужно запомнить, пока автор не опишет SQL Server Buffer Pool), SQL Server запрашивает специальный DMV, чтобы получить все объекты памяти в его процессе: sys.dm_os_memory_objects.
Как Вы заметили, оба, Memory Clerk и DMV для объектов памяти, представляют колонку программы распределения страницы (page_allocator_address). Автор представил программу распределения страницы на Рисунке 1. Для распределения страниц, под прикрытием объектов памяти используются интерфейсы программ распределения страниц Memory Clerk-ов. Это полезно знать, когда Вы хотите подключиться к Memory Clerk-у и к DMV объекта памяти.
До сих пор автор описывал внутреннюю структуру менеджера памяти SQLOS. Теперь пришло время поговорить, как все это вписывается в SQL Server.


Buffer Pool

Теперь мы добрались до того места, где всё становится очень интересным. В этой главе всё, о чём уже говорил автор, включая управление памятью, должно встать на свои места.
Помните, что у SQL Server имеется два параметра настройки памяти, которыми Вы можете управлять посредством sp_conifigure. Это максимальный и минимальный размер занимаемой сервером памяти. Автор не уверен, знаете ли Вы, что эти две установки в действительности управляют размером общего буферного пула. Они не управляют общим количеством физической памяти, используемой SQL Server. В реальности невозможно управлять объемом памяти, используемым SQL Server, потому что могут существовать внешние компоненты, загруженные в серверный процесс.
После запуска SQL Server, в течение процедур инициализации выясняется сколько виртуального адресного пространства (VAS) нужно зарезервировать для использования под Buffer Pool. Решение это базируется на том количестве физической памяти (RAM), которое доступно в блоке. Если размер доступной физической памяти равен или больше чем размер VAS, её можно использовать, помня, что VAS - это ограниченный ресурс особенно на x86, где VAS составляет 256 МБ для внешних компонент плюс несколько потоков, которые установлены для SQL Server, и число которых нужно умножить на 512 КБ. Как Вы помните, 512 КБ - это размер стека потока в SQL Server. В заданной по умолчанию конфигурации с физической памятью большей чем 2GB, Buffer Pool потребует 256MB+256*512KB = 384 МБ памяти в VAS. Эту область иногда принято называть MemToLeave, но в действительности это не правильно. SQL Server мог бы ограничиться использованием этой части VAS, но автор далее продемонстрирует когда такого может не случиться. Вы могли вспомнить ещё один параметр, который иногда рекомендуют использовать, если SQL Server начинает выдавать ошибку: "Can't Reserve Virtual Address Space". Первые 256 МБ - это то, чем управляет параметр запуска сервера -g. Если Вы установите -g 512 МБ, то размер VAS, который BP не сможет использовать, будет равен 512MB+256*512KB = 640 МБ. По сути, не имеет смысла устанавливать параметр -g 256 МБ, поскольку это как раз то значение, которое применяется по умолчанию.
Как только BP определит необходимый размер VAS, он сразу будет задействован, и будет зарезервировано всё, что необходимо. Чтобы в этом убедиться, Вы можете контролировать с помощью системного монитора число виртуальных байт распределённых для SQL Server или можно воспользоваться представлением vasummary, о котором автор писал в предыдущих статьях. Если всё нормально, Buffer Pool не может получить одним куском больше памяти, чем приблизительно выдано VAS для SQL Server, и Вы увидите несколько больших зарезервированных областей. Это поведение существенно отличается от поведения многих других серверов, которые Вы, возможно, наблюдали. Иногда это воспринимают как утечку VAS в SQL Server. В действительности это поведение полностью соответствует дизайну.
Buffer Pool задействует страницы по требованию. В зависимости от востребованости внутренней памяти и состояния внешней памяти, будет определён получатель, объем памяти, и принято решение, что нужно задействовать до того, как память можно будет утилизировать. Постоянно происходит извлечение и перевычисление системной информации и потребителя листания. Запрашиваемая память не может превысить максимальную память, которая указана в параметре настройки сервера: max server memory. Даже если установит min server memory равным max server memory, Buffer Pool задействует эту память только по требованию. Вы можете наблюдать такое поведение, контролируя соответствующие сообщения в Профайлере.
Размер страницы для базы данных SQL Server равен 8 КБ. Buffer Pool - это кэш страниц данных. Следовательно, Buffer Pool оперирует страницами размером 8 КБ. Он задействует пока ещё свободные блоки памяти, и только порциями по 8 КБ. Если внешние компоненты решают заимствовать память из Buffer Pool, они тоже смогут получить блоки только размером 8 КБ. Такое поведение блоков не сохраняется после возвращения их в обычную память. Интересный факт? Это означает, что для компонент SQL Server использование Buffer Pool может осуществляться только под управлением менеджера памяти, и до тех пор, пока он распределяет буфера по 8 КБ (иногда страницы, распределенные для BP, называю захваченными). На Рисунке 3 показано взаимодействие SQLOS и Buffer Pool.

----------------- | Memory Node | ----------------- | | V ------------------------ | Single Page Allocator | ------------------------ | | V ----------------- | Buffer Pool | ----------------- Рис. 3

Менеджер памяти SQLOS может динамически настраиваться для использования специализированной программы распределения одиночных страницы. Это происходит во время запуска SQL Server, когда настраивается Buffer Pool с целью выбора программы для распределения SQLOS одиночных страницы. С этого момента Buffer Pool поддерживает все динамически распределенные одиночные страницы. Например, можно вспомнить, что объект памяти будет использовать для своих нужд по 8 КБ. Когда компонент создает объект памяти, распределение осуществляется программой SQLOS для одиночных страницы, которая использует BP.
При описании менеджера памяти автор упоминал, что каждый большой компонент имеет собственного Memory Clerk-а. Это означает, что Buffer Pool также имеет своего собственного Memory Clerk-а. Как же это возможно, если BP зависит он SQLOS Memory Clerk-а, а менеджер памяти SQLOS, в свою очередь, полагается на BP? Это обычная дилемма первичности курицы или яйца, которую можно часто наблюдать в операционных системах. Ключ к пониманию здесь в том, что Buffer Pool никогда не использует никаких программ SQLOS для распределения страницы. На него влияют только виртуальный и AWE интерфейсы SQLOS.

----------------- | Buffer Pool | ----------------- | | V ----------------------- | Memory Clerk (VM/AWE) | ----------------------- | | V ----------------- | Memory Node | ----------------- Рис. 4

Все компоненты SQL Server оптимизированы для распределений по 8 КБ так, чтобы они могли распределять память через программу SQLOS для распределения одиночных страницы и, следовательно, через Buffer Pool. Однако, бывают случаи когда компоненту нужны большие буферы. Если это происходит, такое распределение будет обеспечено узлом памяти программы распределения нескольких страниц или виртуальной программой распределения. Как Вы могли догадаться, память будет распределена за пределами Buffer Pool. Именно поэтому автор не любит термин MemToLeave, SQL Server в действительности распределяет память и за пределами этой области!


Buffer Pool и механизмы AWE

Описание менеджера памяти SQLOS и Buffer Pool было бы неполным без рассказа о том, как во всём этом может использоваться AWE. Действительно важно понять, как Buffer Pool распределяет свою память, когда в SQL Server задействованы механизмы использования AWE. Для начала вспомним, что когда в AWE режиме происходит распределение VAS и страниц физической памяти, работа BP зависит от интерфейса Memory Clerk-а SQLOS. Во-вторых, нужно иметь в виду ещё несколько важных отличий. Вначале BP резервирует VAS кусками по 4 МБ, вместо того, что бы зарезервировать "цельный" большой кусок. Это предоставляет возможность SQL Server высвобождать VAS, когда процесс её утилизирует (высвобождение было бы не возможно без включения через параметры сервера механизмов использования AWE, и разделения на куски). После этого распределяется вся требующаяся память, с использованием AWE. Как раз в этом поведение SQL Server 2000 сильно отличается от поведения SQL Server 2005, т.к. для BP в SQL Server 2000 была бы распределена вся доступная механизмам AWE память.
Buffer Pool является для сервера основной программой распределения памяти и в AWE режиме он распределяет память с учётом механизмов AWE. Это означает, что все распределения через программу SQLOS для одиночных страницы, будут осуществляется из страниц, распределенных через AWE. Про это очень часто забывают, поэтому автор хочет повторить ещё раз: когда сервер работает в AWE режиме, большинство его распределений осуществляются через механизмы AWE. По этой причине, если SQL Server работает в этом режиме, Вы не увидите приватных байт и увеличения используемой памяти.
Так как страницы данных зависят от адресации, то есть её включают, Buffer Pool может отобразить их внутри или вне VAS. Другие компоненты могут вести себя аналогично, если они не основываются на распределении фактических адресов. К сожалению, кроме BP сейчас не существует других компонент, которые могут воспользоваться механизмами AWE.


О чём мы поговорим далее

Автор пока ещё не закончил описание того, как SQLOS управляет памятью. Поговорить можно ещё о многом. В следующих статьях будет рассмотрен механизм кэширования, применяемый в SQLOS, и то, как утилизируется память. Также важным аспектом для последующего изучения станет изучение возможностей получения посредством команд DBCC информации состояние памяти и сравнение этого подхода с аналогичными возможностями DMV.
Автор понимает, что этот материал не прост для восприятия, и просит направлять ему все возможные вопросы, которые у Вас могут возникнуть, и ответы на которые помогут читателям более глубоко и подробно освоить тему настоящей статьи.
Если у Вас есть какие - либо замечания, автор также готов их выслушать. Это для него действительно важно, так как может внести коррективы в его последующие статьи.

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

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