Восстановление Oracle RAC в деталях: подводные камни

Восстановление кластера Oracle RAC в деталяхПервое, о чем следует сказать в начале обсуждения процедуры восстановления в Oracle RAC – мы опустим восстановление носителя (media recovery). В действительности процедура восстановления носителя в кластере ничем не отличается от процедуры восстановления носителя в версии Oracle с единственным экземпляром. Вы берете резервную копию базы данных и файлы журнала повторений, и применяет те записи повторения, которые должны быть применены. А так как восстановление в Oracle выполняется в два этапа, совершенно неважно, что для восстановления придется синхронизировать файлы журналов из разных экземпляров.



Конечно же, есть пара весьма интересных деталей. Например, необходимость слияния (логического) всех файлов журнала означает, что при создании физической резервной базы данных для системы Oracle RAC, только один из резервных экземпляров сможет читать записи повторения и выполнять слияние. (Это не так плохо, как кажется, потому что один экземпляр может передавать записи повторения другим экземплярам точно так же, как версия Oracle с единственным экземпляром может выполнять параллельное восстановление.)

Наиболее важным аспектом в процедуре восстановления является восстановление экземпляра (instance recovery) – в конце концов, одним из достоинств RAC является высокая надежность и тот факт, что «система в целом» успешно преодолевает выход и строя экземпляра (или машины, на которой он выполняется). Поэтому стоит поближе посмотреть, как выполняется это восстановление.

Разные экземпляры постоянно обмениваются друг с другом сообщениями. Поэтому, если один экземпляр исчезнет, остальные обнаружат это очень быстро. В этом случае они все начнут состязаться за приобретение единственной блокировки восстановления экземпляра (Instance Recovery, IR), и экземпляр, которому удастся ее получить, выполнит восстановление экземпляра Oracle, потерпевшего аварию.

Одна часть работы связана с восстановлением изменений, которые были выполнены в блоках кэша аварийным экземпляром, и откатом неподтвержденных транзакций. Другая часть связана с реконструированием ведущих ресурсов, которыми владел аварийный экземпляр, и очисткой всех ссылок на него из GRD. И третья часть связана с «перебалансировкой» GRD из-за изменения размера кластера и невозможности использовать прежний алгоритм хэширования для поиска ресурсов.


Перебалансировка


Способ перераспределения ведущих ресурсов постоянно изменяется от версии к версии Oracle, но некоторая его часть остается неизменной с версии 9i. Oracle хранит очень небольшую карту «логических» и «физических» экземпляров и в периоды устойчивой работы кластера, логическому экземпляру N будет соответствовать физический экземпляр N.

Когда экземпляр «выпадает» из кластера, Oracle просто перераспределяет связи между оставшимися физическими экземплярами и логическими, а затем создает заново утерянные ведущие ресурсы на физическом экземпляре, начавшем восстановление. Благодаря такому подходу отпадает необходимость пересоздавать все ресурсы, но это означает, что владение ресурсами распределяется уже не в равных долях.

Возможно, что потом в дело вступит вторичный механизм, и ведущие ресурсы будут перемещены на другие узлы в соответствии с представлениями о справедливом распределении в кластере из N–1 узлов, но сразу после выхода узла из строя они окажутся на физическом экземпляре, начавшем восстановление.

Возможно имеет смысл упомянуть, что в отношении ресурсов BL Oracle использует алгоритм хэширования, опирающийся на единицу измерения по 256 блоков (в 11.2). Каждый файл с данными делится на фрагменты по 256 блоков и владельцем всех блоков внутри фрагмента назначается один и тот же экземпляр. Это означает, что в процессе сканирования таблиц каждый запрос, читающий сразу несколько блоков, с большой долей вероятности будет охватывать блоки, принадлежащие единственному экземпляру – особенно если используются локальные табличные пространства, которые оперируют в границах 1 Мбайта.

Немного сложнее должен выглядеть алгоритм перераспределения ресурсов BL при добавлении экземпляра в кластер – особенно, когда кластер невелик – но, похоже, что при переходе от числа экземпляров N–1 к числу экземпляров N каждый экземпляр передает новому узлу владение каждым N-м фрагментом. Это не соответствует обычному шаблону владения, но обеспечивает достаточно справедливому перераспределению с минимумом разрушений.


