Задача процесса ARCn — копировать в другое место оперативный файл журнала повторного выполнения, когда он заполняется процессом LGWR. Эти архивные файлы журнала повторного выполнения затем можно использовать для восстановления носителя. Тогда как оперативный журнал повторного выполнения используется для "исправления" файлов данных в случае сбоя питания (когда прекращается работа экземпляра), архивные журналы повторного выполнения используются для восстановления файлов данных в случае сбоя диска. Если будет потерян диск, содержащий файл данных /d01/oradata/ora8i/system.dbf, можно взять резервные копии за прошлую неделю, восстановить из них старую копию файла и попросить сервер применить оперативный журнал повторного выполнения и все архивные журналы, сгенерированные с момента создания этой резервной копии. Это "подтянет" файл по времени к остальным файлам в базе данных, и можно будет продолжить работу без потери данных.
Процесс ARCn обычно копирует оперативный журнал повторного выполнения в несколько мест (избыточность — гарантия сохранности данных!). Это могут быть диски на локальной машине или, что лучше, на другой машине, на случай катастрофического сбоя. Во многих случаях архивные файлы журнала повторного выполнения копируются затем другим процессом на третье устройство хранения, например на ленту. Они также могут отправляться на другую машину для применения к резервной базе данных (это одно из средств защиты от сбоев, предлагаемое Oracle).
Oracle проектировалась как максимально переносимая СУБД, — она доступна на всех распространенных платформах. Поэтому физическая архитектура Oracle различна в разных операционных системах. Например, в ОС UNIX СУБД Oracle реализована в виде нескольких отдельных процессов операционной системы — практически каждая существенная функция реализована отдельным процессом. Для UNIX такая реализация подходит, поскольку основой многозадачности в ней является процесс. Для Windows, однако, подобная реализация не подходит и работала бы не слишком хорошо (система получилась бы медленной и плохо масштабируемой). На этой платформе СУБД Oracle реализована как один многопоточный процесс, т.е. с использованием подходящих для этой платформы механизмов реализации. На мэйнфреймах IBM, работающих под управлением OS/390 и zOS, СУБД Oracle использует несколько адресных пространств OS/390, совместно образующих экземпляр Oracle. Для одного экземпляра базы данных можно сконфигурировать до 255 адресных пространств. Более того, СУБД Oracle взаимодействует с диспетчером загрузки OS/390 WorkLoad Manager (WLM) для установки приоритетности выполнения определенных компонентов Oracle по отношению друг к другу и к другим задачам, работающим в системе OS/390. В ОС Netware тоже используется многопоточная модель. Хотя физические средства реализации СУБД Oracle на разных платформах могут отличаться, архитектура системы — достаточно общая, чтобы можно было понять, как СУБД Oracle работает на всех платформах.
В этой главе мы рассмотрим три основных компонента архитектуры Oracle.
Файлы. Будут рассмотрены пять видов файлов, образующих базу данных и поддерживающих экземпляр. Это файлы параметров, сообщений, данных, временных данных и журналов повторного выполнения.
Структуры памяти, в частности системная глобальная область (System Global Area — SGA). Мы рассмотрим взаимодействие SGA, PGA и UGA. Будут также рассмотрены входящие в SGA Java-пул, разделяемый пул и большой пул.
Физические процессы или потоки. Будут описаны три типа процессов, образующих экземпляр: серверные процессы, фоновые процессы и подчиненные процессы.
База данных Oracle может работать в двух режимах — NOARCHIVELOG
и ARCHIVELOG. Я считаю, что система, используемая в производственных условиях, обязательно должна работать в режиме ARCHIVELOG. Если база данных не работает в режиме ARCHIVELOG, данные рано или поздно будут потеряны. Работать в режиме NOARCHIVELOG можно только в среде разработки или тестирования.
Эти режимы отличаются тем, что происходит с файлом журнала повторного выполнения до того как сервер Oracle его перепишет. Сохранять ли копию информации повторного выполнения или разрешить серверу Oracle переписать ее, потеряв при этом навсегда — очень важный вопрос. Если не сохранить этот файл, мы не сможем восстановить данные с резервной копии до текущего момента. Предположим, резервное копирование выполняется раз в неделю, по субботам. В пятницу вечером, после того как за неделю было сгенерировано несколько сотен журналов повторного выполнения, происходит сбой диска. Если база данных не работала в режиме ARCHIVELOG, остается только два варианта дальнейших действий.
Удалить табличное пространство/пространства, связанные со сбойным диском. Любое табличное пространство, имеющее файлы данных на этом диске, должно быть удалено, включая его содержимое. Если затронуто табличное пространство SYSTEM (словарь данных Oracle), этого сделать нельзя.
Восстановить данные за субботу и потерять все изменения за неделю.
Оба варианта непривлекательны, поскольку приводят к потере данных. Работая же в режиме ARCHIVELOG, достаточно найти другой диск и восстановить на него соответствующие файлы с субботней резервной копии. Затем применить к ним архивные журналы повторного выполнения и, наконец, — оперативные журналы повторного выполнения (то есть повторить все накопленные за неделю транзакции в режиме быстрого наката). При этом ничего не теряется. Данные восстанавливаются на момент сбоя.
Часто приходится слышать, что в производственных системах режим ARCHIVELOG не нужен. Это глубочайшее заблуждение. Если не хотите в один момент потерять данные, сервер должен работать в режиме ARCHIVELOG. "Мы используем дисковый массив RAID-5 и абсолютно защищены" — вот типичное оправдание. Я сталкивался с ситуациями, когда по вине изготовителя все пять дисков массива одновременно останавливались. Я видел поврежденные аппаратным контроллером файлы данных, которые в поврежденном виде надежно защищались дисковым массивом. Если имеется резервная копия данных на момент, предшествующий сбою оборудования, и архивы не повреждены, — восстановление возможно. Поэтому нет разумных оснований для того, чтобы не использовать режим ARCHIVELOG в системе, где данные представляют хоть какую-нибудь ценность. Производительность — не основание. При правильной настройке на архивирование расходуется незначительное количество ресурсов системы. Это, а также тот факт, что быстро работающая система, в которой данные теряются, — бесполезна, заставляет сделать вывод, что, даже если бы архивирование журналов замедляло работу системы в два раза, оно в любом случае должно выполняться.
Не поддавайтесь ни на какие уговоры и не отказывайтесь от режима ARCHIVELOG. Вы потратили много времени на разработку приложения, поэтому надо, чтобы пользователи ему доверяли. О доверии можно забыть, если их данные будут потеряны.
Итак, мы рассмотрели основные типы файлов, используемых сервером Oracle: от небольших файлов параметров инициализации (без которых не удастся даже запустить экземпляр) до принципиально важных файлов журнала повторного выполнения и файлов данных. Обсудили структуры хранения данных в Oracle: от табличных пространств, сегментов и экстентов до блоков базы данных — наименьшей единицы хранения. Была описана обработка контрольной точки в базе данных и даже (несколько преждевременно) затронута работа физических процессов или потоков, составляющих экземпляр Oracle. В последующих разделах этой главы мы более детально рассмотрим эти процессы и структуры памяти.
Большой пул назван так не потому, что это "большая" структура (хотя его размер вполне может быть большим), а потому, что используется для выделения больших фрагментов памяти — больших, чем те, для управления которыми создавался разделяемый пул. До его появления в Oracle 8.0, выделение памяти выполнялось в рамках разделяемого пула. Это было неэффективно при использовании средств, выделяющих "большие" объемы памяти, например, при работе в режиме MTS. Проблема осложнялась еще и тем, что при обработке, требующей больших объемов памяти, эта память используется не так, как предполагает управление памятью в разделяемом пуле. Память в разделяемом пуле управляется на основе давности использования, что отлично подходит для кеширования и повторного использования данных. При выделении же больших объемов памяти фрагмент выделяется, используется и после этого он не нужен, т.е. нет смысла его кешировать.
Серверу Oracle требовался аналог буферных пулов RECYCLE и KEEP
в буферном кеше. Именно в таком качестве сейчас и выступают большой пул и разделяемый пул. Большой пул — это область памяти, управляемая по принципу пула RECYCLE, а разделяемый пул скорее похож на буферный пул KEEP: если фрагмент в нем используется часто, он кешируется надолго.
Память в большом пуле организована по принципу "кучи" и управляется с помощью алгоритмов, аналогичных используемым функциями malloc() и free()
в языке C. После освобождения фрагмента памяти он может использоваться другими процессами. В разделяемом пуле отсутствует понятие освобождения фрагмента памяти. Память выделяется, используется, а затем перестает использоваться. Через некоторое время, если эту память необходимо использовать повторно, сервер Oracle позволит изменить содержимое устаревшего фрагмента. Проблема при использовании только разделяемого пула состоит в том, что все потребности в памяти нельзя подогнать под одну мерку.
Большой пул, в частности, используется:
сервером в режиме MTS для размещения области UGA в SGA;
Этот процесс используется исключительно в среде Oracle Parallel Server (OPS). OPS — конфигурация Oracle, при которой несколько экземпляров монтируют и открывают одну и ту же базу данных. Каждый экземпляр Oracle в этом случае работает на своей машине в кластере, и все они имеют доступ для чтения и записи к одному и тому же набору файлов базы данных.
При этом буферные кеши в SGA экземпляров должны поддерживаться в согласованном состоянии. Для этого и предназначен процесс BSP. В ранних версиях OPS согласование достигалось с помощью выгрузки блока из кеша ('ping'). Если машине в кластере требовалось согласованное по чтению представление блока данных, заблокированного в исключительном режиме другой машиной, выполнялся обмен данными с помощью сброса на диск. В результате получалась очень дорогостоящая операция чтения данных. Сейчас, при наличии процесса BSP, обмен происходит из кеша в кеш через высокоскоростное соединение машин в кластере.
Буфер журнала повторного выполнения используется для временного кеширования данных оперативного журнала повторного выполнения перед записью на диск. Поскольку перенос данных из памяти в память намного быстрее, чем из памяти — на диск, использование буфера журнала повторного выполнения позволяет существенно ускорить работу сервера. Данные не задерживаются в буфере журнала повторного выполнения надолго. Содержимое этого буфера сбрасывается на диск:
раз в три секунды;
при фиксации транзакции;
при заполнении буфера на треть или когда в нем оказывается 1 Мбайт данных журнала повторного выполнения.
Поэтому создание буфера журнала повторного выполнения размером в десятки Мбайт — напрасное расходование памяти. Чтобы использовать буфер журнала повторного выполнения размером 6 Мбайт, например, надо выполнять продолжительные транзакции, генерирующие по 2 Мбайта информации повторного выполнения не более чем за три секунды. Если кто-либо в системе зафиксирует транзакцию в течение этих трех секунд, в буфере не будет использовано и 2 Мбайт, — содержимое буфера будет регулярно сбрасываться на диск. Лишь очень немногие приложения выиграют от использования буфера журнала повторного выполнения размером в несколько мегабайт.
Стандартный размер буфера журнала повторного выполнения, задаваемый параметром LOG_BUFFER в файле init.ora, определяется как максимальное из значений 512 и (128 * количество_процессоров) Кбайт. Минимальный размер этой области равен максимальному размеру блока базы данных для соответствующей платформы, умноженному на четыре. Если необходимо узнать это значение, установите LOG_BUFFER равным 1 байту и перезапустите сервер. Например, на моем сервере под Windows 2000 я получил следующий результат:
SVRMGR> show parameter log_buffer NAME TYPE VALUE ----------------------------------- ------- -------------------------- log_buffer integer 1
SVRMGR> select * from v$sgastat where name = 'log_buffer'; POOL NAME BYTES ----------- -------------------------- ---------- log_buffer 66560
Теоретически минимальный размер буфера журнала повторного выполнения, независимо от установок в файле init.ora, в данном случае — 65 Кбайт. Фактически он немного больше:
tkyte@TKYTE816> select * from v$sga where name = 'Redo Buffers';
NAME VALUE ------------------------------ ---------- Redo Buffers 77824
То есть размер буфера — 76 Кбайт. Дополнительное пространство выделено из соображений безопасности, как "резервные" страницы, защищающие страницы буфера журнала повторного выполнения.
До сих пор мы рассматривали небольшие компоненты области SGA. Теперь переходим к составляющей, которая достигает огромных размеров. В буферном кеше сервер Oracle хранит блоки базы данных перед их записью на диск, а также после считывания с диска. Это принципиально важный компонент SGA. Если сделать его слишком маленьким, запросы будут выполняться годами. Если же он будет чрезмерно большим, пострадают другие процессы (например, выделенному серверу не хватит пространства для создания области PGA, и он просто не запустится).
Блоки в буферном кеше контролируются двумя списками. Это список "грязных" блоков, которые должны быть записаны процессом записи блоков базы данных (это DBWn; его мы рассмотрим несколько позже). Есть еще список "чистых" блоков, организованный в Oracle 8.0 и предыдущих версиях в виде очереди (LRU — Least Recently Used). Блоки упорядочивались по времени последнего использования. Этот алгоритм был немного изменен в Oracle 8i и последующих версиях. Вместо физического упорядочения списка блоков, сервер Oracle с помощью счетчика, связанного с блоком, подсчитывает количество обращений ("touch count") при каждом обращении (hit) к этому блоку в буферном кеше. Это можно увидеть в одной из действительно "магических" таблиц X$. Эти таблицы не описаны в документации Oracle, но информация о них периодически просачивается.
Таблица X$BH содержит информацию о блоках в буферном кеше. В ней можно увидеть, как "счетчик обращений" увеличивается при каждом обращении к блоку. Сначала необходимо найти блок. Мы используем блок таблицы DUAL — специальной таблицы, состоящей из одной строки и одного столбца, которая есть во всех базах данных Oracle. Необходимо найти соответствующий номер файла и номер блока в файле:
tkyte@TKYTE816> select file_id, block_id 2 from dba_extents 3 where segment_name = 'DUAL' and owner = 'SYS';
FILE_ID BLOCK_ID ---------- ---------- 1 465
Теперь можно использовать эту информацию для получения "счетчика обращений" для этого блока:
Процесс обработки контрольной точки вовсе не обрабатывает ее, как можно предположить по названию, — это делает процесс DBWn. Процесс CKPT просто содействует обработке контрольной точки, обновляя заголовки файлов данных. Раньше процесс CKPT был необязательным, но, начиная с версии 8.0, он запускается всегда, так что он представлен в результатах выполнения команды ps в ОС UNIX. Ранее заголовки файлов данных обновлялись в соответствии с информацией о контрольной точке процессом записи журнала LGWR (Log Writer). Однако с ростом размеров баз данных и увеличением количества файлов это стало невыполнимой задачей для процесса LGWR. Если процессу LGWR надо обновлять десятки, сотни, а то и тысячи файлов, увеличивается вероятность того, что ожидающие фиксации транзакций сеансы будут ждать слишком долго. Процесс CKPT снимает эту задачу с процесса LGWR.
Процесс записи блоков базы данных (Database Block Writer — DBWn) — фоновый процесс, отвечающий за запись измененных блоков на диск. Процесс DBWn записывает измененные блоки из буферного кеша, чтобы освободить пространство в кеше (чтобы освободить буферы для чтения других данных) или в ходе обработки контрольной точки (чтобы перенести вперед позицию в оперативном файле журнала повторного выполнения, с которой сервер Oracle начнет чтение при восстановлении экземпляра после сбоя). Как было описано ранее, при переключении журнальных файлов сервером Oracle запрашивается обработка контрольной точки. Серверу Oracle нужно перенести отметку контрольной точки, чтобы не было необходимости в только что заполненном оперативном файле журнала повторного выполнения. Если ему не удастся это сделать до того, как возникнет необходимость в файле журнала повторного выполнения, выдается сообщение, что обработка контрольной точки не завершена (checkpoint not complete), и придется ждать завершения обработки.
Как видите, производительность процесса DBWn может иметь принципиальное значение. Если он недостаточно быстро записывает блоки для освобождения буферов, сеансам приходится ждать события FREE_BUFFER_WAITS, и показатель 'Write Complete Waits' начинает расти.
Можно сконфигурировать несколько (до десяти) процессов DBWn
(DBW0 ... DBW9). В большинстве систем работает только один процесс записи блоков базы данных, но в больших, многопроцессорных системах имеет смысл использовать несколько. Если сконфигурировано более одного процесса DBWn, не забудьте также увеличить значение параметра инициализации DB_BLOCK_LRU_LATCHES. Он определяет количество защелок списков по давности использования, LRU lists (теперь, в версии 8i, их называют списками количества обращений — touch lists). Каждый процесс DBWn
должен иметь собственный список. Если несколько процессов DBWn совместно используют один список блоков для записи на диск, они будут конфликтовать друг с другом при доступе к списку.
Обычно процесс DBWn использует асинхронный ввод-вывод для записи блоков на диск. При использовании асинхронного ввода-вывода процесс DBWn
Процессы EMNn — часть подсистемы расширенной поддержки очередей. Они используются для уведомления подписчиков очереди о сообщениях, в которых они могут быть заинтересованы. Это уведомление выполняется асинхронно. Имеются функции Oracle Call Interface (OCI) для регистрации обратного вызова, уведомляющего о сообщении. Обратный вызов (callback) — это функция в программе OCI, которая вызывается автоматически при появлении в очереди определенного сообщения. Фоновый процесс EMNn используется для уведомления подписчика. Процесс EMNn запускается автоматически при выдаче первого уведомления в экземпляре. После этого приложение может явно вызвать message_receive(dequeue) для извлечения сообщения из очереди.
В состав базы данных и экземпляра входит шесть типов файлов. С экземпляром связаны файлы параметров. По этим файлам экземпляр при запуске определяет свои характеристики, например размер структур в памяти и местонахождение управляющих файлов.
Базу данных образуют следующие файлы.
Файлы данных. Собственно данные (в этих файлах хранятся таблицы, индексы и все остальные сегменты).
Файлы журнала повторного выполнения. Журналы транзакций.
Управляющие файлы. Определяют местонахождение файлов данных и содержат другую необходимую информацию о состоянии базы данных.
Временные файлы. Используются при сортировке больших объемов данных и для хранения временных объектов.
Файлы паролей. Используются для аутентификации пользователей, выполняющих администрирование удаленно, по сети. Мы не будем их подробно рассматривать.
Наиболее важны первые два типа файлов, поскольку именно в них хранятся накопленные данные. В случае потери остальных файлов хранящиеся данные не пострадают. Если будут потеряны файлы журнала повторного выполнения, некоторые данные могут быть потеряны. Если же будут потеряны файлы данных и все их резервные копии, данные, безусловно, будут потеряны навсегда.
Теперь давайте детально рассмотрим все типы файлов и их содержимое.
Файлы данных вместе с файлами журнала повторного выполнения являются наиболее важными в базе данных. Именно в них хранятся все данные. В каждой базе данных есть хотя бы один файл данных, но обычно их намного больше. Только самые простые, "тестовые" базы данных имеют один файл данных. В любой реальной базе данных должно быть минимум два файла данных: один — для системных данных (табличное пространство SYSTEM), другой — для пользовательских (табличное пространство USER). В этом разделе мы рассмотрим организацию файлов данных в Oracle и способы хранения данных в этих файлах. Но прежде надо разобраться, что такое табличное пространство, сегмент, экстент и блок. Все это — единицы выделения пространства под объекты в базе данных Oracle.
Начнем с сегментов. Сегменты — это области на диске, выделяемые под объекты — таблицы, индексы, сегменты отката и т.д. При создании таблицы создается сегмент таблицы. При создании секционированной таблицы создается по сегменту для каждой секции. При создании индекса создается сегмент индекса и т.д. Каждый объект, занимающий место на диске, хранится в одном сегменте. Есть сегменты отката, временные сегменты, сегменты кластеров, сегменты индексов и т.д.
Сегменты, в свою очередь, состоят из одного или нескольких экстентов. Экстент — это непрерывный фрагмент пространства в файле. Каждый сегмент первоначально состоит хотя бы из одного экстента, причем для некоторых объектов требуется минимум два экстента (в качестве примера можно назвать сегменты отката). Чтобы объект мог вырасти за пределы исходного экстента, ему необходимо выделить следующий экстент. Этот экстент не обязательно должен выделяться рядом с первым; он может находиться достаточно далеко от первого, но в пределах экстента в файле пространство всегда непрерывно. Размер экстента варьируется от одного блока до 2 Гбайт.
Экстенты состоят из блоков. Блок — наименьшая единица выделения пространства в Oracle. В блоках и хранятся строки данных, индексов или промежуточные результаты сортировок. Именно блоками сервер Oracle обычно выполняет чтение и запись на диск. Блоки в Oracle бывают размером 2 Кбайта, 4 Кбайта или 8 Кбайт (хотя допустимы также блоки размером 16 Кбайт и 32 Кбайта).
С базой данных Oracle связано много файлов параметров: от файла TNSNAMES.ORA
на клиентской рабочей станции (используемого для поиска сервера) и файла LISTENER.ORA на сервере (для запуска процесса прослушивания Net8) до файлов SQLNET.ORA, PROTOCOL.ORA, NAMES.ORA, CMAN.ORA и LDAP.ORA. Наиболее важным является файл параметров инициализации экземпляра, потому что без него не удастся запустить экземпляр. Остальные файлы тоже важны; они связаны с поддержкой сети и обеспечением подключения к базе данных. Однако рассматриваться в этом разделе они не будут. Сведения об их конфигурировании и настройке можно найти в руководстве Oracle Net8 Administrators Guide. Обычно разработчик не настраивает эти файлы — они создаются администратором.
Файл параметров инициализации экземпляра обычно называют файлом init или файлом init.ora. Это название происходит от стандартного имени этого файла, — init<ORACLE_SID>.ora. Например, экземпляр со значением SID, равным tkyte816, обычно имеет файл параметров инициализации inittkyte816.ora. Без файла параметров инициализации нельзя запустить экземпляр Oracle. Поэтому файл этот достаточно важен. Однако, поскольку это обычный текстовый файл, который можно создать в любом текстовом редакторе, сохранять его ценой собственной жизни не стоит.
Для тех, кому незнаком термин SID или параметр ORACLE_SID, представлю полное определение. SID — это идентификатор экземпляра (сайта). В ОС UNIX он хешируется совместно со значением ORACLE_HOME (задающим каталог, в котором установлено ПО Oracle) для создания уникального ключа при подсоединении области SGA. Если значение ORACLE_SID или ORACLE_HOME задано неправильно, выдается сообщение об ошибке ORACLE NOT AVAILABLE, поскольку невозможно подключиться к сегменту разделяемой памяти, определяемому этим "магическим" ключом. В ОС Windows разделяемая память используется не так, как в ОС UNIX, но параметр SID все равно важен. В одном и том же базовом каталоге ORACLE_HOME может быть несколько баз данных, так что необходимо иметь возможность уникально идентифицировать их и соответствующие конфигурационные файлы.
Файлы журнала повторного выполнения принципиально важны для базы данных Oracle. Это журналы транзакций базы данных. Они используются только для восстановления при сбое экземпляра или носителя или при поддержке резервной базы данных на случай сбоев. Если на сервере, где работает СУБД, отключится питание и вследствие этого произойдет сбой экземпляра, для восстановления системы в состояние, непосредственно предшествующее отключению питания, сервер Oracle при повторном запуске будет использовать оперативные журналы повторного выполнения. Если диск, содержащий файлы данных, полностью выйдет из строя, для восстановления резервной копии этого диска на соответствующий момент времени сервер Oracle, помимо оперативных журналов повторного выполнения, будет использовать также архивные. Кроме того, при случайном удалении таблицы или какой-то принципиально важной информации, если эта операция зафиксирована, с помощью оперативных и архивных журналов повторного выполнения можно восстановить данные из резервной копии на момент времени, непосредственно предшествующий удалению.
Практически каждое действие, выполняемое в СУБД Oracle, генерирует определенные данные повторного выполнения, которые надо записать в оперативные файлы журнала повторного выполнения. При вставке строки в таблицу конечный результат этой операции записывается в журналы повторного выполнения. При удалении строки записывается факт удаления. При удалении таблицы в журнал повторного выполнения записываются последствия этого удаления. Данные из удаленной таблицы не записываются, но рекурсивные SQL-операторы, выполняемые сервером Oracle при удалении таблицы, генерируют определенные данные повторного выполнения. Например, при этом сервер Oracle удалит строку из таблицы SYS.OBJ$, и это удаление будет отражено в журнале.
Некоторые операции могут выполняться в режиме с минимальной генерацией данных повторного выполнения. Например, можно создать индекс с атрибутом NOLOGGING. Это означает, что первоначальное создание этого индекса не будет записываться в журнал, но любые инициированные при этом рекурсивные SQL-операторы, выполняемые сервером Oracle, — будут. Например, вставка в таблицу SYS.OBJ$ строки, соответствующей индексу, в журнал записываться не будет. Однако последующие изменения индекса при выполнении SQL-операторов INSERT, UPDATE и DELETE, будут записываться в журнал.
Есть два типа файлов журнала повторного выполнения: оперативные и архивные. В главе 5 мы еще раз затронем тему журналов повторного выполнения и сегментов отката, чтобы понять, как они влияют на разработку приложений. Пока же мы опишем, что собой представляют журналы повторного выполнения и их назначение.
Фиксированная область SGA — это часть области SGA, размер которой зависит от платформы и версии. Она "компилируется" в двоичный модуль сервера Oracle при установке (отсюда и название — "фиксированная"). Фиксированная область SGA содержит переменные, которые указывают на другие части SGA, а также переменные, содержащие значения различных параметров. Размером фиксированной области SGA (как правило, очень небольшой) управлять нельзя. Можно рассматривать эту область как "загрузочную" часть SGA, используемую сервером Oracle для поиска других компонентов SGA.
Экземпляр Oracle состоит из двух частей: области SGA и набора фоновых процессов. Фоновые процессы выполняют рутинные задачи сопровождения, обеспечивающие работу СУБД. Есть, например, процесс, автоматически поддерживающий буферный кеш и при необходимости записывающий блоки данных на диск. Есть процесс, копирующий заполненный файл оперативного журнала повторного выполнения в архив. Еще один процесс отвечает за очистку всех структур, которые использовались завершившимися процессами, и т.д. Каждый из этих процессов решает конкретную задачу, но работает в координации с остальными. Например, когда процесс, записывающий файлы журнала, заполняет один журнал и переходит на следующий, он уведомляет процесс, отвечающий за архивирование заполненного журнала, что для него есть работа.
Есть два класса фоновых процессов: предназначенные исключительно для решения конкретных задач (как только что описанные) и решающие множество различных задач. Например, есть фоновый процесс, обеспечивающий работу внутренних очередей заданий в Oracle. Этот процесс контролирует очередь заданий и выполняет находящиеся в ней задания. Во многом он похож на выделенный сервер, но без подключения к клиенту. Сейчас мы рассмотрим все эти фоновые процессы, начиная с тех, которые выполняют конкретную задачу, а затем перейдем к процессам "общего назначения".
На следующей схеме представлены фоновые процессы экземпляра Oracle, имеющие конкретное назначение:
+------------+ [LMD0]--------------------------->| кластерные |+ ^ [LCKn]------------------->| экземпляры | ^ [BSP]----------->+------------+| | | ^ [LMON]--> +------------+ | | | ^ | | | | v | | v +--------------------------------------------+ PMON<----------->| SGA | | +--------------+ +---------------+ | SMON<----------->| | буферный кеш | | буфер журнала | | | +--------------+ +---------------+ | [RECO]<--------->| | | | | +-------+---------------------+--------------+ | ^ | | ^ | | | | | | v v v v | CKPT DBWn LGWR [ARCn]----+ | | | | ^ | v v v v | v +-------------+ +-------------------+ +-------------+ | +----------+ | удаленная | | файлы базы данных |+ | оперативный | | | архивные | | база данных | | + | журнал | | | журналы | +-------------+ +-------------------+ +-------------+ -+-+ +----------+ +------------------+| |0101010101010| +-----------------+ |1010101010101| +-------------+
Вы не обязательно увидите все эти процессы сразу после запуска своего экземпляра, но большинство из них работает в каждом экземпляре. Процесс ARCn (архиватор) запускается только при работе в режиме архивирования журналов (Archive Log Mode) при включенном автоматическом архивировании. Процессы LMD0, LCKn, LMON и BSP (подробнее о них — ниже) запускаются только при работе с Oracle Parallel Server (конфигурация сервера Oracle, поддерживающая несколько экземпляров на различных машинах в кластерной среде), если открывается одна и та же база данных. Для простоты на схеме не показаны процессы диспетчеров MTS (Dnnn) и разделяемых серверов (Snnn). Поскольку мы только что детально их рассмотрели, они не показаны, чтобы упростить схему. Предыдущая схема показывает, что можно "увидеть" при запуске экземпляра Oracle, если база данных смонтирована и открыта. Например, в моей UNIX-системе сразу после запуска экземпляра имеются следующие процессы:
$ /bin/ps -aef | grep 'ora_.*_ora8i$' ora816 20642 1 0 Jan 17 ? 5:02 ora_arc0_ora8i ora816 20636 1 0 Jan 17 ? 265:44 ora_snp0_ora8i ora816 20628 1 0 Jan 17 ? 92:17 ora_lgwr_ora8i ora816 20626 1 0 Jan 17 ? 9:23 ora_dbw0_ora8i ora816 20638 1 0 Jan 17 ? 0:00 ora_s000_ora8i ora816 20634 1 0 Jan 17 ? 0:04 ora_reco_ora8i ora816 20630 1 0 Jan 17 ? 6:56 ora_ckpt_ora8i ora816 20632 1 0 Jan 17 ? 186:44 ora_smon_ora8i ora816 20640 1 0 Jan 17 ? 0:00 ora_d000_ora8i ora816 20624 1 0 Jan 17 ? 0:05 ora_pmon_ora8i
Как человеку, участвовавшему во многих тестированиях производительности, преимущества ограничения степени параллелизма мне очевидны. При тестировании клиенты просят запустить как можно больше пользователей, пока система не перестанет работать. Одним из результатов такого рода тестирования является диаграмма, показывающая зависимость количества транзакций от количества одновременно работающих пользователей:
Транзакции в секунду
^ | Максимальный параллелизм
| | | __ | - - | / \ | / \ | / \ | / | | / \ | / \ |/ +---------------------------------> Одновременно работающие пользователи
Сначала при добавлении одновременно работающих пользователей количество транзакций растет. С какого-то момента, однако, добавление новых пользователей не увеличивает количества выполняемых в секунду транзакций: оно стабилизируется. Пропускная способность достигла максимума, и время ожидания ответа начинает расти (каждую секунду выполняется то же количество транзакций, но пользователи получают результаты со все возрастающей задержкой. При дальнейшем добавлении пользователей пропускная способность начинает падать. Количество одновременно работающих пользователей перед началом этого падения и является максимально допустимой степенью параллелизма в системе. Дальше система переполняется запросами, и образуются очереди. С этого момента система не справляется с нагрузкой. Не только существенно увеличивается время ответа, но и начинает падать пропускная способность системы. Если ограничить количество одновременно работающих пользователей до числа, непосредственно предшествующего падению, можно обеспечить максимальную пропускную способность и приемлемое время ответа для большинства пользователей. Режим MTS позволяет ограничить максимальную степень параллелизма в системе до этого количества одновременно работающих пользователей.
Java-пул - это самый новый пул памяти в Oracle 8i. Он был добавлен в версии 8.1.5 для поддержки работы Java-машины в базе данных. Если поместить хранимую процедуру на языке Java или компонент EJB (Enterprise JavaBean) в базу данных, сервер Oracle будет использовать этот фрагмент памяти при обработке соответствующего кода. Одним из недостатков первоначальной реализации Java-пула в Oracle 8.1.5 было то, что он не отображался командой SHOW SGA и не был представлен строками в представлении V$SGASTAT. В то время это особенно сбивало с толку, поскольку параметр инициализации JAVA_POOL_SIZE, определяющий размер этой структуры, имел стандартное значение 20 Мбайт. Это заставляло людей гадать, почему область SGA занимает оперативной памяти на 20 Мбайт больше, чем следует.
Начиная с версии 8.1.6, однако, Java-пул виден в представлении V$SGASTAT, а также в результатах выполнения команды SHOW SGA. Параметр инициализации JAVA_POOL_SIZE используется для определения фиксированного объема памяти, отводящегося для Java-кода и данных сеансов. В Oracle 8.1.5 этот параметр мог иметь значения от 1 Мбайта до 1 Гбайт. В Oracle 8.1.6 и последующих версиях диапазон допустимых значений уже 32 Кбайта-1 Гбайт. Это противоречит документации, где по-прежнему указан устаревший минимум — 1 Мбайт.
Java-пул используется по-разному, в зависимости от режима работы сервера Oracle. В режиме выделенного сервера Java-пул включает разделяемую часть каждого Java-класса, использованного хоть в одном сеансе. Эти части только читаются (векторы выполнения, методы и т.д.) и имеют для типичных классов размер от 4 до 8 Кбайт.
Таким образом, в режиме выделенного сервера (который, как правило, и используется, если в приложениях применяются хранимые процедуры на языке Java) объем общей памяти для Java-пула имеет весьма невелик; его можно определить исходя из количества используемых Java-классов. Учтите, что информация о состоянии сеансов при работе в режиме разделяемого сервера в области SGA не сохраняется, поскольку эти данные находятся в области UGA, а она, если вы помните, в режиме разделяемого сервера является частью области PGA.
Процесс LCKn используется исключительно в среде OPS. Он подобен по функциям описанному выше процессу LMD, но обрабатывает запросы ко всем остальным глобальным ресурсам, кроме буферного кеша.
Процесс LGWR отвечает за сброс на диск содержимого буфера журнала повторного выполнения, находящегося в области SGA. Он делает это:
раз в три секунды;
при фиксации транзакции;
при заполнении буфера журнала повторного выполнения на треть или при записи в него 1 Мбайта данных.
Поэтому создание слишком большого буфера журнала повторного выполнения не имеет смысла: сервер Oracle никогда не сможет использовать его целиком. Все журналы записываются последовательно, а не вразброс, как вынужден выполнять ввод-вывод процесс DBWn. Запись большими пакетами, как в этом случае, намного эффективнее, чем запись множества отдельных блоков в разные части файла. Это одна из главных причин выделения процесса LGWR
и журнала повторного выполнения. Эффективность последовательной записи измененных байтов перевешивает расход ресурсов на дополнительный ввод-вывод. Сервер Oracle мог бы записывать блоки данных непосредственно на диск при фиксации, но это потребовало бы записи множества разбросанных блоков, а это существенно медленнее, чем последовательная запись изменений процессом LGWR.
Этот процесс используется исключительно в среде OPS. Процесс LMD управляет глобальными блокировками и глобальными ресурсами для буферного кеша в кластерной среде. Другие экземпляры посылают локальному процессу LMD
запросы с требованием снять блокировку или определить, кто ее установил. Процесс LMD также выявляет и снимает глобальные взаимные блокировки.
Этот процесс используется исключительно в среде OPS. Процесс LMON
контролирует все экземпляры кластера для выявления сбоя экземпляра. Затем он вместе с диспетчером распределенных блокировок (Distributed Lock Manager — DLM), используемым аппаратным обеспечением кластера, восстанавливает глобальные блокировки, которые удерживаются сбойным экземпляром.
Каждый экземпляр Oracle имеет одну большую область памяти, которая называется SGA, System Global Area — глобальная область системы. Это большая разделяемая структура, к которой обращаются все процессы Oracle. Ее размер варьируется от нескольких мегабайт в небольших тестовых системах до сотен мегабайт в системах среднего размера и множества гигабайт в больших системах.
В ОС UNIX область SGA — это физический объект, которую можно "увидеть" с помощью утилит командной строки. Физически область SGA реализована как сегмент разделяемой памяти — отдельный фрагмент памяти, к которому могут подключаться процессы. При отсутствии процессов Oracle вполне допустимо иметь в системе область SGA; память существует отдельно от них. Однако наличие области SGA при отсутствии процессов Oracle означает, что произошел тот или иной сбой экземпляра. Эта ситуация — нештатная, но она бывает. Вот как "выглядит" область SGA в ОС UNIX:
$ ipcs -mb IPC status from <running system> as of Mon Feb 19 14:48:26 EST 2001 T ID KEY MODE OWNER GROUP SEGSZ Shared Memory: m 105 0xf223dfc8 --rw-r----- ora816 dba 186802176
В ОС Windows увидеть область SGA, как в ОС UNIX, нельзя. Поскольку на этой платформе экземпляр Oracle работает как единый процесс с одним адресным пространством, область SGA выделяется как приватная память процесса ORACLE.EXE. С помощью диспетчера задач Windows (Task Manager) или другого средства контроля производительности можно узнать, сколько памяти выделено процессу ORACLE.EXE, но нельзя определить, какую часть по отношению к другим выделенным структурам памяти занимает область SGA.
В самой СУБД Oracle можно определить размер области SGA независимо от платформы. Есть еще одно "магическое" представление V$, именуемое V$SGASTAT. Вот как его можно использовать:
tkyte@TKYTE816> compute sum of bytes on pool tkyte@TKYTE816> break on pool skip 1 tkyte@TKYTE816> select pool, name, bytes 2 from v$sgastat 3 order by pool, name;
POOL NAME BYTES ----------- ------------------------------ ---------- java pool free memory 18366464 memory in use 2605056 *********** ---------- sum 20971520
Как уже было сказано, PGA — это область памяти процесса. Эта область памяти используется одним процессом или одним потоком. Она недоступна ни одному из остальных процессов/потоков в системе. Область PGA обычно выделяется с помощью библиотечного вызова malloc() языка C и со временем может расти (или уменьшаться). Область PGA никогда не входит в состав области SGA — она всегда локально выделяется процессом или потоком.
Область памяти UGA хранит состояние сеанса, поэтому всегда должна быть ему доступна. Местонахождение области UGA зависит исключительно от конфигурации сервера Oracle. Если сконфигурирован режим MTS, область UGA должна находиться в структуре памяти, доступной всем процессам, следовательно, в SGA. В этом случае сеанс сможет использовать любой разделяемый сервер, так как каждый из них сможет прочитать и записать данные сеанса. При подключении к выделенному серверу это требование общего доступа к информации о состоянии сеанса снимается, и область UGA становится почти синонимом PGA, — именно там информация о состоянии сеанса и будет располагаться. Просматривая статистическую информацию о системе, можно обнаружить, что при работе в режиме выделенного сервера область UGA входит в PGA (размер области PGA будет больше или равен размеру используемой памяти UGA — размер UGA будет учитываться при определении размера области PGA).
Размер области PGA/UGA определяют параметры уровня сеанса в файле init.ora: SORT_AREA_SIZE и SORT_AREA_RETAINED_SIZE. Эти два параметра управляют объемом пространства, используемым сервером Oracle для сортировки данных перед сбросом на диск, и определяют объем сегмента памяти, который не будет освобожден по завершении сортировки. SORT_AREA_SIZE обычно выделяется в области PGA, а SORT_AREA_RETAINED_SIZE — в UGA. Управлять размером областей UGA/PGA можно с помощью запроса к специальному представлению V$ сервера Oracle. Эти представления называют также представлениями динамической производительности. Подробнее эти представления V$
рассматриваются в главе 10. С помощью представлений V$ можно определить текущее использование памяти под области PGA и UGA. Например, запущен небольшой тестовый пример, требующий сортировки большого объема данных. Просмотрев несколько первых строк данных, я решил не извлекать остальное результирующее множество. После этого можно сравнить использование памяти "до" и "после":
В каждой базе данных Oracle есть как минимум два оперативных файла журнала повторного выполнения. Эти оперативные файлы журнала повторного выполнения имеют фиксированный размер и используются циклически. Сервер Oracle выполняет запись в файл журнала 1, а когда доходит до конца этого файла, — переключается на файл журнала 2 и переписывает его содержимое от начала до конца. Когда заполнен файл журнала 2, сервер переключается снова на файл журнала 1 (если имеется всего два файла журнала повторного выполнения; если их три, сервер, разумеется, переключится на третий файл).
Переход с одного файла журнала на другой называется переключением журнала. Важно отметить, что переключение журнала может вызвать временное "зависание" плохо настроенной базы данных. Поскольку журналы повторного выполнения используются для восстановления транзакций в случае сбоя, перед повторным использованием файла журнала необходимо убедиться, что его содержимое не понадобится в случае сбоя. Если сервер Oracle "не уверен", что содержимое файла журнала не понадобится, он приостанавливает на время изменения в базе данных и убеждается, что данные, "защищаемые" этой информацией повторного выполнения, записаны на диск. После этого обработка возобновляется, и файл журнала переписывается. Мы затронули ключевое понятие баз данных — обработку контрольной точки. Чтобы понять, как используются оперативные журналы повторного выполнения, надо разобраться с обработкой контрольной точки, использованием буферного кеша базы данных и рассмотреть функции процесса записи блоков базы данных (Database Block Writer - DBWn). Буферный кеш и процесс DBWn подробно рассматриваются ниже, но мы все равно забегаем вперед, так что имеет смысл поговорить о них.
В буферном кеше базы данных временно хранятся блоки базы данных. Это структура в области SGA разделяемой памяти экземпляра Oracle. При чтении блоки запоминаются в этом кеше (предполагается, что в дальнейшем их не придется читать с диска). Буферный кеш — первое и основное средство настройки производительности сервера. Он существует исключительно для ускорения очень медленного процесса ввода-вывода. При изменении блока путем обновления одной из его строк изменения выполняются в памяти, в блоках буферного кеша. Информация, достаточная для повторного выполнения этого изменения, записывается в буфер журнала повторного выполнения — еще одну структуру данных в области SGA. При фиксации изменений с помощью оператора COMMIT сервер Oracle не записывает на диск все измененные блоки в области SGA. Он только записывает в оперативные журналы повторного выполнения содержимое буфера журнала повторного выполнения. Пока измененный блок находится в кеше, а не на диске, содержимое соответствующего оперативного журнала может быть использовано в случае сбоя экземпляра. Если сразу после фиксации изменения отключится питание, содержимое буферного кеша пропадет.
Этот процесс отвечает за очистку после нештатного прекращения подключений. Например, если выделенный сервер "падает" или, получив сигнал, прекращает работу, именно процесс PMON освобождает ресурсы. Процесс PMON
откатит незафиксированные изменения, снимет блокировки и освободит ресурсы в области SGA, выделенные прекратившему работу процессу.
Помимо очистки после прерванных подключений, процесс PMON контролирует другие фоновые процессы сервера Oracle и перезапускает их при необходимости (если это возможно). Если разделяемый сервер или диспетчер сбоит (прекращает работу), процесс PMON запускает новый процесс (после очистки структур сбойного процесса). Процесс PMON следит за всеми процессами Oracle и либо перезапускает их, либо прекращает работу экземпляра, в зависимости от ситуации. Например, в случае сбоя процесса записи журнала повторного выполнения (LGWR) экземпляр надо перезапускать. Это серьезная ошибка и самое безопасное — немедленно прекратить работу экземпляра, предоставив исправление данных штатному процессу восстановления. Это происходит очень редко, и о случившемся надо немедленно сообщить службе поддержки Oracle.
Еще одна функция процесса PMON в экземпляре (версия Oracle 8i) — регистрировать экземпляр в процессе прослушивания протокола Net8. При запуске экземпляра процесс PMON опрашивает известный порт (если явно не указан другой), чтобы убедиться, запущен и работает ли процесс прослушивания. Известный/стандартный порт, используемый сервером Oracle, — порт 1521. А что произойдет, если процесс прослушивания запущен на другом порту? В этом случае используется тот же механизм, но адрес процесса прослушивания необходимо указать явно с помощью параметра инициализации LOCAL_LISTENER. Если процесс прослушивания запущен, процесс PMON связывается с ним и передает соответствующие параметры, например имя службы.
Теперь мы готовы рассмотреть последний класс процессов Oracle — подчиненные процессы. В сервере Oracle есть два типа подчиненных процессов — ввода-вывода (I/O slaves) и параллельных запросов (Parallel Query slaves).
В Oracle 7.1 появились средства распараллеливания запросов к базе данных. Речь идет о возможности создавать для SQL-операторов типа SELECT, CREATE TABLE, CREATE INDEX, UPDATE и т.д. план выполнения, состоящий из нескольких планов, которые можно выполнять одновременно. Результаты выполнения этих планов объединяются. Это позволяет выполнить операцию за меньшее время, чем при последовательном выполнении. Например, если имеется большая таблица, разбросанная по десяти различным файлам данных, 16-процессорный сервер, и необходимо выполнить к этой таблице запрос, имеет смысл разбить план выполнения этого запроса на 16 небольших частей и полностью использовать возможности сервера. Это принципиально отличается от использования одного процесса для последовательного чтения и обработки всех данных.
Подчиненные процессы ввода-вывода используются для эмуляции асинхронного ввода-вывода в системах или на устройствах, которые его не поддерживают. Например, ленточные устройства (чрезвычайно медленно работающие) не поддерживают асинхронный ввод-вывод. Используя подчиненные процессы ввода-вывода, можно сымитировать для ленточных устройств такой способ работы, который операционная система обычно обеспечивает для дисков. Как и в случае действительно асинхронного ввода-вывода, процесс, записывающий на устройство, накапливает большой объем данных в виде пакета и отправляет их на запись. Об их успешной записи процесс (на этот раз — подчиненный процесс ввода-вывода, а не ОС) сигнализирует исходному вызвавшему процессу, который удаляет этот пакет из списка данных, ожидающих записи. Таким образом, можно существенно повысить производительность, поскольку именно подчиненные процессы ввода-вывода ожидают завершения работы медленно работающего устройства, а вызвавший их процесс продолжает выполнять другие важные действия, собирая данные для следующей операции записи.
Подчиненные процессы ввода-вывода используются в нескольких компонентах Oracle 8i — процессы DBWn и LGWR используют их для имитации асинхронного ввода-вывода, а утилита RMAN (Recovery MANager — диспетчер восстановления) использует их при записи на ленту.
Использование подчиненных процессов ввода-вывода управляется двумя параметрами инициализации.
BACKUP_TAPE_IO_SLAVES. Этот параметр указывает, используются ли подчиненные процессы ввода-вывода утилитой RMAN для резервного копирования или восстановления данных с ленты. Поскольку этот параметр предназначен для ленточных устройств, а к ленточным устройствам в каждый момент времени может обращаться только один процесс, он — булева типа, а не задает количество используемых подчиненных процессов, как можно было ожидать. Утилита RMAN
запускает необходимое количество подчиненных процессов, в соответствии с количеством используемых физических устройств. Если параметр BACKUP_TAPE_IO_SLAVES имеет значение TRUE, то для записи или чтения с ленточного устройства используется подчиненный процесс ввода-вывода. Если этот параметр имеет (стандартное) значение FALSE, подчиненные процессы ввода-вывода не используются при резервном копировании. К ленточному устройству тогда обращается фоновый процесс, выполняющий резервное копирование.
DBWn_IO_SLAVES. Задает количество подчиненных процессов ввода-вывода, используемых процессом DBWn. Процесс DBWn и его подчиненные процессы всегда записывают на диск измененные буфера буферного кеша. По умолчанию этот параметр имеет значение 0, и подчиненные процессы ввода-вывода не используются.
Осталось рассмотреть последний элемент "головоломки". Мы изучили организацию базы данных и набор образующих ее физических файлов. Разбираясь с использованием памяти сервером Oracle, рассмотрели половину экземпляра. Оставшийся компонент архитектуры — набор процессов, образующий вторую половину экземпляра. Некоторые из этих процессов, например процесс записи блоков в базу данных (DBWn) и процесс записи журнала (LGWR), уже упоминались. Здесь мы более детально рассмотрим функцию каждого процесса: что и почему они делают. В этом разделе "процесс" будет использоваться как синоним "потока" в операционных системах, где сервер Oracle реализован с помощью потоков. Так, например, если описывается процесс DBWn, в среде Windows ему соответствует поток DBWn.
В экземпляре Oracle есть три класса процессов.
Серверные процессы. Они выполняют запросы клиентов. Мы уже затрагивали тему выделенных и разделяемых серверов. И те, и другие относятся к серверным процессам.
Фоновые процессы. Это процессы, которые начинают выполняться при запуске экземпляра и решают различные задачи поддержки базы данных, такие как запись блоков на диск, поддержка оперативного журнала повторного выполнения, удаление прекративших работу процессов и т.д.
Подчиненные процессы. Они подобны фоновым процессам, но выполняют, кроме того, действия от имени фонового или серверного процесса.
Мы рассмотрим все эти процессы и постараемся выяснить, какую роль они играют в экземпляре.
Процесс QMNn по отношению к таблицам AQ выполняет ту же роль, что и процесс SNPn по отношению к таблице заданий. Этот процесс контролирует очереди и уведомляет ожидающие сообщений процессы о том, что доступно сообщение. Он также отвечает за распространение очередей — возможность переместить сообщение, поставленное в очередь в одной базе данных, в другую базу данных для извлечения из очереди.
Монитор очередей — это необязательный фоновый процесс. Параметр инициализации AQ_TM_PROCESS позволяет создать до десяти таких процессов с именами QMN0, ..., QMN9. По умолчанию процессы QMNn
не запускаются.
Разделяемый пул — один из наиболее важных фрагментов памяти в области SGA, особенно для обеспечения производительности и масштабируемости. Слишком маленький разделяемый пул может снизить производительность настолько, что система будет казаться зависшей. Слишком большой разделяемый пул может привести к такому же результату. Неправильное использование разделяемого пула грозит катастрофой.
Итак, что же такое разделяемый пул? В разделяемом пуле сервер Oracle кеширует различные "программные" данные. Здесь кешируются результаты разбора запроса. Перед повторным разбором запроса сервер Oracle просматривает разделяемый пул в поисках готового результата. Выполняемый сеансом PL/SQL-код тоже кешируется здесь, так что при следующем выполнении не придется снова читать его с диска. PL/SQL-код в разделяемом пуле не просто кешируется, — появляется возможность его совместного использования сеансами. Если 1000 сеансов выполняют тот же код, загружается и совместно используется всеми сеансами лишь одна копия этого кода. Сервер Oracle хранит в разделяемом пуле параметры системы. Здесь же хранится кеш словаря данных, содержащий информацию об объектах базы данных. Короче, в разделяемом пуле хранится все, кроме продуктов питания.
Разделяемый пул состоит из множества маленьких (около 4 Кбайт) фрагментов памяти. Память в разделяемом пуле управляется по принципу давности использования (LRU). В этом отношении она похожа на буферный кеш: если фрагмент не используется, он теряется. Стандартный пакет DBMS_SHARED_POOL
позволяет изменить это и принудительно закрепить объекты в разделяемом пуле. Это позволяет загрузить часто используемые процедуры и пакеты при запуске сервера и сделать так, чтобы они не выбрасывались из пула как устаревшие. Обычно, если в течение определенного периода времени фрагмент памяти в разделяемом пуле не использовался, он выбрасывается как устаревший. Даже PL/SQL-код, который может иметь весьма большой размер, управляется механизмом постраничного устаревания, так что при выполнении кода очень большого пакета необходимый код загружается в разделяемый пул небольшими фрагментами. Если в течение продолжительного времени он не используется, то в случае переполнения выбрасывается из разделяемого пула, а пространство выделяется для других объектов.
Процесс RECO имеет очень конкретную задачу: он восстанавливает транзакции, оставшиеся в готовом состоянии из-за сбоя или потери связи в ходе двухэтапной фиксации (2PC). 2PC — это распределенный протокол, позволяющий неделимо фиксировать изменения в нескольких удаленных базах данных. Он пытается максимально снизить вероятность распределенного сбоя перед фиксацией. При использовании протокола 2PC между N базами данных одна из баз данных обычно (но не всегда) та, к которой первоначально подключился клиент, становится координатором. Соответствующий сервер опрашивает остальные N -1 серверов, готовы ли они фиксировать транзакцию. Фактически, этот сервер связывается с остальными N - 1 серверами и просит их подготовиться к фиксации. Каждый из N -1 серверов сообщает о своем состоянии готовности как да (YES) или нет (NO). Если любой из серверов вернул NO, вся транзакция откатывается. Если все серверы вернули YES, координатор рассылает всем N - 1 серверам сообщение о постоянной фиксации.
Если серверы ответили YES и подготовились к фиксации, но до получения директивы о фактической фиксации от координатора происходит сбой сети или возникает какая-то другая ошибка, транзакция становится сомнительной
(in-doubt) распределенной транзакцией. Протокол 2PC старается сократить до минимума время, в течение которого это может произойти, но не может полностью предотвратить сомнительные транзакции. Если сбой произойдет в определенном месте и в определенное время, дальнейшую обработку сомнительной транзакции выполняет процесс RECO. Он пытается связаться с координатором транзакции, чтобы узнать ее исход. До этого транзакция остается незафиксированной. Связавшись с координатором транзакции, процесс RECO восстановит либо откатит ее.
Если связаться с координатором долго не удается и имеется ряд сомнительных транзакций, их можно зафиксировать или откатить вручную. Это приходится делать, поскольку сомнительная распределенная транзакция может вызвать блокирование читающих пишущими (единственный случай в СУБД Oracle). Ваш администратор базы данных должен связаться с администратором другой базы данных и попросить его определить состояние сомнительных транзакций. Затем администратор базы данных может зафиксировать или откатить их, предоставив все остальное процессу RECO.
Если система не перегружена и нет необходимости использовать режим MTS для обеспечения необходимой функциональности, лучше использовать выделенный сервер. Выделенный сервер проще устанавливать, и упрощается настройка производительности. Есть ряд операций, которые можно выполнять только при подключении в режиме выделенного сервера, так что в любом экземпляре надо поддерживать либо оба режима, либо только режим выделенного сервера.
С другой стороны, если необходимо поддерживать большое количество пользователей и известно, что эксплуатировать систему придется в режиме MTS, я рекомендую разрабатывать и тестировать ее тоже в режиме MTS. Если система разрабатывалась в режиме разделяемого сервера и никогда не тестировалась в режиме MTS, вероятность неудачи повышается. Испытывайте систему в рабочих условиях; тестируйте ее производительность; проверьте, хорошо ли она работает в режиме MTS. То есть, проверьте, не монополизирует ли она надолго разделяемые серверы. Обнаруженные на стадии разработки недостатки устранить гораздо проще, чем при внедрении. Для сокращения времени работы процесса можно использовать средства расширенной обработки очередей (Advanced Queues — AQ), но это надо учесть в проекте приложения. Такие вещи лучше делать на этапе разработки.
Если в приложении уже используется пул подключений (например, пул подключений компонентов J2EE) и размер этого пула определен верно, использование режима MTS только снизит производительность. Размер пула подключений уже рассчитан с учетом максимального количества одновременных подключений, поэтому необходимо, чтобы каждое из этих подключений выполнялось непосредственно к выделенному серверу. Иначе один пул подключений будет просто подключаться к другому пулу подключений.
Трудно решить, с какого компонента сервера начать описание. Процессы используют область SGA, поэтому рассматривать SGA до процессов не имеет смысла. С другой стороны, при описании процессов и их функционирования придется ссылаться на компоненты SGA. Они тесно взаимосвязаны. С файлами работают процессы, и их нет смысла описывать, пока не объяснено, что делают процессы. Ниже определены некоторые термины и сделан общий обзор сервера Oracle, после чего подробно рассматриваются отдельные компоненты.
Два термина в контексте Oracle вызывают большую путаницу. Речь идет о терминах "база данных" и "экземпляр". В соответствии с принятой в Oracle терминологией, эти понятия определяются так:
база данных - набор физических файлов операционной системы;
экземпляр - набор процессов Oracle и область SGA.
Эти два термина иногда взаимозаменяемы, но представляют принципиально разные концепции. Взаимосвязь между ними такова, что база данных может быть смонтирована и открыта в нескольких экземплярах. Экземпляр может смонтировать и открыть только одну базу данных в каждый момент времени. Не обязательно отрывать и монтировать одну и ту же базу данных при каждом запуске экземпляра.
Стало еще непонятнее? Вот ряд примеров, которые помогут прояснить ситуацию. Экземпляр — это набор процессов операционной системы и используемая ими память. Все эти процессы могут работать с базой данных, которая представляет собой просто набор файлов (файлов данных, временных файлов, файлов журнала повторного выполнения, управляющих файлов). В каждый момент времени с экземпляром связан только один набор файлов. В большинстве случаев обратное утверждение тоже верно; с базой данных работает только один экземпляр. В случае же использования параллельного сервера Oracle (Oracle Parallel Server — OPS), опции Oracle, позволяющей серверу функционировать на нескольких компьютерах в кластерной среде, одна и та же база данных может быть одновременно смонтирована и открыта несколькими экземплярами. Это делает возможным доступ к базе данных одновременно с нескольких компьютеров. Oracle Parallel Server позволяет создавать системы с высокой доступностью данных и, при условии правильной реализации, очень масштабируемые. Рассмотрение опции OPS здесь не предусмотрено, поскольку для описания особенностей ее реализации потребовалась бы отдельная книга.
Мы уже бегло рассматривали эти процессы ранее при обсуждении выделенных и разделяемых серверов. Здесь мы еще раз опишем два вида серверных процессов и более детально рассмотрим их архитектуру.
Выделенные и разделяемые серверы решают одну и ту же задачу: обрабатывают передаваемые им SQL-операторы. При получении запроса SELECT * FROM EMP
именно выделенный/разделяемый сервер Oracle будет разбирать его и помещать в разделяемый пул (или находить соответствующий запрос в разделяемом пуле). Именно этот процесс создает план выполнения запроса. Этот процесс реализует план запроса, находя необходимые данные в буферном кеше или считывая данные в буферный кеш с диска. Такие серверные процессы можно назвать "рабочими лошадками" СУБД. Часто именно они потребляют основную часть процессорного времени в системе, поскольку выполняют сортировку, суммирование, соединения — в общем, почти все.
В режиме выделенного сервера имеется однозначное соответствие между клиентскими сеансами и серверными процессами (или потоками). Если имеется 100 сеансов на UNIX-машине, будет 100 процессов, работающих от их имени. Графически это можно представить так:
...
С клиентским приложением скомпонованы библиотеки Oracle. Они обеспечивают функциональный интерфейс (Application Program Interface — API) для взаимодействия с базой данных. Функции API "знают", как передавать запрос к базе данных и обрабатывать возвращаемый курсор. Они обеспечивают преобразование запросов пользователя в передаваемые по сети пакеты, обрабатываемые выделенным сервером. Эти функции обеспечивает компонент Net8 — сетевое программное обеспечение/протокол, используемое Oracle для клиент-серверной обработки (даже в n-звенной архитектуре есть место для клиент-серверного взаимодействия). Сервер Oracle использует такую архитектуру, даже если протокол Net8 не нужен. То есть, когда клиент и сервер работают на одной и той же машине, используется эта двухпроцессная (известная также как двухзадачная — two-task) архитектура. Эта архитектура обеспечивает два преимущества.
Эти фоновые процессы необязательны — они запускаются в случае необходимости. Они реализуют средства, необязательные для штатного функционирования базы данных. Использование этих средств инициируется явно или косвенно, при использовании возможности, требующей их запуска.
Служебных фоновых процессов — два. Один из них запускает посланные на выполнение задания. В СУБД Oracle встроена очередь пакетных заданий, позволяющая выполнять по расписанию однократные или периодические задания. Другой процесс поддерживает и обрабатывает таблицы очереди, используемые средствами расширенной поддержки очередей (Advanced Queuing — AQ). Средства AQ обеспечивают встроенные возможности обмена сообщениями между сеансами базы данных.
Эти процессы можно увидеть в среде ОС UNIX, как и любой другой фоновый процесс, с помощью команды ps. В представленных ранее результатах выполнения команды ps можно видеть, что у меня в экземпляре работает один процесс очереди заданий (ora_snp0_ora8I) и ни одного процесса очереди.
SMON — это процесс, занимающийся всем тем, от чего "отказываются" остальные процессы. Это своего рода "сборщик мусора" для базы данных. Вот некоторые из решаемых им задач.
Очистка временного пространства. С появлением по-настоящему временных табличных пространств эта задача упростилась, но она не снята с повестки дня полностью. Например, при построении индекса выделяемые ему в ходе создания экстенты помечаются как временные (TEMPORARY). Если выполнение оператора CREATE INDEX прекращено досрочно по какой-либо причине, процесс SMON
должен эти экстенты освободить. Есть и другие операции, создающие временные экстенты, за очистку которых также отвечает процесс SMON.
Восстановление после сбоев. Процесс SMON после сбоя восстанавливает экземпляр при перезапуске.
Дефрагментация свободного пространства. При использовании табличных пространств, управляемых по словарю, процесс SMON заменяет расположенные подряд свободные экстенты одним "большим" свободным экстентом. Это происходит только в табличном пространстве, управляемом по словарю и имеющем стандартную конструкцию хранения с ненулевым значением параметра PCTINCREASE.
Восстановление транзакций, затрагивающих недоступные файлы. Эта задача аналогична той, которая возникает при запуске базы данных. Процесс SMON
восстанавливает сбойные транзакции, пропущенные при восстановлении экземпляра после сбоя по причине недоступности файлов для восстановления. Например, файл мог быть на недоступном или на не смонтированном диске. Когда файл будет доступен, процесс SMON восстановит его.
Восстановление сбойного экземпляра в OPS. В конфигурации Oracle Parallel Server, если одна из машин кластера останавливается (на ней происходит сбой), другая машина в экземпляре откроет файлы журнала повторного выполнения этой сбойной машины и восстановит все данные этой машины.
Очистка таблицы OBJ$. OBJ$ — низкоуровневая таблица словаря данных, содержащая записи практически для каждого объекта (таблицы, индекса, триггера, представления и т.д.) базы данных. Часто там встречаются записи, представляющие удаленные или "отсутствующие" объекты, используемые механизмом поддержки зависимостей Oracle. Процесс SMON удаляет эти ненужные строки.
Сейчас можно сказать, что имя для процесса SNPn выбрано неудачно. В версии 7.0 сервера Oracle впервые появилась поддержка репликации. Это делалось с помощью объекта базы данных, известного как моментальный снимок
(snapshot). Внутренним механизмом для обновления или приведения к текущему состоянию моментальных снимков был SNPn — процесс обработки снимков (snapshot process). Этот процесс контролировал таблицу заданий, по которой определял, когда необходимо обновлять моментальные снимки в системе. В Oracle 7.1 корпорация Oracle открыла это средство для общего доступа через пакет DBMS_JOB. То, что было связано с моментальными снимками в версии 7.0, стало "очередью заданий" в версии 7.1 и последующих. Со временем имена параметров для управления очередью (как часто ее надо проверять и сколько процессов может быть в очереди) изменились со SNAPSHOT_REFRESH_INTERVAL и SNAPSHOT_REFRESH_PROCESSES на JOB_QUEUE_INTERVAL и JOB_QUEUE_PROCESSES. А вот имя процесса операционной системы не изменилось.
Можно запускать до 36 процессов очереди заданий. Они именуются SNP0, SNP1, ..., SNP9, SNPA, ..., SNPZ. Эти процессы очередей заданий интенсивно используются при репликации в ходе обновления моментального снимка или материализованного представления. Разработчики также часто используют их для запуска отдельных (фоновых) или периодически выполняющихся заданий. Например, далее в книге будет показано, как использовать очереди заданий для существенного ускорения обработки: за счет дополнительной работы можно сделать намного приятнее среду для пользователя (аналогично тому, как сделано в самом сервере Oracle при использовании процессов LGWR и DBWn).
Процессы SNPn сочетают в себе особенности как разделяемого, так и выделенного сервера: обрабатывают несколько заданий, но памятью управляют как выделенный сервер (область UGA находится в области PGA процесса). Процесс очереди заданий выполняет в каждый момент времени только одно задание. Вот почему необходимо несколько процессов, если требуется выполнять несколько заданий одновременно. На уровне заданий не поддерживаются потоки или вытеснение. Запущенное задание выполняется, пока не будет выполнено (или не произойдет сбой). В приложении А мы более детально рассмотрим пакет DBMS_JOB и нетрадиционное использование очереди заданий.
В системе с тысячами пользователей ОС может быстро оказаться перегруженной при попытке управлять тысячами процессов. В обычной системе одновременно активна лишь небольшая часть этих тысяч пользователей. Например, я недавно работал над системой с 5000 одновременно работающих пользователей. В каждый момент времени в среднем активны были не более 50. Эта система могла бы работать с 50 разделяемыми серверными процессами, на два порядка (в 100 раз) сокращая количество процессов в операционной системе. При этом существенно сокращается количество переключений контекстов на уровне операционной системы.
Это одна из наиболее часто упоминаемых причин использования режима MTS: сокращается объем памяти, необходимой для поддержки определенного количества пользователей. Да, сокращается, но не настолько, как можно было бы ожидать. Помните, что при использовании режима MTS область UGA помещается в SGA. Это означает, что при переходе на режим MTS необходимо точно оценить суммарный объем областей UGA и выделить место в области SGA с помощью параметра инициализации LARGE_POOL. Поэтому размер области SGA при использовании режима MTS обычно очень большой. Эта память выделяется заранее и поэтому может использоваться только СУБД. Сравните это с режимом разделяемого сервера, когда процессы могут использовать любую область памяти, не выделенную под SGA. Итак, если область SGA становится намного больше вследствие размещения в ней областей UGA, каким же образом экономится память? Экономия связана с уменьшением количества выделяемых областей PGA. Каждый выделенный/разделяемый сервер имеет область PGA. В ней хранится информация процесса. В ней располагаются области сортировки, области хешей и другие структуры процесса. Именно этой памяти для системы надо меньше, если используется режим MTS. При переходе с 5000 выделенных серверов на 100 разделяемых освобождается 4900 областей PGA — именно такой объем памяти и экономится в режиме MTS.
Конечно, используют в этих целях режим MTS только при отсутствии выбора. Если необходимо взаимодействовать с компонентами EJB в базе данных, придется использовать режим MTS. Есть и другие расширенные возможности подключения, требующие использования режима MTS. Если необходимо централизовать связи нескольких баз данных, например, также придется использовать режим MTS.
Теперь пришло время рассмотреть основные структуры памяти сервера Oracle. Их три.
SGA, System Global Area — глобальная область системы. Это большой совместно используемый сегмент памяти, к которому обращаются все процессы Oracle.
PGA, Process Global Area — глобальная область процесса. Это приватная область памяти процесса или потока, недоступная другим процессам/потокам.
UGA, User Global Area — глобальная область пользователя. Это область памяти, связанная с сеансом. Глобальная область памяти может находиться в SGA либо в PGA. Если сервер работает в режиме MTS, она располагается в области SGA, если в режиме выделенного сервера, — в области PGA.
Рассмотрим кратко области PGA и UGA, затем перейдем к действительно большой структуре — области SGA.
Управляющий файл — это сравнительно небольшой файл (в редких случаях он может увеличиваться до 64 Мбайт), содержащий информацию обо всех файлах, необходимых серверу Oracle. Из файла параметров инициализации (init.ora) экземпляр может узнать, где находятся управляющие файлы, а в управляющем файле описано местонахождение файлов данных и файлов журнала повторного выполнения. В управляющих файлах хранится и другие необходимые серверу Oracle сведения, в частности время обработки контрольной точки, имя базы данных (которое должно совпадать со значением параметра инициализации db_name), дата и время создания базы данных, хронология архивирования журналов повторного выполнения (именно она приводит к увеличению размера управляющего файла в некоторых случаях) и т.д.
Управляющие файлы надо мультиплексировать либо аппаратно (располагать на RAID-массиве), либо с помощью средств сервера Oracle, когда RAID-массив или зеркалирование использовать нельзя. Необходимо поддерживать несколько копий этих файлов, желательно на разных дисках, чтобы предотвратить потерю управляющих файлов в случае сбоя диска. Потеря управляющих файлов — не фатальное событие, она только существенно усложнит восстановление.
С управляющими файлами разработчику скорее всего сталкиваться никогда не придется. Для администратора базы данных это — важная часть базы данных, но для разработчика эти файлы не особенно нужны.
Временные файлы в Oracle — это специальный тип файлов данных. Сервер Oracle использует временные файлы для хранения промежуточных результатов сортировки большого объема данных или результирующих множеств, если для них не хватает оперативной памяти. Постоянные объекты данных, такие как таблицы или индексы, во временных файлах никогда не хранятся, в отличие от содержимого временных таблиц и построенных по ним индексов. Так что создать таблицы приложения во временном файле данных нельзя, а вот хранить в нем данные можно, если использовать временную таблицу.
Сервер Oracle обрабатывает временные файлы специальным образом. Обычно все изменения объектов записываются в журналы повторного выполнения. Эти журналы транзакций в дальнейшем можно использовать для повторного выполнения транзакций. Это делается, например, при восстановлении после сбоя. Временные файлы в этом процессе не участвуют. Для них не генерируются данные повторного выполнения, хотя и генерируются данные отмены (UNDO) при работе с глобальными временными таблицами, чтобы можно было откатить изменения, сделанные в ходе сеанса. Создавать резервные копии временных файлов данных нет необходимости, а если кто-то это делает, то напрасно теряет время, поскольку данные во временном файле восстановить все равно нельзя.
Рекомендуется конфигурировать базу данных так, чтобы временные табличные пространства управлялись локально. Убедитесь, что ваш администратор базы данных использует команду CREATE TEMPORARY TABLESPACE. Никому не нужно еще одно обычное табличное пространство, используемое под временные данные, поскольку не удастся получить преимущества временных файлов данных. Убедитесь также, что в качестве временного используется локально управляемое табличное пространство с экстентами одинакового размера, соответствующего значению параметра инициализации sort_area_size. Создаются такие временные табличные пространства примерно так:
tkyte@TKYTE816> create temporary tablespace temp 2 tempfile 'c:\oracle\oradata\tkyte816\temp.dbf' 3 size 5m 4 extent management local 5 uniform size 64k;
Tablespace created.
Поскольку мы опять вторгаемся в сферу деятельности администратора базы данных, переходим к следующей теме.
Прежде чем перейти к остальным процессам, давайте обсудим, почему поддерживается два режима подключения и когда лучше использовать каждый из них. Режим выделенного сервера — наиболее широко используемый способ подключения к СУБД Oracle для всех приложений, использующих SQL-запросы. Режим выделенного сервера проще настроить и он обеспечивает самый простой способ подключения. При этом требуется минимальное конфигурирование. Настройка и конфигурирование режима MTS, хотя и несложный, но дополнительный шаг. Основное различие между этими режимами, однако, не в настройке. Оно связано с особенностями работы. При использовании выделенного сервера имеется соответствие один к одному между клиентским сеансом и серверным процессом. В режиме MTS соответствие — многие к одному (много клиентов и один разделяемый сервер). Как следует из названия, разделяемый сервер — общий ресурс, а выделенный — нет. При использовании общего ресурса необходимо стараться не монополизировать его надолго. Как было показано в главе 1, в примере с компонентами EJB, запускавшими продолжительную хранимую процедуру, монополизация этого ресурса может приводить как бы к зависанию системы. На представленной выше схеме имеется два разделяемых сервера. При наличии трех клиентов, более-менее одновременно пытающихся запустить 45-секундный процесс, два из них получат результат через 45 секунд, а третий — через 90 секунд. Правило номер один для режима MTS: убедитесь, что транзакции выполняются быстро. Они могут выполняться часто, но должны быть короткими (что обычно и бывает в системах OLTP). В противном случае будут наблюдаться все признаки замедления работы системы из-за монополизации общих ресурсов несколькими процессами. В экстремальных случаях, если все разделяемые серверы заняты, система "зависает".
Поэтому режим MTS очень хорошо подходит для систем класса OLTP, характеризующихся короткими, но частыми транзакциями. В системе класса OLTP транзакции выполняются за миллисекунды, — ни одно действие не требует для выполнения более чем доли секунды. Режим MTS не подходит, однако, для хранилища данных. В такой системе выполняются запросы продолжительностью одна, две, пять и более минут. Для режима MTS это "смертельно". В системе, где 90 процентов задач относятся к классу OLTP, а 10 процентов — "не совсем OLTP", можно поддерживать одновременно выделенные и разделяемые серверы в одном экземпляре. В этом случае существенно сокращается количество процессов для пользователей OLTP, а "не совсем OLTP"-задачи не монополизируют надолго разделяемые серверы.
Итак, какие же преимущества дает режим MTS, если учитывать, для какого типа транзакций он предназначен? Режим MTS позволяет добиться следующего.