Oracle mechanics

21.11.2010

ASMM в Oracle 10.2, online отключение в RAC окружении

Filed under: Диагностика системы (instance),memory management,Oracle,RAC — Игорь Усольцев @ 23:40
Tags: ,

Документация Oracle 10g R2 следующим образом описывает Automatic Shared Memory Management (ASMM) в части управления shared pool

… внутренний алгоритм настройки обычно не пытается уменьшить shared pool из-за наличия открытых курсоров (open cursors), фиксированных в памяти (pinned) PL/SQL пакетов и наличия SQL в различных стадиях выполнения, что делает невозможным нахождение гранул памяти, доступных для освобождения. Следовательно, алгоритм автоматической настройки выполняет только увеличение shared pool небольшими порциями, начиная с определённого размера и стабилизируя размер shared pool на оптимальном с позиции производительности уровне

Понятно, что получается, если один из автоматически управляемых компонентов может только увеличиваться (на примере Oracle 10.2.0.4, 2-node RAC, ASMM включен):

$ grep '__shared_pool_size' alert_instance1.log
__shared_pool_size       = 352321536
...
__shared_pool_size       = 1191182336
...
__shared_pool_size       = 1426063360
__shared_pool_size       = 1627389952
...
__shared_pool_size       = 8690597888
__shared_pool_size       = 9193914368
...
__shared_pool_size       = 12079595520
...
__shared_pool_size       = 12868124672

За пару лет время эксплуатации размер shared pool «автоматически» вырос с 300 МБ до 12 ГБ при общем размере SGA_TARGET = 20G

Посмотрим распределение памяти между автоматически управляемыми компонентами SGA

SQL>  SELECT  INST_ID, component, current_size, min_size, max_size
FROM    gv$sga_dynamic_components
WHERE   current_size != 0;

INST_ID    COMPONENT    CURRENT_SIZE    MIN_SIZE    MAX_SIZE
2        shared pool     12868124672  9546235904           0
2         large pool        16777216    16777216           0
2          java pool        33554432    33554432           0
2  DEFAULT buffer cache   8539602944  8539602944           0
1        shared pool     12868124672 12868124672           0
1         large pool        16777216    16777216           0
1          java pool        16777216    16777216           0
1  DEFAULT buffer cache   8556380160  8556380160           0

Прежде чем смотреть распределение выделенной памяти по компонентам shared pool,интересно отметить, что суммарный размер shared pool из обзора v$sgastat (см. ниже) не совпадает с реальным из v$sga_dynamic_components, показанным выше (текущий размер также можно увидеть по значению динамического параметра __shared_pool_size), что честно описано в Bug 4577426  V$SGASTAT may show misleading BYTES values larger than really allocated для версий Oracle 10.2.0.4-11.2.0.1

SQL> select inst_id, sum(bytes)
from gv$sgastat
where pool = 'shared pool'
group by inst_id
INST_ID    SUM(BYTES)
1         15904909088
2         15272406312

Однако это не мешает (хотя бы приблизительно) оценить размеры самых ёмких компонентов shared pool

SQL> select *
from gv$sgastat
where pool = 'shared pool'
order by bytes desc;
2    shared pool    free memory       8381608944
1    shared pool    free memory       4961505832
1    shared pool    sql area          3285569880
1    shared pool    KGH: NO ACCESS    2970889696
2    shared pool    KGH: NO ACCESS    2603302912
1    shared pool    CCursor           1426942048
2    shared pool    CCursor            903596776
2    shared pool    sql area           874789416
1    shared pool    sql area:KOKA      817362712
2    shared pool    sql area:KOKA      640229088
...