В процедуре восстановления есть два ключевых момента. С одной стороны, она выполняется полностью автоматически (и, если вам повезет и вы выполнили соответствующие настройки, аварийный экземпляр так же автоматически будет перезапущен). С другой стороны, перестройка и перебалансировка GRD приостанавливает экземпляры на короткое время – невозможно заранее точно сказать, сколько времени это займет, в идеальном случае – не больше нескольких секунд.

Теневые ресурсы и прошлые образы играют интересную роль в восстановлении. Oracle может проверить все теневые ресурсы на оставшихся узлах, чтобы восстановить образы ведущих ресурсов с аварийного экземпляра – этот этап вносит, пожалуй, самый большой вклад в период времени, на который происходит приостановка – и в процессе восстановления ведущих ресурсов может удалить любые ведущие ресурсы (на любом экземпляре), хранящие блокировки только для
аварийного экземпляра, исключая ресурсы BL с монопольными блокировками которые, возможно, требуют восстановления.

Выполняя восстановление, Oracle может сократить объем работ, связанных с применением записей из журнала за счет использования прошлых образов (Past Images), которые, как известно, являются самыми свежими копиями блоков и могли бы быть записаны на диск, если бы другой экземпляр не затребовал их по сети. То есть, всякий раз, обнаружив запись повторения для блока, идентифицируемого как прошлый образ, Oracle может пропустить запись, если ее номер SCN меньше номера SCN последнего изменения прошлого образа. Этот прием помогает уменьшить время, необходимое на восстановление, но вы все еще будете наблюдать сеансы, ожидающие доступа к блокам, закрепленным процессом восстановления.

 

Последовательности

Остаток этой статьи будет посвящен более конкретным примерам проблем, с которыми вы можете столкнуться, и знакомству с различными функциональными возможностями исследования аномалий, характерных для RAC. Нет никаких особых причин, почему я выбрал последовательности для исследований – просто они позволяют быстрее и проще достичь результатов, которые я хотел бы продемонстрировать. Для начала мы избавимся от пары типичных ошибочных представлений о последовательностях, далее исследуем внутреннюю реализацию последовательностей, порождающую некоторые проблемы в RAC и затем посмотрим, как следует использовать один из распространенных методов работы с последовательностями в Oracle Real Application Clusters (RAC).

Последовательности Oracle можно использовать разными способами, но чаще всего они служат источниками уникальных, монотонно возрастающих целых чисел, если создаются с применением синтаксиса по умолчанию:

create sequence test_sequence;

Если с помощью пакета dbms_metadata прочитать полное определение этой последовательности из словаря данных, вы увидите следующие важные особенности, которые следует учитывать при переходе на RAC: 

select
dbms_metadata.get_ddl(‘SEQUENCE’,’TEST_SEQUENCE’,user) defn
from dual;
DEFN
--------------------------------------------------
CREATE SEQUENCE «TEST_USER».»TEST_SEQUENCE»
MINVALUE 1 MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER
NOCYCLE

Обратите внимание на предложение CACHE 20 (вместо числа 20 у вас может быть любое другое положительное целое число или все предложение может быть заменено словом NOCACHE) и предложение NOORDER. Размер кэша может по-разному сказываться на работе последовательности в версии Oracle с единственным экземпляром и в RAC, а если NOORDER заменить на ORDER, отличия в RAC станут катастрофическими.

 

Кэширование последовательностей

Существует два неверных представления о последовательностях и их кэшировании, которые нужно исправить. Под «кэшем» в данном случае подразумевается совсем не то, что привыкли понимать многие. Это не традиционный кэш, а только лишь цель; если установить для последовательности кэш размером 100, это не значит, что Oracle создаст 100 чисел и сохранит их где-то для последующего использования. Отсюда следует, что не имеет смысла выбирать слишком большое значение в качестве размера кэша.

