null

Как Oracle память транжирил

    В Oracle 11g появилась система AMM (Automatic Memory Management) и свойство MEMORY_TARGET, и казалось бы вот он - способ регулировать потребление памяти Oracle. Однако структура потребления памяти инстансом Oracle несколько сложнее. Его можно выразить подобной диаграммой Венна:

    Расмотрим ее на примере Oracle 11g + Solaris 10.

   С точки зрения Oracle

    Идентифицировать потребление памяти со стороны Oracle выполняется с помощью служебных view V$PROCESS и V$PROCESS_MEMORY - по процессам, V$SGASTAT и V$PGASTAT - кумулятивно для SGA и PGA соответственно.

SQL> SET linesize 80;
    COLUMN pid FORMAT 999999;
    COLUMN spid FORMAT a7;
    COLUMN program FORMAT a25;
    SELECT pid, spid, program, pga_used_mem, pga_alloc_mem, pga_max_mem FROM v$process;

    PID SPID    PROGRAM                   PGA_USED_MEM PGA_ALLOC_MEM PGA_MAX_MEM
------- ------- ------------------------- ------------ ------------- -----------
      1         PSEUDO                               0             0           0
      2 5370    oracle@oracle (PMON)            742968        826392      826392
      3 5372    oracle@oracle (PSP0)            724800        809976      809976
      4 5374    oracle@oracle (VKTM)            721552        809976      809976
<...>
     25 6046    oracle@oracle                  9447644      11688952    49568760
     26 6316    oracle@oracle                  3643596       5200888     7560184
     27 6318    oracle@oracle                  2509260       3759096     3759096
     28 6243    oracle@oracle                  1706816       2776056     4348920
<...>


    В колонке PROGRAM мы видим имя запущенной программы, в случае (PMON) это например фоновый процесс монитора процессов, если же оно не указано, значит этот процесс обслуживает клиентское соединение. В колонках pga_used_mem, pga_alloc_mem, pga_max_mem (pga_freeable_mem не показана) - соответственно выделенная программой память из сегмента PGA. Отметим, что это верно только для конфигурации с Dedicated Process - в случае для общих пулов (Shared Pool Process) память выделяется процессами из SGA.
    
    Память PGA делится на 4 категории: "SQL", "PL/SQL", "OLAP" и "JAVA". Посмотреть разделение по категориям можно в view V$PROCESS_MEMORY для процесса с PID 25 можно так:

SQL> select category, used, allocated from v$process_memory where pid = 25;

CATEGORY              USED  ALLOCATED
--------------- ---------- ----------
SQL                  17496     103912
PL/SQL              298336     796184
Freeable                 0    1376256
Other                         9412600


    Как видим, большая часть памяти отведена под категорию Other.

    Суммарный объем потребляемой памяти можно получить например так:
    COLUMN component FORMAT A30
    SELECT component, current_size, min_size, max_size
        FROM v$memory_dynamic_components;

Solaris уполномочен заявить

Потребление памяти с точки зрения операционной системы (и соответственно меня как ее системного администратора) выглядит несколько иначе. Тут можно выделить такие факторы:

  •   При выделении памяти она только резервируется в пространстве swap (оно включает в себя как доступную оперативную память минус DISM-сегменты, ядро, и зарезервированные железом области, так и дисковый своп) - это называется Virtual Size (VSZ), тогда как реальное выделение физической оперативной происходит при первом обращении к ней - это называется Resident Set Size (RSS).
  • Некоторые типы сегментов, такие как сегмент кода разделяемой библиотеки, или DISM-сегменты, используемые СУБД под SGA разделяются, то есть одна и та же физическая память отображается в разные процессы, и поэтому простое суммирование полей SZ и RSS вывода утилиты ps бесполезно.
  • Кроме собственно PGA, серверные процессы Oracle могут использовать память внутри стандартной библиотеки C, кроме того требуется для каждой разделяемой библиотеки создавать собственный сегмент данных, для потоков держать стеки. Все это создает дополнительные, неучтенные расходы.  


    Подробный анализ потребляемой памяти со стороны Solaris выполняется посредством утилиты pmap. Собрать pmap для всех процессов Oracle, можно например так (потребуется оболочка bash, так как она поддерживает [[]] и оператор =~):

    ( ps -eo pid,rss,vsz,comm |
        while read PID RSS VSZ COMM
        do
            if [[ $COMM =~ "ora" ]]; then
                echo --
                echo $PID $VSZ $RSS
                pmap -x $PID;
            fi
        done ) > /tmp/pmap-collect.out

    Для каждого из процессов она соберет карту его сегментов и выразит потребляемую ими память в килобайтах. Чтобы просуммировать показатели по множеству процессов, я реализовал утилиту pmapsummary:
    pmapsummary.py {-r|-v} [-s no|only|once|all] [-c COL1,COL2] [-S SORTCOL] [pmap-collect.out]
    pmapsummary.py -h
        -r для RSS (Resident Set Size)
        -v для VSZ (Virtual Size)
        -s - как считать общую память (no - игнорировать, only - показывать только ее,
                once - считать для одного процесса, all - считать для всех процессов )
        -c - какие колонки показывать
        -S - по какой колонке сортировать
                
    Колонки:
        ANON - анонимная память
        HEAP - куча
        DISM - intimated shared memory (SHM)
        MMAP - устройства и файлы, отображенные с помощью mmap
        CODE - программный код бинарного файла и разделяемых библиотек
        DATA - сегменты данных бинарного файла и разделяемых библиотек
        STK - стеки потоков
        TOTAL - все вместе

