|
|
|||||||||||||||||||||||||||||
|
Oracle для профессионалов. Глава 2. Часть 2Источник: CITFORUM Том Кайт
Буфер журнала повторного выполненияБуфер журнала повторного выполнения используется для временного кеширования данных оперативного журнала повторного выполнения перед записью на диск. Поскольку перенос данных из памяти в память намного быстрее, чем из памяти - на диск, использование буфера журнала повторного выполнения позволяет существенно ускорить работу сервера. Данные не задерживаются в буфере журнала повторного выполнения надолго. Содержимое этого буфера сбрасывается на диск:
Поэтому создание буфера журнала повторного выполнения размером в десятки Мбайт - напрасное расходование памяти. Чтобы использовать буфер журнала повторного выполнения размером 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 Теперь можно использовать эту информацию для получения "счетчика обращений" для этого блока: sys@TKYTE816> select tch from x$bh where file# = 1 and dbablk = 465; TCH ---------- 10 sys@TKYTE816> select * from dual; D - X sys@TKYTE816> select tch from x$bh where file# = 1 and dbablk = 465; TCH ---------- 11 sys@TKYTE816> select * from dual; D - X sys@TKYTE816> select tch from x$bh where file# = 1 and dbablk = 465; TCH ---------- 12 При каждом обращении к блоку увеличивается значение счетчика. Использованный буфер больше не переносится в начало списка. Он остается на месте, а его "счетчик обращений" увеличивается. Блоки со временем перемещаются по списку естественным путем, поскольку измененные блоки переносятся в список "грязных" (для записи на диск процессом DBWn). Кроме того, если несмотря на повторное использование блоков буферный кеш заполнился, и блок с небольшим значением "счетчика обращений" удаляется из списка, он возвращается с новыми данными примерно в середину списка. Полный алгоритм управления списком довольно сложный и меняется с каждой новой версией Oracle. Подробности его работы несущественны для разработчиков, достаточно помнить, что интенсивно используемые блоки кешируются надолго, а редко используемые - долго в кеше не задерживаются. Буферный кеш в версиях до Oracle 8.0 представлял собой один большой кеш. Все блоки кешировались одинаково, никаких средств деления пространства буферного кеша на части не существовало. В Oracle 8.0 добавлена возможность создания буферных пулов. С ее помощью можно зарезервировать в буферном кеше место для сегментов (как вы помните, сегменты соответствуют таблицам, индексам и т.д.). Появилась возможность выделить место (буферный пул) достаточного размера для размещения целиком в памяти, например, таблиц-"справочников". При чтении сервером Oracle блоков из этих таблиц они кешируются в этом специальном пуле. Они будут конфликтовать за место в пуле только с другими помещаемыми в него сегментами. Остальные сегменты в системе будут "сражаться" за место в стандартном буферном пуле. При этом повышается вероятность их кеширования: они не выбрасываются из кеша как устаревшие при считывании других, не связанных с ними блоков. Буферный пул, обеспечивающий подобное кеширование, называется пулом KEEP. Блоками в пуле KEEP сервер управляет так же, как в обычном буферном кеше. Если блок используется часто, он остается в кеше; если к блоку некоторое время не обращались и в буферном пуле не осталось места, этот блок выбрасывается из пула как устаревший. Можно выделить еще один буферный пул. Он называется пулом RECYCLE. В нем блоки выбрасываются иначе, чем в пуле KEEP. Пул KEEP предназначен для продолжительного кеширования "горячих" блоков. Из пула RECYCLE блок выбрасывается сразу после использования. Это эффективно в случае "больших" таблиц, которые читаются случайным образом. (Понятие "большая таблица" очень относительно; нет эталона для определения того, что считать "большим".) Если в течение разумного времени вероятность повторного считывания блока мала, нет смысла долго держать такой блок в кеше. Поэтому в пуле RECYCLE блоки регулярно перечитываются. ... Разделяемый пулРазделяемый пул - один из наиболее важных фрагментов памяти в области SGA, особенно для обеспечения производительности и масштабируемости. Слишком маленький разделяемый пул может снизить производительность настолько, что система будет казаться зависшей. Слишком большой разделяемый пул может привести к такому же результату. Неправильное использование разделяемого пула грозит катастрофой. Итак, что же такое разделяемый пул? В разделяемом пуле сервер Oracle кеширует различные "программные" данные. Здесь кешируются результаты разбора запроса. Перед повторным разбором запроса сервер Oracle просматривает разделяемый пул в поисках готового результата. Выполняемый сеансом PL/SQL-код тоже кешируется здесь, так что при следующем выполнении не придется снова читать его с диска. PL/SQL-код в разделяемом пуле не просто кешируется, - появляется возможность его совместного использования сеансами. Если 1000 сеансов выполняют тот же код, загружается и совместно используется всеми сеансами лишь одна копия этого кода. Сервер Oracle хранит в разделяемом пуле параметры системы. Здесь же хранится кеш словаря данных, содержащий информацию об объектах базы данных. Короче, в разделяемом пуле хранится все, кроме продуктов питания. Разделяемый пул состоит из множества маленьких (около 4 Кбайт) фрагментов памяти. Память в разделяемом пуле управляется по принципу давности использования (LRU). В этом отношении она похожа на буферный кеш: если фрагмент не используется, он теряется. Стандартный пакет DBMS_SHARED_POOL позволяет изменить это и принудительно закрепить объекты в разделяемом пуле. Это позволяет загрузить часто используемые процедуры и пакеты при запуске сервера и сделать так, чтобы они не выбрасывались из пула как устаревшие. Обычно, если в течение определенного периода времени фрагмент памяти в разделяемом пуле не использовался, он выбрасывается как устаревший. Даже PL/SQL-код, который может иметь весьма большой размер, управляется механизмом постраничного устаревания, так что при выполнении кода очень большого пакета необходимый код загружается в разделяемый пул небольшими фрагментами. Если в течение продолжительного времени он не используется, то в случае переполнения выбрасывается из разделяемого пула, а пространство выделяется для других объектов. Самый простой способ поломать механизм разделяемого пула Oracle - не использовать связываемые переменные. Как было показано в главе 1, отказавшись от использования связываемых переменных, можно "поставить на колени" любую систему, поскольку:
Если каждый переданный серверу Oracle запрос специфичен, с жестко заданными константами, это вступает в противоречие с назначением разделяемого пула. Разделяемый пул создавался для того, чтобы хранящиеся в нем планы выполнения запросов использовались многократно. Если каждый запрос - абсолютно новый и никогда ранее не встречался, в результате кеширования только расходуются дополнительные ресурсы. Разделяемый пул начинает снижать производительность. Обычно эту проблему пытаются решить, увеличивая разделяемый пул, но в результате становится еще хуже. Разделяемый пул снова неизбежно заполняется, и его поддержка требует больших ресурсов, чем поддержка маленького разделяемого пула, поскольку при управлении большим заполненным пулом приходится выполнять больше действий, чем при управлении маленьким заполненным пулом. Единственным решением этой проблемы является применение разделяемых операторов SQL, которые используются повторно. В главе 10 мы опишем параметр инициализации CURSOR_SHARING, который можно использовать для частичного решения подобных проблем, но наиболее эффективное решение - применять повторно используемые SQL-операторы. Даже самые большие из крупных систем требуют от 10000 до 20000 уникальных SQL-операторов. В большинстве систем используется лишь несколько сотен уникальных запросов. Следующий практический пример показывает, насколько все осложняется при неправильном использовании разделяемого пула. Меня пригласили поработать над системой, стандартной процедурой обслуживания которой была остановка экземпляра каждую ночь для очистки области SGA и последующий перезапуск. Это приходилось делать, поскольку в течение дня в системе возникали проблемы, связанные с избыточной загрузкой процессора, и, если сервер работал больше одного дня, производительность начинала падать. Единственная причина этого была в том, что за период с 9 утра до 5 вечера они полностью заполняли разделяемый пул размером 1 Гбайт в области SGA общим размером 1,1 Гбайт. Да, именно так: 0,1 Гбайта было выделено под буферный кеш и другие компоненты, а 1 Гбайт - для кеширования запросов, которые никогда не выполнялись повторно. Систему приходилось перезапускать, потому что свободная память в разделяемом пуле исчерпывалась в течение одного дня. На поиск и удаление устаревших структур (особенно из такого большого разделяемого пула) расходовалось столько ресурсов, что производительность резко падала (хотя она и до этого была далека от оптимальной, ведь приходилось управлять разделяемым пулом в 1 Гбайт). Кроме того, пользователи этой системы постоянно требовали добавления новых процессоров, поскольку полный разбор SQL-операторов требовал больших вычислительных ресурсов. Когда, после внесения исправлений, в приложении стали использоваться связываемые переменные, удалось не только снизить требования к ресурсам машины (у них и так вычислительные мощности намного превышали необходимые), но и появилась возможность пересмотреть распределение памяти. Вместо разделяемого пула размером в 1 Гбайт оказалось достаточно выделить 100 Мбайт, причем за много недель непрерывной работы он не заполнился. И последнее, что хотелось бы сказать о разделяемом пуле и параметре инициализации SHARED_POOL_SIZE. Нет никакой связи между результатами выполнения запроса: sys@TKYTE816> select sum(bytes) from v$sgastat where pool = 'shared pool'; SUM(BYTES) ---------- 18322028 1 row selected. и значением параметра инициализации SHARED_POOL_SIZE: sys@TKYTE816> show parameter shared_pool_size NAME TYPE VALUE ----------------------------------- ------- -------------------------- shared_pool_size string 15360000 кроме того, что значение SUM(BYTES) FROM V$SGASTAT всегда больше, чем значение параметра SHARED_POOL_SIZE. В разделяемом пуле хранится много других структур, не охватываемых соответствующим параметром инициализации. Значение SHARED_POOL_SIZE обычно является основным, но не единственным фактором, определяющим размер разделяемого пула SUM(BYTES). Например, параметр инициализации CONTROL_FILES задает управляющие файлы, а для каждого управляющего файла в разделе "прочее" разделяемого пула требуется 264 байта. Жаль, что показатель 'shared pool' в представлении V$SGASTAT и параметр инициализации SHARED_POOL_SIZE получили похожие названия, поскольку параметр инициализации влияет на размер разделяемого пула, но не задает его полностью. Большой пулБольшой пул назван так не потому, что это "большая" структура (хотя его размер вполне может быть большим), а потому, что используется для выделения больших фрагментов памяти - б о льших, чем те, для управления которыми создавался разделяемый пул. До его появления в Oracle 8.0, выделение памяти выполнялось в рамках разделяемого пула. Это было неэффективно при использовании средств, выделяющих "большие" объемы памяти, например, при работе в режиме MTS. Проблема осложнялась еще и тем, что при обработке, требующей больших объемов памяти, эта память используется не так, как предполагает управление памятью в разделяемом пуле. Память в разделяемом пуле управляется на основе давности использования, что отлично подходит для кеширования и повторного использования данных. При выделении же больших объемов памяти фрагмент выделяется, используется и после этого он не нужен, т.е. нет смысла его кешировать. Серверу Oracle требовался аналог буферных пулов RECYCLE и KEEP в буферном кеше. Именно в таком качестве сейчас и выступают большой пул и разделяемый пул. Большой пул - это область памяти, управляемая по принципу пула RECYCLE, а разделяемый пул скорее похож на буферный пул KEEP: если фрагмент в нем используется часто, он кешируется надолго. Память в большом пуле организована по принципу "кучи" и управляется с помощью алгоритмов, аналогичных используемым функциями malloc() и free() в языке C. После освобождения фрагмента памяти он может использоваться другими процессами. В разделяемом пуле отсутствует понятие освобождения фрагмента памяти. Память выделяется, используется, а затем перестает использоваться. Через некоторое время, если эту память необходимо использовать повторно, сервер Oracle позволит изменить содержимое устаревшего фрагмента. Проблема при использовании только разделяемого пула состоит в том, что все потребности в памяти нельзя подогнать под одну мерку. Большой пул, в частности, используется:
Как видите, ни одну из описанных выше областей памяти нельзя помещать в буферный пул с вытеснением небольших фрагментов памяти на основе давности использования. Область UGA, например, не будет использоваться повторно по завершении сеанса, поэтому ее немедленно надо возвращать в пул. Кроме того, область UGA обычно - достаточно большая. Как было показано на примере, где изменялось значение параметра SORT_AREA_RETAINED_SIZE, область UGA может быть очень большой, и, конечно, больше, чем фрагмент в 4 Кбайта. При помещении области UGA в разделяемый пул она фрагментируется на части одинакового размера и, что хуже всего, выделение больших областей памяти, никогда не используемых повторно, приведет к выбрасыванию из пула фрагментов, которые могли бы повторно использоваться. В дальнейшем на перестройку этих фрагментов памяти расходуются ресурсы сервера. То же самое справедливо и для буферов сообщений. После того как сообщение доставлено, в них уже нет необходимости. С буферами, создаваемыми в процессе резервного копирования, все еще сложнее: они большие и сразу после использования сервером Oracle должны "исчезать". Использовать большой пул при работе в режиме MTS не обязательно, но желательно. Если сервер работает в режиме MTS в отсутствие большого пула, вся память выделяется из разделяемого пула, как это и было в версиях Oracle вплоть до 7.3. Из-за этого производительность со временем будет падать, поэтому такой конфигурации надо избегать. Большой пул стандартного размера будет создаваться при установке одного из следующих параметров инициализации: DBWn_IO_SLAVES или PARALLEL_AUTOMATIC_TUNING. Рекомендуется задавать размер большого пула явно. Однако стандартное значение не может использоваться во всех без исключения случаях. Java-пул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. При работе в режиме MTS Java-пул включает:
Оставшаяся часть области UGA выделяется как обычно - из разделяемого пула или из большого пула, если он выделен. Поскольку общий размер Java-пула фиксирован, разработчикам приложений необходимо оценить общий объем памяти для приложения и умножить на предполагаемое количество одновременно поддерживаемых сеансов. Полученное значение будет определять общий размер Java-пула. Каждая Java-часть области UGA будет увеличиваться и уменьшаться при необходимости, но помните, что размер пула должен быть таким, чтобы части всех областей UGA могли поместиться в нем одновременно. В режиме MTS, который обычно используется для приложений, использующих архитектуру CORBA или компоненты EJB (об этом говорилось в главе 1), может потребоваться очень большой Java-пул., Его размер будет зависеть не от количества используемых классов, а от количества одновременно работающих пользователей. Как и большой пул, размеры которого становятся очень большими в режиме MTS, Java-пул тоже может разрастаться до огромных размеров. Итак, в этом разделе была рассмотрена структура памяти сервера Oracle. Мы начали с уровня процессов и сеансов, поговорили об областях PGA (Process Global Area - глобальная область процесса) и UGA (User Global Area - глобальная область пользователя) и разобрались в их взаимосвязи. Было показано, как режим, в котором пользователь подключается к серверу Oracle, определяет организацию памяти. Подключение к выделенному серверу предполагает использование памяти серверным процессом в большем объеме, чем подключение в режиме MTS, но работа в режиме MTS требует создания намного большей области SGA. Затем мы описали компоненты самой области SGA, выделив в ней шесть основных структур. Были описаны различия между разделяемым и большим пулом, и показано, почему большой пул необходим для "сохранения" разделяемого пула. Мы описали Java-пул и его использование в различных условиях. Был рассмотрен буферный кеш и способ деления его на меньшие, более специализированные пулы. Теперь можно переходить к физическим процессам экземпляра Oracle. ПроцессыОсталось рассмотреть последний элемент "головоломки". Мы изучили организацию базы данных и набор образующих ее физических файлов. Разбираясь с использованием памяти сервером Oracle, рассмотрели половину экземпляра. Оставшийся компонент архитектуры - набор процессов, образующий вторую половину экземпляра. Некоторые из этих процессов, например процесс записи блоков в базу данных (DBWn) и процесс записи журнала (LGWR), уже упоминались. Здесь мы более детально рассмотрим функцию каждого процесса: что и почему они делают. В этом разделе "процесс" будет использоваться как синоним "потока" в операционных системах, где сервер Oracle реализован с помощью потоков. Так, например, если описывается процесс DBWn, в среде Windows ему соответствует поток DBWn. В экземпляре Oracle есть три класса процессов.
Мы рассмотрим все эти процессы и постараемся выяснить, какую роль они играют в экземпляре. Серверные процессыМы уже бегло рассматривали эти процессы ранее при обсуждении выделенных и разделяемых серверов. Здесь мы еще раз опишем два вида серверных процессов и более детально рассмотрим их архитектуру. Выделенные и разделяемые серверы решают одну и ту же задачу: обрабатывают передаваемые им SQL-операторы. При получении запроса SELECT * FROM EMP именно выделенный/разделяемый сервер Oracle будет разбирать его и помещать в разделяемый пул (или находить соответствующий запрос в разделяемом пуле). Именно этот процесс создает план выполнения запроса. Этот процесс реализует план запроса, находя необходимые данные в буферном кеше или считывая данные в буферный кеш с диска. Такие серверные процессы можно назвать "рабочими лошадками" СУБД. Часто именно они потребляют основную часть процессорного времени в системе, поскольку выполняют сортировку, суммирование, соединения - в общем, почти все. В режиме выделенного сервера имеется однозначное соответствие между клиентскими сеансами и серверными процессами (или потоками). Если имеется 100 сеансов на UNIX-машине, будет 100 процессов, работающих от их имени. Графически это можно представить так8: ... С клиентским приложением скомпонованы библиотеки Oracle. Они обеспечивают функциональный интерфейс (Application Program Interface - API) для взаимодействия с базой данных. Функции API "знают", как передавать запрос к базе данных и обрабатывать возвращаемый курсор. Они обеспечивают преобразование запросов пользователя в передаваемые по сети пакеты, обрабатываемые выделенным сервером. Эти функции обеспечивает компонент Net8 - сетевое программное обеспечение/протокол, используемое Oracle для клиент-серверной обработки (даже в n-звенной архитектуре есть место для клиент-серверного взаимодействия). Сервер Oracle использует такую архитектуру, даже если протокол Net8 не нужен. То есть, когда клиент и сервер работают на одной и той же машине, используется эта двухпроцессная (известная также как двухзадачная - two-task) архитектура. Эта архитектура обеспечивает два преимущества.
Ранее в этой главе мы рассматривали "порождение", или создание, этих серверных процессов процессом прослушивания Oracle Net8 Listener. Не будем снова возвращаться к этому процессу, но коротко рассмотрим, что происходит, если процесс прослушивания не задействован. Механизм во многом аналогичен, но вместо создания выделенного сервера процессом прослушивания с помощью вызовов fork()/exec() в ОС UNIX или вызова IPC (Inter Process Communication), как это происходит в Windows, процесс создается непосредственно клиентским процессом. Это можно четко увидеть в ОС UNIX: ops$tkyte@ORA8I.WORLD> select a.spid dedicated_server, 2 b.process clientpid 3 from v$process a, v$session b 4 where a.addr = b.paddr 5 and b.audsid = userenv('sessionid') 6 / DEDICATED CLIENTPID --------- --------- 7055 7054 ops$tkyte@ORA8I.WORLD> !/bin/ps -lp 7055 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 8 S 30174 7055 7054 0 41 20 61ac4230 36815 639b1998 ? 0:00 oracle ops$tkyte@ORA8I.WORLD> !/bin/ps -lp 7054 F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 8 S 12997 7054 6783 0 51 20 63eece30 1087 63eecea0 pts/7 0:00 sqlplus Я использовал запрос для определения идентификатора процесса (PID) моего выделенного сервера (столбец SPID в представлении V$PROCESS - это идентификатор процесса операционной системы, использовавшегося для выполнения запроса). Кроме того, в столбце PROCESS представления V$SESSION находится идентификатор клиентского процесса, подключившегося к базе данных. С помощью команды ps можно явно показать, что PPID (Parent Process ID - идентификатор родительского процесса) моего выделенного сервера соответствует процессу SQL*Plus. В данном случае именно утилита SQL*Plus создала выделенный сервер с помощью системных вызовов fork() и exec(). Теперь давайте более детально рассмотрим другой тип серверных процессов - разделяемый серверный процесс. Для подключения к серверному процессу этого типа обязательно используется протокол Net8, даже если клиент и сервер работают на одной машине, - нельзя использовать режим MTS без процесса прослушивания Net8. Как уже описывалось ранее в этом разделе, клиентское приложение подключается к процессу прослушивания Net8 и перенаправляется на процесс-диспетчер. Диспетчер играет роль канала передачи информации между клиентским приложением и разделяемым серверным процессом. Ниже представлена схема подключения к базе данных через разделяемый сервер9: ... Как видите, клиентские приложения со скомпонованными в них библиотеками Oracle физически подключаются к диспетчеру MTS. Диспетчеров MTS для любого экземпляра можно сгенерировать несколько, но часто для сотен и даже тысяч пользователей используется один диспетчер. Диспетчер отвечает за получение входящих запросов от клиентских приложений и их размещение в очереди запросов в области SGA. Первый свободный разделяемый серверный процесс, по сути, ничем не отличающийся от выделенного серверного процесса, выберет запрос из очереди и подключится к области UGA соответствующего сеанса. Разделяемый сервер обработает запрос и поместит полученный при его выполнении результат в очередь ответов. Диспетчер постоянно следит за появлением результатов в очереди и передает их клиентскому приложению. С точки зрения клиента нет никакой разницы между подключением к выделенному серверу и подключением в режиме MTS, - они работают одинаково. Различие возникает только на уровне экземпляра. Выделенный и разделяемый серверПрежде чем перейти к остальным процессам, давайте обсудим, почему поддерживается два режима подключения и когда лучше использовать каждый из них. Режим выделенного сервера - наиболее широко используемый способ подключения к СУБД Oracle для всех приложений, использующих SQL-запросы. Режим выделенного сервера проще настроить и он обеспечивает самый простой способ подключения. При этом требуется минимальное конфигурирование. Настройка и конфигурирование режима MTS, хотя и несложный, но дополнительный шаг. Основное различие между этими режимами, однако, не в настройке. Оно связано с особенностями работы. При использовании выделенного сервера имеется соответствие один к одному между клиентским сеансом и серверным процессом. В режиме MTS соответствие - многие к одному (много клиентов и один разделяемый сервер). Как следует из названия, разделяемый сервер - общий ресурс, а выделенный - нет. При использовании общего ресурса необходимо стараться не монополизировать его надолго. Как было показано в главе 1, в примере с компонентами EJB, запускавшими продолжительную хранимую процедуру, монополизация этого ресурса может приводить как бы к зависанию системы. На представленной выше схеме имеется два разделяемых сервера. При наличии трех клиентов, более-менее одновременно пытающихся запустить 45-секундный процесс, два из них получат результат через 45 секунд, а третий - через 90 секунд. Правило номер один для режима MTS: убедитесь, что транзакции выполняются быстро. Они могут выполняться часто, но должны быть короткими (что обычно и бывает в системах OLTP). В противном случае будут наблюдаться все признаки замедления работы системы из-за монополизации общих ресурсов несколькими процессами. В экстремальных случаях, если все разделяемые серверы заняты, система "зависает". Поэтому режим MTS очень хорошо подходит для систем класса OLTP, характеризующихся короткими, но частыми транзакциями. В системе класса OLTP транзакции выполняются за миллисекунды, - ни одно действие не требует для выполнения более чем доли секунды. Режим MTS не подходит, однако, для хранилища данных. В такой системе выполняются запросы продолжительностью одна, две, пять и более минут. Для режима MTS это "смертельно". В системе, где 90 процентов задач относятся к классу OLTP, а 10 процентов - "не совсем OLTP", можно поддерживать одновременно выделенные и разделяемые серверы в одном экземпляре. В этом случае существенно сокращается количество процессов для пользователей OLTP, а "не совсем OLTP"-задачи не монополизируют надолго разделяемые серверы. Итак, какие же преимущества дает режим MTS, если учитывать, для какого типа транзакций он предназначен? Режим MTS позволяет добиться следующего. Сократить количество процессов/потоков операционной системыВ системе с тысячами пользователей ОС может быстро оказаться перегруженной при попытке управлять тысячами процессов. В обычной системе одновременно активна лишь небольшая часть этих тысяч пользователей. Например, я недавно работал над системой с 5000 одновременно работающих пользователей. В каждый момент времени в среднем активны были не более 50. Эта система могла бы работать с 50 разделяемыми серверными процессами, на два порядка (в 100 раз) сокращая количество процессов в операционной системе. При этом существенно сокращается количество переключений контекстов на уровне операционной системы. Искусственно ограничить степень параллелизмаКак человеку, участвовавшему во многих тестированиях производительности, преимущества ограничения степени параллелизма мне очевидны. При тестировании клиенты просят запустить как можно больше пользователей, пока система не перестанет работать. Одним из результатов такого рода тестирования является диаграмма, показывающая зависимость количества транзакций от количества одновременно работающих пользователей: Транзакции в секунду ^ / Максимальный параллелизм / / / __ / - - / / / / / / / / / / / / / // +---------------------------------> Одновременно работающие пользователи Сначала при добавлении одновременно работающих пользователей количество транзакций растет. С какого-то момента, однако, добавление новых пользователей не увеличивает количества выполняемых в секунду транзакций: оно стабилизируется. Пропускная способность достигла максимума, и время ожидания ответа начинает расти (каждую секунду выполняется то же количество транзакций, но пользователи получают результаты со все возрастающей задержкой. При дальнейшем добавлении пользователей пропускная способность начинает падать. Количество одновременно работающих пользователей перед началом этого падения и является максимально допустимой степенью параллелизма в системе. Дальше система переполняется запросами, и образуются очереди. С этого момента система не справляется с нагрузкой. Не только существенно увеличивается время ответа, но и начинает падать пропускная способность системы. Если ограничить количество одновременно работающих пользователей до числа, непосредственно предшествующего падению, можно обеспечить максимальную пропускную способность и приемлемое время ответа для большинства пользователей. Режим MTS позволяет ограничить максимальную степень параллелизма в системе до этого количества одновременно работающих пользователей. Сократить объем памяти, необходимый системеЭто одна из наиболее часто упоминаемых причин использования режима 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. РекомендацияЕсли система не перегружена и нет необходимости использовать режим MTS для обеспечения необходимой функциональности, лучше использовать выделенный сервер. Выделенный сервер проще устанавливать, и упрощается настройка производительности. Есть ряд операций, которые можно выполнять только при подключении в режиме выделенного сервера, так что в любом экземпляре надо поддерживать либо оба режима, либо только режим выделенного сервера. С другой стороны, если необходимо поддерживать большое количество пользователей и известно, что эксплуатировать систему придется в режиме MTS, я рекомендую разрабатывать и тестировать ее тоже в режиме MTS. Если система разрабатывалась в режиме разделяемого сервера и никогда не тестировалась в режиме MTS, вероятность неудачи повышается. Испытывайте систему в рабочих условиях; тестируйте ее производительность; проверьте, хорошо ли она работает в режиме MTS. То есть, проверьте, не монополизирует ли она надолго разделяемые серверы. Обнаруженные на стадии разработки недостатки устранить гораздо проще, чем при внедрении. Для сокращения времени работы процесса можно использовать средства расширенной обработки очередей (Advanced Queues - AQ), но это надо учесть в проекте приложения. Такие вещи лучше делать на этапе разработки. Если в приложении уже используется пул подключений (например, пул подключений компонентов J2EE) и размер этого пула определен верно, использование режима MTS только снизит производительность. Размер пула подключений уже рассчитан с учетом максимального количества одновременных подключений, поэтому необходимо, чтобы каждое из этих подключений выполнялось непосредственно к выделенному серверу. Иначе один пул подключений будет просто подключаться к другому пулу подключений. Фоновые процессыЭкземпляр 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 Они соответствуют процессам, представленным на схеме, за исключением процесса SNPn (о нем будет рассказано позже, т.к. он не является фоновым процессом, выполняющим "конкретной" задачу). Обратите внимание на соглашение по именованию этих процессов. Имя процесса начинается с префикса ora_. Затем следуют четыре символа, представляющие фактическое имя процесса, а затем суффикс - _ora8i. Дело в том, что у меня параметр инициализации ORACLE_SID (идентификатор сайта) имеет значение ora8i. В ОС UNIX это существенно упрощает идентификацию фоновых процессов Oracle и их привязку к определенному экземпляру (в Windows простого способа для этого нет, поскольку фоновые процессы реализованы как потоки одного большого процесса). Но что самое интересное, хотя это и не очевидно по представленным результатам, - все эти процессы реализуются одним и тем же двоичным файлом. Вы не найдете на диске двоичный выполняемый файл arc0, точно так же, как не найдете файлов LGWR и DBW0. Все эти процессы реализуются файлом oracle (именно этот выполняемый двоичный файл запускается). Просто при запуске процессы получают такие псевдонимы, чтобы проще было идентифицировать их назначение. Это позволяет совместно использовать большую часть объектного кода на платформе UNIX. В среде Windows это вообще не имеет значения, поскольку процессы Oracle - всего лишь потоки в одном физическом процессе, поэтому все они - один большой двоичный файл. Давайте теперь рассмотрим функции каждого процесса. PMON - монитор процессовЭтот процесс отвечает за очистку после нештатного прекращения подключений. Например, если выделенный сервер "падает" или, получив сигнал, прекращает работу, именно процесс PMON освобождает ресурсы. Процесс PMON откатит незафиксированные изменения, снимет блокировки и освободит ресурсы в области SGA, выделенные прекратившему работу процессу. Помимо очистки после прерванных подключений, процесс PMON контролирует другие фоновые процессы сервера Oracle и перезапускает их при необходимости (если это возможно). Если разделяемый сервер или диспетчер сбоит (прекращает работу), процесс PMON запускает новый процесс (после очистки структур сбойного процесса). Процесс PMON следит за всеми процессами Oracle и либо перезапускает их, либо прекращает работу экземпляра, в зависимости от ситуации. Например, в случае сбоя процесса записи журнала повторного выполнения (LGWR) экземпляр надо перезапускать. Это серьезная ошибка и самое безопасное - немедленно прекратить работу экземпляра, предоставив исправление данных штатному процессу восстановления. Это происходит очень редко, и о случившемся надо немедленно сообщить службе поддержки Oracle. Еще одна функция процесса PMON в экземпляре (версия Oracle 8i) - регистрировать экземпляр в процессе прослушивания протокола Net8. При запуске экземпляра процесс PMON опрашивает известный порт (если явно не указан другой), чтобы убедиться, запущен и работает ли процесс прослушивания. Известный/стандартный порт, используемый сервером Oracle, - порт 1521. А что произойдет, если процесс прослушивания запущен на другом порту? В этом случае используется тот же механизм, но адрес процесса прослушивания необходимо указать явно с помощью параметра инициализации LOCAL_LISTENER. Если процесс прослушивания запущен, процесс PMON связывается с ним и передает соответствующие параметры, например имя службы. SMON - монитор системыSMON - это процесс, занимающийся всем тем, от чего "отказываются" остальные процессы. Это своего рода "сборщик мусора" для базы данных. Вот некоторые из решаемых им задач.
Этот список дает представление о том, что делает процесс SMON. Как видно из представленной выше информации о процессах, полученной с помощью команды ps, процесс SMON может со временем потребовать существенных вычислительных ресурсов (команда ps выполнялась на машине, где экземпляр проработал около месяца). Процесс SMON периодически "пробуждается" (или его "будят" другие фоновые процессы) для выполнения задач сопровождения. RECO - восстановление распределенной базы данныхПроцесс 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. CKPT - обработка контрольной точкиПроцесс обработки контрольной точки вовсе не обрабатывает ее, как можно предположить по названию, - это делает процесс DBWn. Процесс CKPT просто содействует обработке контрольной точки, обновляя заголовки файлов данных. Раньше процесс CKPT был необязательным, но, начиная с версии 8.0, он запускается всегда, так что он представлен в результатах выполнения команды ps в ОС UNIX. Ранее заголовки файлов данных обновлялись в соответствии с информацией о контрольной точке процессом записи журнала LGWR (Log Writer). Однако с ростом размеров баз данных и увеличением количества файлов это стало невыполнимой задачей для процесса LGWR. Если процессу LGWR надо обновлять десятки, сотни, а то и тысячи файлов, увеличивается вероятность того, что ожидающие фиксации транзакций сеансы будут ждать слишком долго. Процесс CKPT снимает эту задачу с процесса LGWR. DBWn - запись блоков базы данныхПроцесс записи блоков базы данных (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 собирает пакет блоков для записи и передает его операционной системе. Процесс DBWn не ждет, пока ОС запишет блоки, - он собирает следующий пакет для записи. Завершив асинхронную запись, ОС уведомляет об этом процесс DBWn. Это позволяет процессу DBWn работать намного быстрее, чем при последовательном выполнении действий. В разделе "Подчиненные процессы" будет показано, как с помощью подчиненных процессов ввода-вывода можно эмулировать асинхронный ввод-вывод на платформах, где он не поддерживается. И последнее замечание о процессе DBWn. Он, по определению, записывает блоки, разбросанные по всему диску, - процесс DBWn выполняет множество записей вразброс. В случае изменений будут изменяться разбросанные блоки индекса и блоки данных, достаточно случайно распределенные по диску. Процесс LGWR, напротив, выполняет в основном запись последовательных блоков в журнал повторного выполнения. Это - важное отличие и одна из причин, почему сервер Oracle имеет журнал повторного выполнения и отдельный процесс LGWR. Записи вразброс выполняются намного медленнее, чем последовательные записи. Имея грязные блоки в буферном кеше в SGA и процесс LGWR, записывающий большое количество последовательных блоков информации для восстановления измененных буферов, можно повысить производительность. Сочетание работы двух процессов - процесс DBWn медленно работает в фоновом режиме, тогда как процесс LGWR быстро выполняет работу для ожидающего пользователя - позволяет повысить общую производительность. Это верно даже несмотря на то, что сервер Oracle может выполнять больший объем ввода-вывода, чем надо (записывает в журнал и в файл данных), - записи в оперативный журнал повторного выполнения можно пропустить, если в ходе обработки контрольной точки сервер Oracle уже записал измененные блоки на диск. LGWR - запись журналаПроцесс LGWR отвечает за сброс на диск содержимого буфера журнала повторного выполнения, находящегося в области SGA. Он делает это:
Поэтому создание слишком большого буфера журнала повторного выполнения не имеет смысла: сервер Oracle никогда не сможет использовать его целиком. Все журналы записываются последовательно, а не вразброс, как вынужден выполнять ввод-вывод процесс DBWn. Запись большими пакетами, как в этом случае, намного эффективнее, чем запись множества отдельных блоков в разные части файла. Это одна из главных причин выделения процесса LGWR и журнала повторного выполнения. Эффективность последовательной записи измененных байтов перевешивает расход ресурсов на дополнительный ввод-вывод. Сервер Oracle мог бы записывать блоки данных непосредственно на диск при фиксации, но это потребовало бы записи множества разбросанных блоков, а это существенно медленнее, чем последовательная запись изменений процессом LGWR. ARCn - архивированиеЗадача процесса ARCn - копировать в другое место оперативный файл журнала повторного выполнения, когда он заполняется процессом LGWR. Эти архивные файлы журнала повторного выполнения затем можно использовать для восстановления носителя. Тогда как оперативный журнал повторного выполнения используется для "исправления" файлов данных в случае сбоя питания (когда прекращается работа экземпляра), архивные журналы повторного выполнения используются для восстановления файлов данных в случае сбоя диска. Если будет потерян диск, содержащий файл данных /d01/oradata/ora8i/system.dbf, можно взять резервные копии за прошлую неделю, восстановить из них старую копию файла и попросить сервер применить оперативный журнал повторного выполнения и все архивные журналы, сгенерированные с момента создания этой резервной копии. Это "подтянет" файл по времени к остальным файлам в базе данных, и можно будет продолжить работу без потери данных. Процесс ARCn обычно копирует оперативный журнал повторного выполнения в несколько мест (избыточность - гарантия сохранности данных!). Это могут быть диски на локальной машине или, что лучше, на другой машине, на случай катастрофического сбоя. Во многих случаях архивные файлы журнала повторного выполнения копируются затем другим процессом на третье устройство хранения, например на ленту. Они также могут отправляться на другую машину для применения к резервной базе данных (это одно из средств защиты от сбоев, предлагаемое Oracle). BSP - сервер блоковЭтот процесс используется исключительно в среде Oracle Parallel Server (OPS). OPS - конфигурация Oracle, при которой несколько экземпляров монтируют и открывают одну и ту же базу данных. Каждый экземпляр Oracle в этом случае работает на своей машине в кластере, и все они имеют доступ для чтения и записи к одному и тому же набору файлов базы данных. При этом буферные кеши в SGA экземпляров должны поддерживаться в согласованном состоянии. Для этого и предназначен процесс BSP. В ранних версиях OPS согласование достигалось с помощью выгрузки блока из кеша ('ping'). Если машине в кластере требовалось согласованное по чтению представление блока данных, заблокированного в исключительном режиме другой машиной, выполнялся обмен данными с помощью сброса на диск. В результате получалась очень дорогостоящая операция чтения данных. Сейчас, при наличии процесса BSP, обмен происходит из кеша в кеш через высокоскоростное соединение машин в кластере. LMON - контроль блокировокЭтот процесс используется исключительно в среде OPS. Процесс LMON контролирует все экземпляры кластера для выявления сбоя экземпляра. Затем он вместе с диспетчером распределенных блокировок (Distributed Lock Manager - DLM), используемым аппаратным обеспечением кластера, восстанавливает глобальные блокировки, которые удерживаются сбойным экземпляром. LMD - демон диспетчера блокировокЭтот процесс используется исключительно в среде OPS. Процесс LMD управляет глобальными блокировками и глобальными ресурсами для буферного кеша в кластерной среде. Другие экземпляры посылают локальному процессу LMD запросы с требованием снять блокировку или определить, кто ее установил. Процесс LMD также выявляет и снимает глобальные взаимные блокировки. LCKn - блокированиеПроцесс LCKn используется исключительно в среде OPS. Он подобен по функциям описанному выше процессу LMD, но обрабатывает запросы ко всем остальным глобальным ресурсам, кроме буферного кеша. Служебные фоновые процессыЭти фоновые процессы необязательны - они запускаются в случае необходимости. Они реализуют средства, необязательные для штатного функционирования базы данных. Использование этих средств инициируется явно или косвенно, при использовании возможности, требующей их запуска. Служебных фоновых процессов - два. Один из них запускает посланные на выполнение задания. В СУБД Oracle встроена очередь пакетных заданий, позволяющая выполнять по расписанию однократные или периодические задания. Другой процесс поддерживает и обрабатывает таблицы очереди, используемые средствами расширенной поддержки очередей (Advanced Queuing - AQ). Средства AQ обеспечивают встроенные возможности обмена сообщениями между сеансами базы данных. Эти процессы можно увидеть в среде ОС UNIX, как и любой другой фоновый процесс, с помощью команды ps. В представленных ранее результатах выполнения команды ps можно видеть, что у меня в экземпляре работает один процесс очереди заданий (ora_snp0_ora8I) и ни одного процесса очереди. SNPn - обработка снимков (очереди заданий)Сейчас можно сказать, что имя для процесса 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 и нетрадиционное использование очереди заданий. QMNn - контроль очередейПроцесс QMNn по отношению к таблицам AQ выполняет ту же роль, что и процесс SNPn по отношению к таблице заданий. Этот процесс контролирует очереди и уведомляет ожидающие сообщений процессы о том, что доступно сообщение. Он также отвечает за распространение очередей - возможность переместить сообщение, поставленное в очередь в одной базе данных, в другую базу данных для извлечения из очереди. Монитор очередей - это необязательный фоновый процесс. Параметр инициализации AQ_TM_PROCESS позволяет создать до десяти таких процессов с именами QMN0, ..., QMN9. По умолчанию процессы QMNn не запускаются. EMNn - монитор событийПроцессы EMNn - часть подсистемы расширенной поддержки очередей. Они используются для уведомления подписчиков очереди о сообщениях, в которых они могут быть заинтересованы. Это уведомление выполняется асинхронно. Имеются функции Oracle Call Interface (OCI) для регистрации обратного вызова, уведомляющего о сообщении. Обратный вызов (callback) - это функция в программе OCI, которая вызывается автоматически при появлении в очереди определенного сообщения. Фоновый процесс EMNn используется для уведомления подписчика. Процесс EMNn запускается автоматически при выдаче первого уведомления в экземпляре. После этого приложение может явно вызвать message_receive(dequeue) для извлечения сообщения из очереди. Подчиненные процессыТеперь мы готовы рассмотреть последний класс процессов Oracle - подчиненные процессы. В сервере Oracle есть два типа подчиненных процессов - ввода-вывода (I/O slaves) и параллельных запросов (Parallel Query slaves). Подчиненные процессы ввода-выводаПодчиненные процессы ввода-вывода используются для эмуляции асинхронного ввода-вывода в системах или на устройствах, которые его не поддерживают. Например, ленточные устройства (чрезвычайно медленно работающие) не поддерживают асинхронный ввод-вывод. Используя подчиненные процессы ввода-вывода, можно сымитировать для ленточных устройств такой способ работы, который операционная система обычно обеспечивает для дисков. Как и в случае действительно асинхронного ввода-вывода, процесс, записывающий на устройство, накапливает большой объем данных в виде пакета и отправляет их на запись. Об их успешной записи процесс (на этот раз - подчиненный процесс ввода-вывода, а не ОС) сигнализирует исходному вызвавшему процессу, который удаляет этот пакет из списка данных, ожидающих записи. Таким образом, можно существенно повысить производительность, поскольку именно подчиненные процессы ввода-вывода ожидают завершения работы медленно работающего устройства, а вызвавший их процесс продолжает выполнять другие важные действия, собирая данные для следующей операции записи. Подчиненные процессы ввода-вывода используются в нескольких компонентах Oracle 8i - процессы DBWn и LGWR используют их для имитации асинхронного ввода-вывода, а утилита RMAN (Recovery MANager - диспетчер восстановления) использует их при записи на ленту. Использование подчиненных процессов ввода-вывода управляется двумя параметрами инициализации.
Подчиненные процессы параллельных запросовВ Oracle 7.1 появились средства распараллеливания запросов к базе данных. Речь идет о возможности создавать для SQL-операторов типа SELECT, CREATE TABLE, CREATE INDEX, UPDATE и т.д. план выполнения, состоящий из нескольких планов, которые можно выполнять одновременно. Результаты выполнения этих планов объединяются. Это позволяет выполнить операцию за меньшее время, чем при последовательном выполнении. Например, если имеется большая таблица, разбросанная по десяти различным файлам данных, 16-процессорный сервер, и необходимо выполнить к этой таблице запрос, имеет смысл разбить план выполнения этого запроса на 16 небольших частей и полностью использовать возможности сервера. Это принципиально отличается от использования одного процесса для последовательного чтения и обработки всех данных. РезюмеВот и все компоненты СУБД Oracle. Мы рассмотрели файлы, используемые в СУБД Oracle: небольшой, но важный файл параметров инициализации init.ora, файлы данных, файлы журнала повторного выполнения и т.д. Мы изучили структуры памяти, используемые экземпляром Oracle как в серверных процессах, так и в области SGA. Было показано, как различные конфигурации сервера, например подключение в режиме MTS и к выделенному серверу, принципиально влияют на использование памяти в системе. Наконец, мы рассмотрели процессы (или потоки - в зависимости от базовой ОС), обеспечивающие выполнение функций сервера Oracle. Теперь мы готовы к рассмотрению других возможностей сервера Oracle - управления блокированием и одновременным доступом, и поддержки транзакций. Ссылки по теме
|
|