Прежде всего обращает внимание значительное количество свободной памяти (free memory): ~4GB на первом и ~8GB на втором инстансах, что соответствует 23% и 39% размера всей SGA! Но уменьшать shared pool и отдать излишки в область buffer cache, где дополнительная память может значительно уменьшит возросшие ожидания db file sequential read, как вышеописано в документации, Oracle 10g не может :(

Кроме того, судя по близким значения размеров shared pool на инстансах и сильно отличающимся областям свободной памяти, можно предположить, что в Real Application Cluster 10g предусмотрена синхронизация размеров shared pool между инстансами кластера при включенном ASMM (запрос в техподдержку пока остаётся без ответа) — неверное предположение, в описанном случае это было просто стечение обстоятельств

Назначение следующей значительной по размеру области разделяемого пула KGH: NO ACCESS объясняется в документе How To Prevent The Growth Of The Component ‘KGH: NO ACCESS’ In The Shared Pool When ASMM Is Enabled [ID 451960.1]

‘KGH: NO ACCESS’  относится к гранулам памяти (granules), находящимся в процессе переноса механизмом ASMM, т.е. областям памяти, которые в настоящее время перераспределяются между Shared Pool и Database Buffer Cache
Компонент памяти Shared Pool обозначаемый как ‘KGH: NO ACCESS’ используется в Buffer Cache

— определённый workaround разработчиков — возврат части памяти через специальную выделенную область неуменьшаемого shared pool. В том же документе даются рекомендации для предотвращения значительного роста KGH: NO ACCESS

1> Отключить ASMM
или
2> Установить минимальные размеры Shared Pool и Database Buffer Cache (параметрами shared_pool_size и db_cache_size) [т.е. ограничить пределы деятельности ASMM]

По совокупности фактов понятно, что размер shared pool неадекватно завышен и продолжает увеличиваться, отнимая необходимую память у buffer cache. Для стабилизации состояния без перезагрузки инстансов можно лишь зафиксировать минимальный размер buffer cache, например, установив параметр db_cache_size в текущее значение __db_cache_size

SQL> select a.ksppinm name,
 2  b.ksppstvl value,
 3  b.ksppstdf deflt,
 4  decode
 5  (a.ksppity, 1,
 6  'boolean', 2,
 7  'string', 3,
 8  'number', 4,
 9  'file', a.ksppity) type,
 10  a.ksppdesc description
 11  from
 12  sys.x$ksppi a,
 13  sys.x$ksppcv b
 14  where
 15  a.indx = b.indx
 16  and
 17  a.ksppinm like '\_\_%\_size' escape '\'
 18  /

NAME                 VALUE       DEFLT     TYPE DESCRIPTION
-------------------- ----------- --------- ---- -----------------------------------------------------
__shared_pool_size   12868124672  FALSE     6    Actual size in bytes of shared pool
__large_pool_size    16777216     FALSE     6    Actual size in bytes of large pool
__java_pool_size     16777216     FALSE     6    Actual size in bytes of java pool
__streams_pool_size  0            FALSE     6    Actual size in bytes of streams pool
__db_cache_size      8556380160   FALSE     6    Actual size of DEFAULT buffer pool for standard block

, т.е. ~ 8 ГБ в нашем случае. При этом в shared pool по прежнему останутся значительные объёмы неиспользуемой памяти (free memory)

Рестартовав инстансы, и по-прежнему не отключая ASMM, можно установить разумные с нашей точки зрения, нижние пределы Shared Pool и the Database Buffer Cache (перераспределив память в сторону buffer cache), но фактически это будет означать переход на полуавтоматическое управление, т.е. значительное ограничение, практически отказ от использования механизма Automatic Shared Memory Management :(

В этой ситуации разумным решением является отключение ASMM, но прежде оценим текущий размер автоматически управляемых буферов по максимальному используемому размеру для 2-х инстансов, чтобы правильно установить размеры буферов, которые ранее управлялись ASMM через параметры shared_pool_size, large_pool_size, java_pool_size, а остальное отдадим buffer cache

shared_pool_size = max(__shared_pool_size - "free memory" - "KGH: NO ACCESS") ~ 4.6 GB
large_pool_size = max(__large_pool_size) ~ 16 MB
java_pool_size = max(__java_pool_size) ~ 32 MB

Таким образом, остаётся при отключении ASMM нужно установить следующие значения параметров (не уменьшив текущих буферов SGA pools — т.е. с минимальным влиянием на текущую производительность бд)

*.db_cache_size=15G
*.shared_pool_size=5G
*.large_pool_size=16M
*.java_pool_size=32M

+ собственно, отключить ASMM, изменив динамический параметр sga_target=0 командой

SQL> alter system set sga_target = 0;

, что успешно получается выполнить на тестовых некластерных системах

Тест 1-й: устанавливаем нижние пределы автоматически управляемых разделов разделяемой памяти на обоих инстансах (на всякий случай), затем пытаемся отключить ASMM на первом инстансе

SQL> Alter system set db_cache_size = 8G scope=memory SID = '*';
System altered.
SQL> Alter system set shared_pool_size = 5G scope=memory SID = '*';
System altered.
SQL> Alter system set large_pool_size = 16m scope=memory SID = '*';
System altered.
SQL> Alter system set java_pool_size = 32m scope=memory SID = '*';
System altered.
SQL>Alter system set sga_target = 0 scope=memory SID = 'instanse1';

1-й инстанс надолго и странно «зависает» (instance hang?), не принимая внешних соединений по TCP/IP, однако допуская локальные соединения через IPC. В alert.log не отражается не только никаких ошибок, но и последняя команда Alter system set sga_target = 0. После нескольких минут ожидания отменяем последнюю команду

^C
Alter system set sga_target = 0 scope=memory SID = 'instance1'
*
ERROR at line 1:
ORA-02097: parameter cannot be modified because specified value is invalid
ORA-01013: user requested cancel of current operation

и рестартуем инстанс для возобновления нормальной работоспособности системы

$ srvctl stop instance -d mydb -i instance1
$ srvctl start instance -d mydb -i instance1

Очевидно, что-то сделано неправильно, хотя формально неясно, что было сделано не так :(

Ответ специалистов Oracle support

You aren’t going to be able to remove ASMM dynamically. The best way to do so in your case would be to do a rolling RAC outage and change each server independently while the others are still up.

Т.е. в нашем случае динамически отключить ASMM не получится, нужно отключать статически с поочерёдной перезагрузкой инстансов (rolling RAC outage) — нормальный вариант, позволяющий сохранять работоспособность системы (доступность бд) на протяжении внесения изменений

Тест 2-й: план логичен и прост — изменить параметры в spfile и по очереди рестартовать инстансы.

Однако

SQL> Alter system set db_cache_size = 15G scope=spfile SID = 'instance1';
 Alter system set db_cache_size = 15G scope=spfile SID = 'instance1'
 *
 ERROR at line 1:
 ORA-32017: failure in updating SPFILE
 ORA-00384: Insufficient memory to grow cache

неочевидная связь между изменение параметра в spfile (для использования при последующем перезапуске) и текущим состоянием памяти с юмором раскрывается в документе Updating DB_CACHE_SIZE With Alter System Scope=Spfile Fails [ID 357322.1]

SQL> alter system set db_cache_size=<new value> scope=spfile;

and surprisingly got

ORA-384 Insufficient memory to grow cache

Ошибка является проявлением бага и связана с функционирующим ASMM (установленным значением  SGA_TARGET > 0). Наблюдается на версиях от 10.1.0.2 до 11.2.0.2, т.е. imho будет исправлена только в будущих релизах, в качестве workaround’а предлагается временно (на время изменения db_cache_size) отключить ASMM дважды рестартовав инстанс

В итоге, учитывая, что на нашей инсталляции согласно рекомендациям Oracle, для управления службами (включая инстансы бд) используется SRVCTL и параметры хранятся в SPFILE, расположенном на ASM, был подготовлен следующий план отключения ASMM при условии непрерывной доступности кластерной бд

1. На всех инстансах из рабочего spfile создаются файлы параметров $ORACLE_HOME/dbs/initinstanceN.ora

SQL> create pfiles from spfile;
File created.

2. В созданных файлах $ORACLE_HOME/dbs/initinstanceN.ora устанавливаются параметры, отключающие ASMM

*.db_cache_size=15G
*.shared_pool_size=5G
*.large_pool_size=16M
*.java_pool_size=32M
*.sga_target=0

3. С использованием SRVCTL штатно останавливается первый инстанс

[oracle@rac-node-01 ~]$ srvctl stop instance -d mydb -i instance1

4. Стартуем первый инстанс, используя модифицированный pfile с помощью SQLPLUS

$ sqlplus / as sysdba
Connected to an idle instance.
SQL> startup pfile='$ORACLE_HOME/dbs/initinstance1.ora';

проверяем, что первый инстанс успешно зарегистрирован Oracle Clusterware

SQL> !crs_stat -t
Name           Type           Target    State     Host
------------------------------------------------------------
...
ora.instance1.inst application    ONLINE    ONLINE    rac-node-01
ora.instance2.inst application    ONLINE    ONLINE    rac-node-02
...

5. С использованием SRVCTL штатно останавливается второй инстанс

[oracle@rac-node-02 ~]$ srvctl stop instance -d mydb -i instance2

6. Стартуем второй инстанс используя модифицированный pfile с помощью SQLPLUS

SQL> startup pfile='$ORACLE_HOME/dbs/initinstance2.ora';

проверяем, что второй инстанс успешно зарегистрирован Oracle Clusterware

SQL> !crs_stat -t
Name           Type           Target    State     Host
------------------------------------------------------------
...
ora.instance1.inst application    ONLINE    ONLINE    rac-node-01
ora.instance2.inst application    ONLINE    ONLINE    rac-node-02
...

7. С любой из нод пересоздаём spfile из файла параметров (pfile)

SQL> create SPFILE='+DG1/mydb/spfilemydb.ora' from pfile='$ORACLE_HOME/dbs/instance2.ora';
File created.

На этом шаге был основной вопрос: не блокирует ли Oracle Clusterware при запущенных и зарегистрированных инстансах бд запись в spfile, определённый в конфигурации кластерной бд и зафиксированный в кластерном регистре (cluster registry)

$ srvctl config database -d mydb -a | grep SPFILE

8. Поочерёдный рестарт всех инстансов с использованием SRVCTL

[oracle@rac-node-01 ~]$ srvctl stop instance -d mydb -i instance1
[oracle@rac-node-01 ~]$ srvctl start instance -d mydb -i instance1
[oracle@rac-node-02 ~]$ srvctl stop instance -d mydb-i instance2
[oracle@rac-node-02 ~]$ srvctl start instance -d mydb-i instance2

В принципе, в последнем шаге необходимости нет, выполняется чтобы убедиться в том, что изменения вступили в силу и в дальнейшем будут использоваться по умолчанию

План был одобрен техподдержкой Oracle и успешно выполнен

Ссылка по теме How to relocate an spfile from one ASM diskgroup to another on a RAC environment? [ID 342234.1]

Документация Oracle 11.2 также не очень оптимистично оценивает возможность динамического изменения режима ASMM

Для включения ASMM лучше установить желаемое ненулевое значение SGA_TARGET перед стартом бд. Динамическое изменение SGA_TARGET с нулевого до ненулевого значения может не дать желаемого результата, поскольку shared pool может быть невозможно уменьшить…

2 комментария »

  1. Привет!

    Относительно того откуда может получаться «значительное количество свободной памяти (free memory) в разделяемом пуле» да еще и с ORA-04031 в результате, можно почитать у Tanel Poder в посте ORA-04031 errors and monitoring shared pool subpool memory utilization with sgastatx.sql

    odenysenko

    комментарий от odenysenko — 06.01.2011 @ 11:55 | Ответить

    • спасибо, статья и скрипты хорошие, в описанном случае до ORA-04031 не доходило ни разу, ни до, ни после отключения ASMM
      кстати, там же Tanel Poder пишет об особенностях выделения памяти в subpool’ах:
      «..ни разу не видел, чтобы один subpool возвращал память другому subpool’у, т.е. в случае, если один subpool аллоцировал всю зарезервированную память сразу после старта инстанса по причине какой-то стартовой активности приложений, другие subpool’ы могут остаться небольшими по размеру в течение всего существования инстанса»
      что, вероятно, прямо связано с особенностями «безвозвратного» выделения памяти shared pool при использовании ASMM

      комментарий от Игорь Усольцев — 23.01.2011 @ 12:34 | Ответить


RSS feed for comments on this post. TrackBack URI

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

Блог на WordPress.com.

%d такие блоггеры, как: