Что вы видите на закладке «Общая информация» в IBAnalyst?

Введение

Этот документ объясняет отображение информации (статистики баз данных InterBase и Firebird) в IBAnalyst в разделе «Общая информация» и поясняет, как ее интерпретировать. Также мы добавили в дистрибутив IBAnalyst несколько примеров, чтобы можно было понять соотношение транзакций и сравнить их с информацией в вашей базе данных.

! IBAnalyst начиная с версии 2.0 платный, а с 2017 отдельно от пакета HQbird не продается (поддерживает все последние версии Firebird и InterBase). Версия IBAnalyst 1.9 бесплатна, поддерживает статистику до Firebird 2.0 и InterBase 7.5.

Если вы не знаете, что такое Oldest transaction, Oldest snapshot, Active и Next, предварительно прочитайте статьи:  

Номера транзакций в Header Page

Если вы даже прочитали вышеуказанные статьи, все равно вам может показаться неясным назначение OIT/OST/OAT в Header Page. Вот краткая таблица:
Номер Застревает, ... Застревание приводит к ... Двигается вперед ...
Oldest transaction когда в транзакции с этим номером было отменено по rollback много изменений, или когда произошел обрыв соединения
  • автоматическому срабатыванию sweep, если sweep interval >0 и разница между Oldest и Oldest Snapshot (в IB 7.1/7.5 – Oldest Active) станет больше sweep interval
  • увеличению памяти, потребляемому транзакциями snapshot
при успешной отработке автоматического или ручного (gfix -sweep) sweep
Oldest Snapshot когда долго длится транзакция snapshot (или read committed write в версиях до IB 7.1), запомнившая OST на момент своего старта накоплению версий записей при старте очередной транзакции, если транзакция, удерживавшая OST, завершилась
Oldest Active когда транзакция с данным номером остается активной длительное время накоплению версий записей при старте очередной транзакции, если транзакция, удерживавшая OAT, завершилась
Next никогда   при старте очередной транзакции
Примечание. Oldest transaction в статьях упоминается и как Oldest Interesting Transaction (OIT). Это одно и то же.
 

Нормальное состояние базы данных

Примеры статистики находятся в каталоге Examples. Запустите IBAnalyst и откройте (меню Статистика/Загрузить из файла) файл !allok.txt.



IBAnalyst 1.7 и выше показывает не только дату создания базы данных, но и также анализирует текущее время получения статистики через Services API, или время создания файла статистики.

Поэтому мы не рекомендуем редактировать полученные файлы статистики. Иначе IBAnalyst будет некорректно считать среднее число транзакций в день. В этом примере строка Transactions per day показывает, что в день в этой БД совершается примерно 12500 транзакций, и база данных "живет" в течение 8-ми дней с момента своего создания или restore.

Здесь транзакции Oldest, Oldest snapshot, Oldest active и Next transactions находятся в отличном соотношении. Мы желаем, чтобы в ваших базах данных примерно так было всегда.

Перед анализом вашей базы данных убедитесь, что вы получили статистику из базы данных, находящейся в работе. Большинство предупреждений по состоянию транзакций базируются на оценке промышленной загрузки и времени жизни базы данных. Если в вашей базе данных низкая активность (меньше ~1000 транзакций в сутки, обычно в процессе разработки), или база данных длительное время не использовалась, рекомендации и предупреждения IBAnalyst могут оказаться бесполезными.
 

Много активных транзакций

Теперь откройте файл !lotofactive.txt (вы можете вернуться к картинке !allok в любой момент для того, чтобы сравнить с ней все последующие примеры).



Здесь строка Active transactions помечена красным, потому что существует большая разница между Oldest active и Next transaction. Это означает, что на момент сбора статистики некоторая транзакция была активной, в то время как после нее стартовало 55,000 транзакций (которые могут быть в любом состоянии – активны, завершены по commit/rollback, или in limbo). Поскольку среднее число транзакций в день примерно ~12500, IBAnalyst показывает вам предупреждение, что некоторая транзакция находится в активном состоянии уже на протяжении 4.4 дней. Такое может происходить, если:
  • некоторое приложение работает, и держит открытой хотя бы одну транзакцию – например, пользователь не закрыл приложение, и какая-либо его форма очень долго открыта.
  • приложения работают длительное время, и "теряют" хэндлы транзакций в коде – если ваш код (или используемые компоненты/библиотеки) создают  транзакции динамически, то возможно где то не происходит завершения такой транзакции по неизвестным причинам.
  • ваши приложения не работают с транзакциями явно (BDE), оставляя работу с транзакциями на усмотрение используемых компонент доступа. В результате длительность активных транзакций никак не контролируется приложением, и можно с большой уверенностью сказать, что большинство транзакций от Oldest Active до Next действительно являются активными.
  • используемая библиотека компонент или драйвер работает с "транзакцией по умолчанию", которой вы не управляете. Поскольку контроля над такой транзакцией нет, она может длиться долго.
