Часто системные администраторы и разработчики баз данных сталкиваются с крайне странной и пугающей ситуацией: на сервере баз данных установлены десятки или сотни гигабайт оперативной памяти, для СУБД MS SQL Server настроены щедрые лимиты, однако в Диспетчере задач Windows (Task Manager) процесс sqlservr.exe скромно отображает потребление в пределах 200–400 МБ. Возникает резонное подозрение: неужели SQL Server отказывается кэшировать данные, работает неэффективно и заставляет дисковую подсистему страдать? В рамках этой статьи мы подробно разберем, почему возникает эта иллюзия, как на самом деле работает менеджер памяти SQL Server, и как правильно настроить систему для максимальной производительности.
Начнем с анализа того, как операционная система Windows и стандартный Диспетчер задач измеряют потребление памяти процессами. Тот показатель, который мы привыкли видеть на вкладке «Процессы» в колонке «Память», представляет собой так называемый Private Working Set (частный рабочий набор процесса). Этот параметр учитывает только те страницы физической памяти, которые были выделены процессом через стандартный системный вызов VirtualAlloc и в данный момент находятся в физическом ОЗУ.
Однако архитектура MS SQL Server спроектирована под работу с огромными массивами данных. Чтобы избежать ситуации, когда операционная система принудительно сбрасывает кэш базы данных в файл подкачки (swapping) при нехватке ресурсов для сторонних процессов, разработчики Microsoft внедрили технологию Lock Pages in Memory (LPIM) (блокировка страниц в памяти).
Когда эта привилегия активна, менеджер памяти SQL Server выделяет оперативную память под свой буферный пул (Buffer Pool — основной кэш данных) через другой, более низкоуровневый системный API Windows — AllocateUserPhysicalPages. Память, выделенная с помощью этого метода, обладает уникальными свойствами:
sqlservr.exe.В результате мы наблюдаем парадоксальную картину: SQL Server может безраздельно владеть сотнями гигабайт ОЗУ, кэшируя таблицы баз данных, а Диспетчер задач в колонке «Память» будет показывать жалкие крохи (обычно те самые 200-400 МБ, которые ушли на служебные нужды, выделенные через стандартный VirtualAlloc). Проблема заключается не в том, что СУБД не «кушает» память, а в том, что базовый инструмент мониторинга Windows не предназначен для отображения заблокированных страниц физической памяти.
Для того чтобы получить достоверные данные о реальном объеме памяти, который удерживает SQL Server под свои нужды на данный момент, мы должны использовать специализированные инструменты. Рассмотрим два наиболее надежных метода: системные представления (DMV) и счетчики производительности Windows.
Самый надежный способ узнать правду — спросить об этом непосредственно саму СУБД. Для этого мы можем выполнить SQL-запрос к динамическому представлению sys.dm_os_process_memory. Подключимся к нашему серверу через среду Microsoft SQL Server Management Studio (SSMS) и выполним следующий скрипт:
SELECT
physical_memory_in_use_kb / 1024 AS [Общая физическая память MB],
locked_page_allocations_kb / 1024 AS [Заблокированная память (LPIM) MB],
large_page_allocations_kb / 1024 AS [Большие страницы MB],
process_physical_memory_low AS [Флаг нехватки памяти]
FROM sys.dm_os_process_memory;
Проанализируем результаты выполнения этого запроса:
Если мы предпочитаем использовать инструменты операционной системы, стандартный Диспетчер задач нам не помощник. Вместо него мы воспользуемся утилитой «Системный монитор» (Performance Monitor). Проанализируем ключевые счетчики производительности, относящиеся к группе объектов SQLServer:Memory Manager:
Если счетчик Total Server Memory практически равен счетчику Target Server Memory, это означает, что SQL Server полностью заполнил выделенный ему кэш и уперся в установленный нами лимит. Если же общая память значительно меньше целевой, значит, нагрузка на сервер в данный момент невелика, и СУБД просто не испытывает необходимости кэшировать больше данных.
Разберем по шагам, как активировать эту полезную технологию, чтобы гарантировать стабильную работу СУБД без нежелательного вытеснения кэша в файл подкачки.
Для того чтобы SQL Server получил право блокировать страницы физической памяти, учетной записи, от имени которой запущена служба СУБД (например, MSSQLSERVER или доменная сервисная учетная запись), необходимо делегировать соответствующее право в групповых политиках операционной системы Windows Server. Выполним следующие шаги:
Win + R, введите команду secpol.msc и нажмите Enter для открытия консоли «Локальная политика безопасности».NT Service\MSSQLSERVER для дефолтного экземпляра) и подтвердите изменения.Важное примечание по версиям и редакциям:
В редакции Enterprise поддержка LPIM включается автоматически сразу после предоставления прав в Windows. В устаревших версиях редакции Standard (например, SQL Server 2008 R2 и старше) требовалось дополнительно прописывать флаг запуска СУБД -T845. Однако начиная с версии SQL Server 2012 Standard (а также в SQL Server 2016 и выше), поддержка LPIM работает по умолчанию без необходимости прописывать какие-либо дополнительные флаги.
Некоторые администраторы считают, что раз SQL Server умеет динамически управлять памятью, то лимиты ставить не обязательно. Это глубокое заблуждение, которое может привести к критическому сбою всей инфраструктуры. Давайте разберем, почему это происходит.
Если мы активируем функцию Lock Pages in Memory и оставим параметр максимального размера памяти сервера (Max Server Memory) по умолчанию (равным огромному числу 2147483647 МБ), произойдет следующее:
Для предотвращения подобных сценариев мы рекомендуем руководствоваться следующими проверенными правилами расчета верхнего лимита памяти для SQL Server:
Сценарий 1. Выделенный сервер баз данных.
Если на сервере работает только SQL Server, операционной системе все равно требуется гарантированный резерв памяти. Рекомендуется использовать следующую формулу резервирования:
Сценарий 2. Совместное размещение SQL Server и сервера приложений (например, 1С:Предприятие).
В небольших и средних компаниях сервер приложений 1С и СУБД SQL Server часто разворачивают на одном физическом сервере. В такой конфигурации жесткое ограничение памяти критически важно! Процессы 1С (rphost.exe) имеют свойство нелинейно расходовать память под нужды пользователей. Если SQL Server займет всю память, процессы 1С начнут сбрасывать свои данные в файл подкачки, что моментально парализует работу сотен пользователей (время отклика интерфейса вырастет в разы). В таком сценарии лимит SQL Server должен рассчитываться так, чтобы серверу 1С и ОС гарантированно оставалось не менее 30-40% от общего объема физического ОЗУ.