Второе ошибочное мнение касается местоположения кэша последовательностей – они хранятся в SGA. Некоторые считают, что кэш хранится в памяти сеанса, что могло бы означать, что если два сеанса используют последовательность с кэшем в 1000 элементов, тогда один сеанс (к примеру) сгенерировал бы числа от 1 до 1000, а другой от 1001 до 2000. Как мне кажется, это мнение появилось из-за возможности получить currval (current value – текущее значение) и nextval (следующее значение) из последовательности. Эта особенность действительно наталкивает на мысль, что последовательности кэшируются локально, в памяти сеансов, но в действительности сеанс просто запоминает в currval результат последнего вызова nextval, это всего лишь одно число, а не «весь кэш».

 

Внутреннее устройство последовательности

В действительности последовательности Oracle не являются чем-то особенным, и в этом легко убедиться, просто проследив за работой пары сеансов и исследовав содержимое файлов трассировки. Фактически последовательности реализуют следующий алгоритм:

Работу этого алгоритма легко проверить. Следующий пример был создан для 11g, где стал допустимым синтаксис присваивания значения последовательности переменной в PL/SQL (даже при том, что внутри по-прежнему используется инструкция select {sequence}. nextval from dual): 

create sequence test_sequence;
declare
       m_n number;
begin
       for i in 1..1000 loop
m_n := test_sequence.nextval;
       end loop;
end;
/

Выполнив этот код с включенным параметром sql_trace, и затем обработав файл трассировки утилитой tkprof, я получил следующие результаты (и некоторые другие, которые я удалил): 

insert into seq$(obj#,increment$,minvalue,maxvalue,cycle#,order$,cache,
highwater,audit$,flags)
values (:1,:2,:3,:4,:5,:6,:7,:8,:9,:10)
call     count      cpu   elapsed       disk      query    current      rows
------- ------ -------- --------- ---------- ---------- ---------- ---------
Parse        1     0.00      0.00          0          0          0         0
Execute      1     0.00      0.00          0          1          4         1
Fetch        0     0.00      0.00          0          0          0         0
------- ------ -------- --------- ---------- ---------- ---------- ---------
total        2     0.00      0.00          0          1          4         1
update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6,
cache=:7,highwater=:8,audit$=:9,flags=:10
where obj#=:1
call     count      cpu   elapsed       disk      query    current      rows
------- ------ -------- --------- ---------- ---------- ---------- ---------
Parse       50     0.00      0.00          0          0          0         0
Execute     50     0.00      0.00          1         50        102        50
Fetch        0     0.00      0.00          0          0          0         0
------- ------ -------- --------- ---------- ---------- ---------- ---------
total      100     0.00      0.00          1         50        102        50

Первая инструкция создает последовательность, добавляя строку в таблицу seq$ со значениями highwater = 1 и cache = 20. При первом обращении к значению nextval (которое равно 1) эта строка изменяется – в столбец highwater записывается значение 21. При каждом последующем двадцатом обращении она снова изменяется – именно поэтому было обнаружено 50 изменений (= 1000/20). Из этого вытекают два важных следствия.

В действительности положение дел в RAC может быть еще хуже из-за того, что в таблице seq$ может иметься 80 – 90 строк на блок. То есть, при наличии нескольких популярных последовательностей можно получить гигантский трафик между экземплярами и множество дополнительных операций чтения из таблицы, даже когда пользователи на разных экземплярах используют разные последовательности. Даже в версии Oracle с единственным такая ситуация может привести к появлению больших значений в buffer busy waits, а в RAC – gc buffer busy waits. (Много лет тому назад на Metalink имелось даже примечание о воссоздании словаря данных таблицы seq$ с очень большим значением pctfree, чтобы ограничить разрушительный характер такого поведения в OPS.)

Примечание. В выводе утилиты tkprof мы видели 50 изменений в таблице seq$, когда вызывали nextval 1000 раз для последовательности с размером кэша, равным 20. Это число также можно было бы заметить в v$enqueue_stat – число приобретений блокировок типа TX (транзакция), TM (таблица) и SQ (последовательность). Кроме того, это же число 50 можно наблюдать в столбце dc_sequences в v$rowcache – каждый раз, когда изменяется таблица, сначала изменяется строка в кэше, а затем она копируется в базу данных.

 

Упорядоченные последовательности