Кто прав?

    Сравним вывод pmapsummary (первая строка соответственно RSS, а вторая VSZ) и служебных view СУБД для одного процесса:

    PID SPID    PROGRAM                   PGA_USED_MEM PGA_ALLOC_MEM PGA_MAX_MEM
------- ------- ------------------------- ------------ ------------- -----------
    34 9167    oracle@oracle                  2992524       4414456     5200888

   PID     ANON     HEAP     DISM     MMAP     CODE     DATA      STK    TOTAL NAME
  9167     4080      840   516096        8   199448     1912      160   722544 oracleorcl (LOCAL=NO)
  9167     4584      848   790528        8   229992     2880     1184  1030024 oracleorcl (LOCAL=NO)


    И для всего сервера:
COMPONENT                      CURRENT_SIZE   MIN_SIZE   MAX_SIZE
------------------------------ ------------ ---------- ----------
shared pool                       301989888  289406976  301989888
large pool                          4194304    4194304    4194304
java pool                           4194304    4194304    4194304
streams pool                        4194304    4194304    4194304
SGA Target                        524288000  524288000  524288000
DEFAULT buffer cache              201326592  201326592  213909504
<...>
PGA Target                        281018368  281018368  281018368
ASM Buffer Cache                          0          0          0


NAME                                          VALUE UNIT
---------------------------------------- ---------- ------------
aggregate PGA target parameter            281018368 bytes
aggregate PGA auto target                 185757696 bytes
global memory bound                        56203264 bytes
total PGA inuse                            74612736 bytes
total PGA allocated                       108959744 bytes
maximum PGA allocated                     205782016 bytes
<...>

   PID     ANON     HEAP     DISM     MMAP     CODE     DATA      STK    TOTAL NAME
  --->    88704    40200   516096      408   199448    62792     4512   912160 <--- total
  --->   115984    40504   790528      408   229992    95016    38304  1310736 <--- total


    Как видим, SGA target и размеры DISM не совпадают, а вот размер "total PGA allocated" в целом соответствует лишь анонимной памяти, выделенной процессами Oracle. Ну и никак не учитываются кучи и сегменты данных процессов, использующие немалые объемы памяти. Для систем со большим количеством процессов это может приводить к значительным накладным расходам, а значит желательно конфигурировать СУБД в режиме Shared Process Pool.

 


pmapsummary.py

К списку статей

 

Интересуюсь по большей части системным анализом программного обеспечения: поиском багов и анализом неисправностей, а также системным программированием (и не оставляю надежд запилить свою операционку, хотя нехватка времени сказывается :) ). Программированием увлекаюсь с 12 лет, но так уж получилось, что стал я инженером.

Основная сфера моей деятельности связана с поддержкой Solaris и оборудования Sun/Oracle, хотя в последнее время к ним прибавились технологии виртуализации (линейка Citrix Xen) и всякое разное от IBM - от xSeries до Power. Учусь на кафедре Вычислительной Техники НИУ ИТМО.

See you...out there!

http://www.facebook.com/profile.php?id=100001947776045
https://twitter.com/AnnoyingBugs