Жаль, но статистика не может сказать, какое количество действительно активных транзакций работают в данный момент. Это может быть просмотрено только в InterBase 7.x при помощи IBConsole, IB Performance Monitor или прямым запросом к временной системной таблице tmp$transactions. В Firebird 1.5 это можно сделать вызовом isc_database_info с параметром isc_info_active_transactions.
 

Oldest transaction

Это номер транзакции, которая завершилась по rollback или была переведена сервером в состояние rollback из-за обрыва соединения, в котором эта транзакция работала. Застревание Oldest transaction буквально означает, что где то в базе данных есть версии записей, которые однозначно являются мусором и должны быть удалены. В то же время застревание Oldest transaction не говорит о том, что в базе данных накапливается мусор – если все записи в базе данных так или иначе прочитываются приложениями, то вероятнее всего накопленные мусорные версии будут удалены посредством кооперативной сборки мусора (фоновой или явной).
 

Sweeping

Откройте !needsweep.txt.

Sweep это процесс, который просматривает все записи в базе данных и пытается убрать их мусорные версии, а также подвинуть "вверх" Oldest transaction. В созданной БД Sweep interval по умолчанию равен 20000. Когда разница между транзакциями (см. таблицу дальше) становится больше Sweep interval, сервер автоматически стартует sweep. В результате вы можете наблюдать периодическое падение производительности вашей БД. Например, ваши приложения нормально работают в понедельник, вторник, в среду вдруг все начало медленно работать, а потом производительность восстановилась. Если вы наблюдаете такие перепады, значит периодически включается  автоматический sweep.
 
Версия сервера Когда стартует sweep?
InterBase 7.1 и выше (Oldest Active – Oldest) > Sweep interval
InterBase 4.x, 5.x, 6.x, Firebird, Yaffil (Oldest Snapshot – Oldest) > Sweep interval
Замечание. IBAnalyst автоматически показывает правильную строку Sweep gap для этих версий. Он детектирует разницу путем определения версии ODS. У баз данных, созданных в Interbase 7.x ODS 11.x, у других серверов базы данных пока создаются в ODS 10.x (у InterBase 5.x ODS равен 9.x и так далее). Поведение InterBase 7.x с базами ODS 10 не проверялось, в этом случае в Параметры/Transactions есть опция Only InterBase 7.x is used, что позволяет включить одинаковый расчет sweep gap для баз ODS 10 и 11.
Когда в статистике обнаруживается, что Sweep interval не равен 0, IBAnalyst обычно помечает эту строку желтым цветом (предупреждая вас о том, что автоматический sweep может стартовать в любой неожиданный момент). В общем 60% промышленных приложений сталкиваются с проблемой автоматического sweep. Самый легкий путь избежать этой проблемы – установить sweep interval в 0, что, собственно, его выключает совсем. Но, если какое-либо приложение сделает много изменений, а затем rollback, то "застрянет" Oldest transaction, и не будет двигаться до тех пор, пока не будет запущен sweep. Поскольку сервер определяет состояния транзакций в интервале от Oldest до Next, эта дистанция будет расти, и производительность будет падать. Для предотвращения этого надо запускать sweep вручную (gfix –sweep). На следующей картинке как раз такая ситуация и изображена – sweep interval = 0, и много изменений было отменено по rollback:

 

Здесь строка Sweep gap показывает, что некая транзакция с многими изменениями была отменена примерно 4.5 дней назад. Мы рекомендуем запускать sweep вручную, например каждый день, когда минимум пользователей работают с базой данных.

Конечно, для упомянутых 60% промышленных систем, возможно, было бы лучше установить Sweep interval больше или меньше умолчательного, однако его эффективное значение можно определить только экспериментально, и оно будет зависеть от многих факторов (среднедневное число транзакций – один из таких факторов). Либо, оставляя Sweep interval в 0, вы просто не хотите, чтобы такой процесс как sweep, запускался автоматически в произвольный (неизвестный вам) момент.

Точно такую же картину вы можете наблюдать в файле !rollback.txt.
 
Замечание. Если sweep стартует автоматически, и в базе много мусора, то за время его работы транзакции Snapshot, Active и Next могут уйти вперед настолько, что после своего завершения sweep автоматически запустится опять при старте ближайшей транзакции.
 

Когда sweep не может выполнить свою работу?

Есть несколько ситуаций, когда sweep не может продвинуть вперед Oldest transaction. Конечно, sweep сначала пытается сделать свою работу, то есть проверить все записи на наличие мусорных версий и собрать их. Но sweep будет запускаться вновь и вновь если



были проблемы во время работы sweep: либо сервер был остановлен, либо произошла какая то ошибка, например при обращении к поврежденной мусорной версии записи. В дополнение, такое соотношение транзакций в вашей базе данных может быть, когда:
  • статистика была собрана в момент работы sweep
  • sweep работает и пытается собрать мусор в таблице, которая часто обновляется. Sweep будет пытаться убрать мусор снова и снова, до тех пор пока update не прекратятся или станут выполняться реже.
  • sweep "застрял" на блокировках страниц, если с базой интенсивно работает много пользователей.

В общем, sweep имеет мало шансов завершиться в обозримый интервал времени при высокой загрузке базы данных. Обычно, когда производительность падает до такого состояния, что работать дальше невозможно, администратор БД перезагружает сервер, sweep стартует при первом коннекте, и пока остальные пользователи подключаются к БД, sweep успевает завершить свою работу.

Поскольку InterBase 7.1 вычисляет разницу для Sweep gap иначе, чем предыдущие версии, есть еще одна ситуация, когда sweep не сработает – это когда некоторое приложение удерживает транзакцию snapshot в активном состоянии:



Здесь два предупреждения – "желтое" для длительно работающего Sweep, и "красные" для ненулевого Sweep interval, и Sweep gap, который больше этого интервала. 
 

Долгоживущий snapshot

Предыдущая картинка показывала наличие транзакции snapshot, находящейся длительное время в активном состоянии. Если Sweep interval установлен в 0, то "красных" предупреждений не будет, только "желтое". Очень похожая картинка показывает "долгоживущий" snapshot:



Как вы видите здесь, для ODS 10 (все остальные кроме IB 7.x) Sweep gap вычисляется как разница между Oldest Snapshot и Oldest transaction. Поэтому тут нет предупреждения по "неработающему sweep" (за исключением предупреждения о ненулевом sweep interval).

Но, не только транзакции snapshot могут привести транзакции в такое состояние. Все версии InterBase, Firebird и Yaffil, за исключением InterBase 7.1/7.5 имеют некоторое поведение, которое мы назвали как "артефакт read_committed ".
 

Когда ReadCommitted блокирует Oldest Snapshot?

Откройте !snapshot2.txt:



Обратите внимание, что Oldest transaction больше Oldest snapshot. И Sweep gap имеет отрицательное значение. Это может произойти в двух случаях. Первый случай, когда есть периодически стартуемые и завершаемые транзакции snapshot. То есть, эта картинка показывает наличие "долгоживущих" snapshot так же, как и предыдущая. Второй случай происходит на серверах, кроме IB 7.1, при работе с ReadCommitted транзакциями (или в комбинации read_committed и snapshot). Здесь транзакция ReadCommitted блокирует Oldest Snapshot точно таким же образом, как транзакции Snapshot. Это поведение является историческим, и оно является результатом недоделок при реализации Read Committed на базе Snapshot в Borland (изначально в InterBase были только snapshot-транзакции).

Такое состояние транзакций может быть сэмулировано так:
  1. стартуйте транзакцию 1, snapshot или read_committed
  2. стартуйте/завершите много транзакций read_committed
  3. стартуйте транзакцию 2, snapshot или read_committed
  4. стартуйте/завершите много транзакций read_committed
  5. сделайте commit транзакции 1
В этот момент текущая активная транзакция 2 (snapshot или read_committed), стартовавшая после старта транзакции 1 (пункт 3), будет удерживать номер Oldest Snapshot (если у вас IB 7.1 и выше, то речь идет только о конкурирующих snapshot. Транзакции read_committed или read_committed+snapshot не будут создавать такой эффект). Так как не было откатов (rollback) больших транзакций, Oldest transaction продвигается вперед, и становится больше, чем Oldest Snapshot.

Таким образом, если у вас есть приложения с  длинными read_committed транзакциями, вы можете наблюдать именно эту картину. К сожалению, здесь переработкой транзакций в приложениях сделать ничего нельзя (за исключением установки читающих транзакций в read read_committed). И разумеется, в этом случае sweep не будет автоматически запускаться (если sweep interval <> 0).
 
Примечание. Данное поведение в отношении read_committed исправлено в Firebird 2.0.
 

Абсолютный и относительный вид

По умолчанию IBAnalyst закрашивает строки транзакций в процентном соотношении к абсолютному значению. То есть 100% считается от 0 до Next transaction. Иногда, когда база данных работает длительное время, можно наблюдать следующее состояние транзакций:



Как видите, числа большие, и разница между snapshot, active и oldest отображается плохо (то есть плотно, все примерно на уровне 97% от Next). Для того, чтобы видеть ситуацию лучше, откройте диалог Параметры, закладку Transactions, и включите "Relative (from oldest) bars %". После нажатия OK закраска изменится на следующую:



Теперь вы видите соотношение транзакций в относительном виде (100% от Oldest (или Snapshot) транзакции до Next, а не от 0). Так легче понять текущую ситуацию и увидеть возможные предупреждения (если таковые будут).

Такой вид сохранится до тех пор пока вы не выключите указанный параметр в окне Параметры. Определить, абсолютный или относительный вид используется, можно по закраске строк Oldest Transaction или Oldest snapshot – в абсолютном виде строка Oldest transaction закрашена всегда (хотя бы часть), а в относительном всегда пустая строка Oldest или Oldest snapshot (одна из двух, но не обе).

Все еще есть вопросы? Напишите нам на  support@ibase.ru.
 

Дополнения

Подпишитесь на новости Firebird в России

Подписаться