Я уже отмечал, что последовательность кэшируется на уровне экземпляра, но в RAC имеется несколько экземпляров, что порождает интересную проблему: по умолчанию каждый экземпляр генерирует собственное множество значений. Если, к примеру, имеется четыре узла и определена последовательность с размером кэша, равным 20, вы сможете заметить, что один экземпляр использует значения от 101 до 120, другой от 121 до 140 и так далее. То есть, значения генерируются и используются не совсем по порядку и это может доставлять массу неприятностей. Такое поведение также означает, что если остановить систему, некоторые числа из последовательности будут потеряны. Один экземпляр, стремящийся к текущему значению highwater в таблице, может обновить таблицу seq$, чтобы сообщить о своей преждевременной остановке, но другие экземпляры не смогут записать свои числа они будут потеряны.


Последовательности, порядок и контроль


Чтобы гарантировать отсутствие промежутков в данных, часто используют прием объявления последовательностей с параметром nocache. Иногда это необходимо для бизнеса, чтобы, например, генерировать номера заказов; иногда для каких-то других, более абстрактных целей. Важно понять, что последовательности Oracle не подходят для подобных функций.

Последовательности не поддерживают транзакции, и Oracle не гарантирует, что вы не потеряете некоторые значения. Если, например, ваш код выберет nextval и затем откатит транзакцию по каким-либо причинам, выбранное значение будет потеряно. Мало того, что параметр nocache (возможно, в сочетании с параметром order) не гарантирует соответствие вашим требованиям, используя его, вы рискуете получить немасштабируемое приложение.

Чтобы гарантировать, что все числа будут следовать по порядку и ни одно число не потеряется, следует использовать механизм, который будет заполнять пул чисел, и алгоритм, гарантирующий либо использование числа, либо сохранение физической записи для любого числа, «выделенного, но не использованного». (Я описал возможную реализацию такого механизма в книге «Practical Oracle 8i» несколько лет тому назад.)


Типичным ответом на проблему «потери» значений является либо установка размера кэша равным нулю (nocache) – что в системах RAC вызывает передачу значительных объемов данных из-за перемещения блока таблицы seq$ из экземпляра в экземпляр – либо использование предложения order с ненулевым (предпочтительнее с большим) размером кэша – что также вызывает существенный трафик между экземплярами, но, хотя бы не генерирует большого числа записей отмены и повторения.

Параметр order специально предназначен для использования в RAC. Вместо того, чтобы позволить каждому экземпляру иметь собственный кэш для последовательности, определяется единственное значение highwater и единственное текущее значение. Доступ к этим единственным значениям регулируется специальной глобальной блокировкой (блокировка SV). То есть значения генерируются по порядку, потому что в каждый момент имеется только одно активное значение и только один экземпляр имеет возможность увеличить его (но даже в этом случае нет гарантий от потери значений сеансом или экземпляром, потерпевшим аварию или выполнившим откат).

Блокировка SV немного необычная и подчеркивает еще одну из странностей, которую легко заметить при внимательном изучении деталей реализации RAC. Если посмотреть содержимое v$lock_type, можно увидеть такое описание блокировки SV: Lock to ensure ordered sequence allocation in RAC mode (блокировка, гарантирующая упорядоченное распределение последовательных значений в режиме RAC), и ее первым параметром (столбец id1 в представлении v$lock – хотя вы не увидите его там) является объект id последовательности. Когда процесс пытается приобрести блокировку SV, вы не увидите никаких признаков этого в представлении v$lock, и точно так же не увидите, что процесс ожидает на блокировке, например, в файле трассировки или в v$session_wait. Вместо этого вы будете видеть ожидание DFS lock handle (одно из множества ожиданий, которые суммируются в представлении v$session_event в виде общего значения events in waitclass Other), и только декодируя значение первого параметра можно определить, что это блокировка SV.

Однако на этом сюрпризы не заканчиваются. Кто-то мог бы ожидать, что блокировка SV приобретается в режиме 6 (монопольный), когда она приобретается сеансом с целью сгенерировать следующее значение. Но, декодировав значение первого параметра события ожидания DFS lock handle, можно увидеть, что блокировка приобретается в режиме 5. Хотите верьте, хотите нет, но в RAC этот режим является монопольным! Я не знаю почему, но вместо шести режимов блокировки ресурсов в обычной версии Oracle с единственным экземпляром, о которых можно подробно прочитать вот в этом блоге, в RAC используется пять значений, которые я перечислил в табл. 1.

