Мы продолжаем цикл статей по анализу производительности SQL Server.

Ранее мы рассмотрели вопросы связанные с анализом проблем перегрузки процессоров (http://blogs.technet.com/b/sqlruteam/archive/2014/01/12/server.aspx). Также как и ранее, при анализе проблем с памятью, мы будем следовать алгоритму приведенному в предыдущей статье (http://blogs.technet.com/b/sqlruteam/archive/2014/01/08/sql.aspx).
Анализ проблем с памятью имеет некоторые особенности, поэтому мы его разобьем на несколько статей.

Перечень наиболее часто встречающихся проблем связанных с памятью:

  • SQL Server "съел" всю память (или очень много), что начало "угнетать" ОС и приложения работающие на ней.
  • Вы установили ограничения на память потребляемую SQL Server и ему стало не хватать выделенной памяти.
  • Какое-либо приложение потребило слишком много памяти и SQL Server-у стало не хватать выделенной памяти
  • "Перекос" в потреблении памяти каким-либо компонентом SQL Server, что стало причиной "угнетения" других компонентов SQL Server.

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

Итак начнем рассмотрение первой причины - "SQL Server "съел" всю (или очень много) память, что начало угнетать ОС и приложения работающие на ней."

В качестве ограничения накладываемого на рассмотрение - в блоге мы будем рассматривать только 64-битовую версию SQL Server и ОС, поскольку 32-битовых остается все меньше и меньше. 

Для начала надо установить факт, что ОС действительно не хватает памяти и эту память потребил SQL Server. Выполнить это можно посмотрев счетчик Memory: Available Bytes. Он показывает сколько памяти осталось у ОС для распределения приложениям и внутреннего использования. Возникает справедливый вопрос:"Каким образом приложение может потребить много памяти и угнетать ОС?". Причин тому может быть несколько:

  • Утечка памяти в приложении или драйвере, особенно утечка невыгружаемого пула.
  • Установка завышенного значения параметра "max server memory" в свойствах SQL Server и  права "Lock Pages in Memory" для учетной записи от которой работает SQL Server.

Во всех остальных случаях ОС способна сама решать вопросы распределения памяти на основе заложенных алгоритмов. (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366525(v=vs.85).aspx, http://blogs.msdn.com/b/tims/archive/2010/10/28/pdc10-mysteries-of-windows-memory-management-revealed-part-one.aspx, http://blogs.technet.com/b/askperf/archive/2007/02/23/memory-management-101.aspx, http://msdn.microsoft.com/en-us/library/windows/hardware/gg463344.aspx).

У нас (Microsoft) есть принятая норма на остаток памяти который должен оставаться доступным для распределения ОС. Эта норма составляет 5% от объема установленного RAM, т.е. в свободном распределении у ОС должно остаться не менее 5% от общего объема RAM установленного на сервере. И как бы это число не казалось большим (особенно при больших объемах установленной памяти), лучше этого правила придерживаться.
Что будет предпринимать ОС, когда приложения потребят слишком много оперативной памяти? При достижении порога Memory: Available Bytes в 100...50 MB Windows включит агрессивный сброс (trimming) рабочих наборов процессов, включая системные драйверы, что тут же приведет к резкому снижению производительности всех компонентов ОС. В данной статье мы не будем рассматривать эти вопросы, возможно мы рассмотрим их в будущем.

Каким образом рассчитать правильное значение "max server memory"?

Здесь есть два случая:

  • Некластеризованный SQL Server, либо кластеризованный SQL Server в режиме Актив/Пассив .
  • Кластеризованный SQL Server работающий в режиме Актив/Актив.

Расчет памяти для некластеризованного, либо кластеризованного SQL Server работающего в режиме Актив/Пассив .

  1. Остаток для ОС - 5%. В нашем случае это около 25 GB (500*5%).
  2. Память под ядро SQL Server (различные *.exe, *.dll, *ocx и пр. модули), SQL heap, CLR. Обычно это до 500 MB, хотя за счет CLR это может быть и больше.
  3. Пямять под кэши "Worker thread", рассчитываемая по формуле (512+(NumCpu-4)*16)*2 MB. В нашем случае это (512+(64-4)*16)* 2MB = 2944 MB (около 2.7 GB).
  4. Итого под "max server memory" остается:  500 - 25 - 0.5 - 2.7 = 471.2 GB. Т.е. размер Буферного пула (при таком значении "max server memory") может вырасти до 471 GB.  
  5. Для версии SQL 2012 и далее "max server memory" включает в себя SQL heap и частично CLR.

Особенно актуален это расчет, если вы используете "Lock Pages In Memory" В этом случае завысив это число или оставив его по умолчанию (что обозначает - любой объем) вы можете поставить ОС в довольно неприятное положения, которое приведет к агрессивному триммированию рабочих наборов и, как следствие, резкому замедлению работы системы.

Расчет памяти для кластеризованный SQL Server в режиме Актив/Актив.

При расчете необходимо учитывать, что пункты 2, 3 и 4 должны быть удвоены, и при использовании права учетной записи SQL Server "Lock Pages In Memory", вам необходимо подобрать не только "max server memory", но и "min server memory", что бы в случае переката обоих SQL Server на один узел вы не забрали всю память у ОС.

В данном случае на сервере установлено 500 GB оперативной памяти и 5% должно быть около 25 GB. Каким бы большим не казалось это цисло, но чем больше на сервере процессоров и памяти, тем (как правило) более ресурсоемкие задачи он выполняет и для их решения ему требуются большие ресурсы.

Как видно из рисунка (в данном случае), остаток памяти на сервере составляет около 7 GB, что не соответствует нашим рекомендациям. 

  

Далее нам необходимо понять, имеет ли SQL Server достаточный запас памяти, часть которого можно освободить в пользу ОС. Для ответа на этот вопрос необходимо проанализировать счетчики производительности SQL Server.

Давайте сначала выясним сколько памяти потребил SQL Server. Для этого надо знать, использует или нет SQL Server право учетной записи SQL Server "Lock Page In Memory", Выяснить это можно из свойств учетной записи, а можно косвенно, через счетчики Performance Monitor. Дело в том, что если право учетной записи SQL Server "Lock Page In Memory" не установлено, то вся (или почти вся) используем��я память будет частью рабочего набора процесса sqlservr.exe. Если же это право установлено, то при этом (скрыто) используется механизм AWE (Address Windows Extension) и основная память под Буферный пул будет размещена за пределами процесса sqlservr.exe.

Как видно из рисунка ниже, размер рабочего набора процесса составляет всего около 4 GB, что значительно меньше общего объема потребленной памяти.

Посмотрим, сколько всего памяти использует SQL Server. Он использует 500 857 024 (около 480 GB) для распределения на Буферный пул, Процедурный кэш, кэш Worker Thread и для некоторых не значительных потребителей. А отсюда можно сделать вывод, что в данном случае SQL Server использует "Lock Pages in Memory".

Далее приступим к поиску ответа на вопрос:"Можно ли отобрать часть памяти у SQL Server, не нанося ему вреда?"

Во первых, давайте проверим какое количество запросов обслуживается из Буферного пула (без выполнения физических чтений). Как мы видим из рисунка ниже по тексту около 100% (точнее 99,972%) запросов выполняются из буферного пула (при пороговом значении данного счетчика не менее 92%), что дает нам надежду на наличие избытка памяти у SQL Server.

Следующим счетчиком, который рекомендуется посмотреть является SQL Server: Page Life Expectancy. Он контролирует время жизни страниц в Буферном пуле. Пороговое значение 300 секунд. В данном случае мы видим среднее значение около 221000, что почти в 700 раз больше порогового. Это укрепляет нас в мысли, что ресурсы есть.

Окончательный ответ нам поможет дать счетчик SQL Server: Lazy Writes/sec, отображающий как часто срабатывает процесс Lazy Writer. Мы знаем, что это процесс активируется тогда, когда у SQL Server заняты около 75% выделенных буферов. Его задача выполнить фиксацию данных и очистить буферы. Для систем имеющих значительный запас памяти этот счетчик должен быть близок к нулю. Как мы видим это так.

Из всего вышесказанного можно сделать вывод: SQL Server имеет достаточный объем памяти и может "поделиться" ей с ОС. Отбирая память у SQL Server (уменьшая "max server memory") необходимо контролировать выше описанные счетчики и определить тот порог, ниже которого уменьшать объем памяти нельзя.

 

Александр Каленик, Senior Premier Field Engineer (PFE), MSFT (Russia)