Режим Имя Описание Эквивалент v$lock
0 KJUSERNL Без полномочий 0 (Null)
1 KJUSERCR Одновременное чтение 2 (режим разделяемой строки)
2 KJUSERCW Одновременная запись 3 (режим монопольного владения строкой)
3 KJUSERPR Защищенное чтение 4 (разделяемый режим)
4 KJUSERPW Защищенная запись 5 (монопольная блокировка в режиме разделяемой строки)
5 KJUSEREX Монопольный доступ 6 (монопольный режим)

Примечание. Существует множество документов, где описывается, как декодировать параметры событий ожидания. Во многих случаях достаточно просто выполнить запрос к v$event_name, чтобы получить достаточно подробное описание. Например, описание первого параметра для многих событий ожидания включает текст name|mode. Символ вертикальной черты («|») подсказывает, что для простоты интерпретации значение следует преобразовать в шестнадцатеричный формат. В данном случае я получил значение 1398145029 первого параметра DFS lock handle, которое в шестнадцатеричном формате имеет вид 0x53560005. Цифра 5 в конце – это режим блокировки, а если вы знакомы с кодами ASCII символов, вы легко декодируете 0x53 и 0x56 как «S» и «V».

К другим событиям, которые можно увидеть, применяя параметр order в определениях часто используемых последовательностей, относятся: ges resource hash list и the row cache lock wait. Первое просто сообщает, что в RAC при работе с ресурсами используются те же стратегии на основе хэш-таблиц и связанных списков, которые мы уже много раз видели раньше. Второе напоминает, что последовательности тесно связаны с их записями в v$rowcache, и для изменения и выталкивания записей в кэш строк, в RAC требуется больше времени (и труда), чем в Oracle с единственным экземпляром.

 

Последовательности и индексы

Детально изучая последовательности, можно еще много интересного узнать о RAC. Далее мы рассмотрим проблему, часто возникающую при использовании последовательностей в качестве «искусственного первичного ключа». Если последовательность используется для создания чисел, которые затем применяются в качестве значений первичного или уникального ключа, появляется индекс на основе столбца, хранящем эти числа – и всякий раз, когда потребуется вставить строку в таблицу, из любого экземпляра, в этот индекс нужно будет вставлять наибольшее значение. Иными словами, создается своеобразная горячая точка, гарантированно ведущая к gc buffer busy waits. Разумеется, эта проблема не ограничивается последовательностями. Для ее появления достаточно, чтобы вставляемые значения всегда последовательно увеличивались – индекс на простом значении «текущая отметка времени» подвержен той же самой проблеме.


Проблема ITL в индексах


Существует давнишний дефект (или ошибка) в реализации B-деревьев индексов в Oracle. Когда листовой блок делится и в то же время несколько-процессов пытаются вставить индексы в делящийся блок, возникает стран процессов пытаются вставить индексы в делящийся блок, возникает странное состояние гонки, приводящее к созданию слишком большого числа элементов ITL (Interested Transaction List – список заинтересованных транзакций) в двух получающихся листовых блоках. Поскольку список ITL в новом листовом блоке индекса всегда, как минимум, имеет такой же размер, как до деления, лишние элементы списка никуда не исчезают – и может так случиться, что в какой-то момент каждый листовой блок индекса будет терять половину своего пространства в списке ITL при создании.

Любой индекс, основанный на последовательности (или отметке времени), является первым кандидатом на появление данной проблемы, и любой индекс, который систематически становится предметом конкуренции (даже самой низкой, когда на каждый процессор приходится не больше одного сеанса) за вставку в горячей точке, легко может столкнуться с проблемой непроизводительной потери половины своего пространства. В ранних версиях Oracle эта проблема решалась простым определением подходящего значения maxtrans для индекса. К сожалению, в версиях, начиная с 10g, Oracle игнорирует параметр maxtrans.

Я написал несколько статей на эту тему в своем блоге, где их можно найти в категории «index explosion». Исправление этого дефекта-ошибки было выпущено для версии Oracle 12.1 и уже появилось несколько версий исправлений для линейки 10.2.


До появления механизма ASSM (Automatic Segment Space Management – автоматическое управление пространством сегмента) можно было определить множество списков свободных фрагментов памяти и (что, иногда, даже более важно) несколько списков свободных групп для ослабления проблемы конкуренции при вставке записей в таблицы. Механизм ASSM, который позволяет разным экземплярам RAC использовать разные битовые блоки из сегмента и тем самым изолировать операции вставки друг от друга, практически избавляет администраторов баз данных от необходимости задумываться о проблеме buffer busy waits для таблиц. Но в случае с индексом этот механизм не является решением. Запись в индекс не может быть произведена в произвольное место, она может находиться только в одном, строго определенном месте.

Есть несколько предложений по решению данной проблемы. Одно из них заключается в преобразовании индекса в индекс с обратным ключом (reverse-key index).

Примечание. В индексе с обратным ключом байты каждого отдельного столбца (кроме rowid, в случае неуникального индекса со встроенным значением rowid) перестраиваются в обратном порядке перед сохранением элемента в индексе. В результате значения, которые первоначально казались похожими, оказываются очень разными. Например, сравните числа 329002 и 329003 до и после переупорядочения: последовательности байтов (c3, 21, 5b, 3) и (c3, 21, 5b, 4) превратятся в последовательности (3, 5b, 21, c3) и (4, 5b, 21, c3).

На первый взгляд идея выглядит очень неплохо – но она имеет побочный эффект. Если большая часть запросов будет обращена к «свежим» данным, может потребоваться кэшировать только малую, «горячую» часть индексов в памяти. Суть приема использования обратного ключа заключается в том, чтобы «размазать» горячее пятно в индексе как можно шире, в результате чего кэшировать приходится большую часть (или даже весь) индекса. На рис. 1 я постарался графически изобразить происходящее.

Влияние на кэширование приема обратного ключа

Рис. 1. Влияние на кэширование приема обратного ключа

Существует две альтернативные стратегии. Простейшая состоит в том, чтобы настроить большой размер кэша для последовательности. Значение в диапазоне от 5000 до 50 000 кажется вполне разумным (не забывайте, что речь идет о высокой частоте следования операций вставки, поэтому предполагается, что кэш будет исчерпан достаточно быстро. В этом случае каждый экземпляр будет вставлять строки, отличающиеся на тысячи значениями ключа от строк, вставляемых другими экземплярами, поэтому экземпляры чаще всего будут выполнять вставку в собственные, изолированные области в индексе. Недостаток такого решения в том, что чаще всего листовые блоки будут делиться 50/50 (за исключением случаев, когда экземпляр вставляет наивысшее значение) – фактически, учитывая проблему конкуренции, упомянутую во врезке выше, можно заметить непроизводительные потери пространства до 25 процентов. Как вариант идеи увеличения различий между значениями, используемыми разными узлами, в прошлом предлагалось добавлять увеличенное в 10^N раз число id экземпляра к значению последовательности, где N – достаточно большое число, такое, что значение 10^N не может быть достигнуто последовательностью в ближайшие несколько лет.

Другая стратегия – если вы приобрели поддержку секционирования (Oracle Partitioning) – заключается в хэшировании разделов индекса. Можно разделить индекс на (например) 16 разных фрагментов хэшированием последовательности чисел и одна горячая точка превратится в 16 (для лучшего эффекта число хэш-разделов всегда должно быть степенью двойки) менее горячих точек. Конкуренция за наивысший блок в каждом разделе все равно останется, но она может снизиться до вполне приемлемого уровня.

Какое бы решение вы не выбрали, не забывайте о сохранении масштаба проблемы в перспективе. Проблема событий buffer busy waits сама по себе неприятная – но если они не приводят к существенным потерям времени, с ними можно мириться. Будьте внимательны при попытке решить эту проблему, чтобы в результате не появилась более сложная и худшая проблема. Я знаком с людьми, которые переходили на кластеры RAC, только потому, что думали, что кластер избавит их от проблем, а затем обнаруживали, что тяжесть проблем от этого только возросла, потому что их природа (таких как большие потери на событиях buffer busy waits) проявляется еще ярче в RAC.

 

В заключение

Основными причинами, заставляющими взглянуть в сторону Oracle RAC, являются высокая надежность и масштабируемость. Если вам интересна высокая надежность, знайте, что настройка RAC является очень непростым делом и прежде чем вводить в эксплуатацию столь сложный стек, тщательно подумайте – какое время простоя является для вас допустимым. Если вам интересна масштабируемость, знайте, что неудачно спроектированные приложения могут вести себя в среде RAC еще хуже из-за дополнительного трафика между экземплярами. С другой стороны, приложение с удачной архитектурой может обеспечивать соответствие запросам производства простым увеличением числа машин в кластере.

Базовой особенностью реализации RAC является постоянный обмен информацией между экземплярами об используемых ими объектах и необходимость их защиты. В Oracle эти функции выполняет распределенный глобальный каталог ресурсов (Global Resource Directory, GRD). Каждый объект – вплоть до блоков данных – имеет соответствующий ему ведущий ресурс, в котором перечисляются все экземпляры, заинтересованные в этом ресурсе. Вообще говоря, местоположение ведущего ресурса определяется простой арифметикой. Каждый экземпляр, включенный в очередь к ведущему ресурсу, так-же имеет локальный «теневой» ресурс. Такая организация позволяет Oracle гарантировать доступность блока для изменения только одному экземпляру, а экземпляру, владеющему ведущим ресурсом для блока, координировать его перемещение по сети, когда он потребуется другому экземпляру. Реализация GRD гарантирует, что независимо от числа экземпляров в кластере, для приобретения блока данных любому экземпляру потребуется не более трех шагов. Именно этим решением Oracle обеспечивает почти идеальную масштабируемость при добавлении новых узлов. Тем не менее, с увеличением числа узлов растет и вероятность выбора трехстороннего способа приобретения ресурса, а трехсторонний способ медленнее двустороннего.

Когда экземпляр терпит аварию, один из других экземпляров очень быстро обнаруживает это и берет на себя управление восстановлением. Этот процесс состоит из двух этапов. Сначала определяется, какими ресурсами владел аварийный экземпляр, что может быть реализовано через проверку теневых ресурсов в остальных экземплярах. Затем просто выполняется чтение файлов журнала аварийного экземпляра, подобно тому, как это делает стандартная процедура восстановления – блоки, требующие восстановления, закрепляются в кэше буферов до окончания восстановления. Это приводит к временной приостановке GRD до момента, пока не отработает алгоритм, который определит, какие ведущие ресурсы каким экземплярам будут принадлежать.

Существует масса тонкостей, которые необходимо принимать во внимание при миграции с версии Oracle с единственным экземпляром на RAC, и множество приемов, помогающих достичь оптимальной производительности. В этом блоге я выбрал последовательности, на примере которых продемонстрировал некоторые подходы, помогающие обойти ловушки в RAC. К последовательностям в RAC необходимо подходить с большой осторожностью и тщательно взвешивать – какую цену вы готовы заплатить за их использование. Как минимум следует установить размер кэша для популярных последовательностей значительно больше , чем предлагает Oracle по умолчанию. Используйте параметры nocache и order только для редко используемых последовательностей.

Так как последовательности часто используются для создания значений искусственных ключей, они образуют своеобразные горячие точки в конце с «высшими значениями» индекса. Будьте осторожны, используя индексы с обратным ключом обратные ключи для преодоления этой проблемы, потому что такая стратегия может привести к увеличению операций с диском – неплохим решением может стать секционирование индексов, если вы уже приобрели лицензию на этот механизм.

Вас заинтересует / Intresting for you:

Восстановление баз данных Orac...
Восстановление баз данных Orac... 9447 просмотров Дэн Tue, 21 Nov 2017, 13:18:05
Выполнение восстановления базы...
Выполнение восстановления базы... 9714 просмотров Дэн Tue, 21 Nov 2017, 13:18:05
Ищем и исправляем ошибки в баз...
Ищем и исправляем ошибки в баз... 6807 просмотров Александров Попков Tue, 21 Nov 2017, 13:18:05
Устранение ошибок в сеансах во...
Устранение ошибок в сеансах во... 7257 просмотров reset Tue, 21 Nov 2017, 13:18:05
Печать
Войдите чтобы комментировать