Проектирование и разработка подсистемы управления транзакциями для АСУД "ЕВФРАТ"

Механизмы управления транзакциями в СУБД. Обзор средств удаленного взаимодействия с объектами. Разработка подсистемы управления транзакциями. Практический анализ производительности подсистемы. Способы защиты пользователей от опасных и вредных факторов.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 14.03.2013
Размер файла 449,9 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Оглавление

  • 1. Введение
  • 2. Специальная часть
  • 2.1 Анализ и обзор существующих решений
  • 2.1.1 Механизмы управления транзакциями в СУБД
  • 2.1.2 Системы управления распределенными транзакциями
  • 2.1.3 Управление транзакциями в среде .NET
  • 2.1.4 Средства удаленного взаимодействия с объектами
  • 2.1.5 Выводы
  • 2.2 Постановка задач
  • 2.3 Разработка подсистемы управления транзакциями
  • 2.3.1 Предлагаемая модель подсистемы управления транзакциями
  • 2.3.2 Модель производительности подсистемы
  • 2.3.3 Практическая реализация подсистемы
  • 2.3.4 Практический анализ производительности подсистемы
  • 2.3.5 Рекомендации по использованию
  • 2.4 Выводы
  • 3. Экологическая часть и безопасность жизнедеятельности
  • 3.1 Исследование воздействия опасных и вредных факторов при эксплуатации ЭВМ и их воздействие на организм человека
  • 3.2 Способы защиты пользователей от опасных и вредных факторов
  • 3.3 Выводы
  • Заключение
  • Список литературы
  • Приложения

1. Введение

Один из способов увеличения производительности вычислительных систем - это переход от одноядерной процессорной архитектуры к многоядерной. Многоядерные процессоры позволяют увеличить количество инструкций, выполняемое за единицу времени. Однако производительность так же будет зависеть от используемого приложения и его оптимизации для выполнения на многоядерном процессоре. Чтобы приложение могло одновременно задействовать несколько процессорных ядер, оно должно хорошо распараллеливаться, иначе, если программный код подразумевает только последовательное выполнение, пользы от многоядерности не будет.

С каждым годом в мире компьютерной индустрии возрастает значимость так называемого «промежуточного программного обеспечения». Существует множество продуктов этой категории, производимых крупными, средними и даже мелкими компаниями, специализирующимися на программном обеспечении. В настоящее время термин «промежуточное программное обеспечение» («middleware») относится к любому программному компоненту, который располагается между пользовательскими приложениями на персональных компьютерах и РСУБД или унаследованной системой, непосредственно управляющими необходимыми данными.

Управление транзакциями - один из важнейших аспектов при создании надежных распределенных систем, хотя в различных технологиях создания таких систем степень универсальности управления транзакциями может существенно варьироваться.

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

2. Специальная часть

2.1 Анализ и обзор существующих решений

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

2.1.1 Механизмы управления транзакциями в СУБД

Для обеспечения целостности базы данных в классических СУБД используется механизм транзакций. Все операции с базой данных осуществляются только от лица транзакций, чье выполнение контролируется специальным алгоритмом, гарантирующим сохранение целостности базы. Алгоритмы управления транзакциями регулируют порядок совместной работы нескольких транзакций и поэтому обычно называются протоколами управления транзакциями. Такие протоколы основываются на предположении, что каждая из управляемых ими транзакций обладает некоторым заданным набором свойств. Разные протоколы могут опираться на разные наборы свойств транзакций, но наиболее стандартным является так называемый набор свойств ACID:

· Atomicity (атомарность): определяет, что транзакция является наименьшим, неделимым блоком алгоритма изменения данных. Другими словами, любые части (подоперации) транзакции либо выполняются все, либо не выполняется ни одной такой части. Поскольку на самом деле невозможно одновременно и атомарно выполнить последовательность команд внутри транзакции, вводится понятие «отката» (rollback): если транзакцию не удаётся полностью завершить, результаты всех до сих пор произведённых действий должны быть отменены и система возвращается в исходное состояние;

· Consistency (непротиворечивость): по окончанию транзакция оставляет данные в непротиворечивом состоянии;

· Isolation (изоляция): во время выполнения транзакции другие процессы не должны видеть данные в промежуточном состоянии;

· Durability (постоянство): независимо от проблем на нижних уровнях (к примеру, обесточивание системы или сбои в оборудовании) изменения, сделанные успешно завершённой транзакцией, останутся сохранёнными после возвращения системы в работу.

Обязательным требованием, предъявляемым к любому протоколу управления транзакциями, является условие сохранения целостного состояния базы данных при совместном выполнении транзакций. Основным критерием определения сохранения целостности базы и, следовательно, корректности работы протокола является критерий сериализуемости получающихся расписаний[1].

Все протоколы управления транзакциями подразделяются на два класса: пессимистические и оптимистические.

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

Одним из наиболее широко распространенных пессимистических протоколов является «двухфазный протокол» (2PL)[2], согласно которому все операции блокирования ресурсов должны предшествовать всем операциям разблокирования. В классическом варианте этого протокола рассматриваются блокировки двух видов - на чтение и на изменение.

Серьезная проблема, которая может возникнуть при применении пессимистического протокола, - это так называемая проблема возникновения «тупиков» (deadlock). Тупик - это такая ситуация, при которой каждая транзакция из некоторого множества ожидает получения блокировки на элемент, который в данный момент времени заблокирован другой транзакцией из этого множества. Попавшие в ситуацию тупика транзакции самостоятельно покинуть его не в силах и могут ждать вечно. Для борьбы с тупиками используются специальные методы их обнаружения и разрешения.

Основная идея оптимистических протоколов - максимизировать объем выполняемой работы. Эти протоколы дают шанс работать всем транзакциям, но разрешают благополучно завершиться только тем из них, чье завершение не влечет нарушения целостности базы.

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

По типу проверки оптимистические протоколы делятся на «вперед смотрящие»[3] (forward validation) и «назад смотрящие»[4] (backward validation). Различие состоит в выборе множества транзакций для проверки на наличие конфликтов при завершении некоторой транзакции. Протоколы из первой группы используют в качестве такого множества все еще не завершенные транзакции (и анормально завершают все те из них, которые конфликтуют с целевой транзакцией, либо саму транзакцию). А «назад смотрящие» проводят проверку по отношению ко всем нормально завершившимся транзакциям и в случае конфликта анормально завершают только целевую транзакцию.

Основным недостатком пессимистического подхода являются простои во время тупиков и растрата машинных ресурсов на их обнаружение и разрешение. Оптимистический подход бесполезно тратит машинные ресурсы на работу транзакций, которые позже будут анормально завершены из-за возникновения конфликтов, а также на работу на стадии проверки при завершении каждой транзакции. Экспериментальные результаты показывают, что в случае классических СУБД пессимистический подход обычно показывает лучшие результаты[5,6]. Поэтому в большинстве современных промышленных СУБД используются разновидности пессимистических протоколов.

В отличие от классических СУБД в системе реального времени с каждой транзакцией ассоциируется директивный срок, т.е. момент времени, до которого транзакция должна быть завершена. По типу директивных сроков СУБД реального времени можно разделить на три основные группы: с жесткими, крепкими и мягкими директивными сроками[7]. В системе с жесткими директивными сроками любая задержка эквивалентна катастрофе, а с крепкими и мягкими директивными сроками только понижает производительность системы. Различие последних состоит в том, что в системе с крепкими директивными сроками транзакция, пропустившая свой директивный срок, выкидывается из системы, а в системе с мягкими директивными сроками такая транзакция просто становится менее значимой, но все еще может быть с пользой завершена.

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

Еще одним важным отличием от случая классических СУБД является использование других критериев производительности. В классических СУБД, производительность обычно измеряется как среднее число завершившихся транзакций в единицу времени, а в системе, работающей в реальном времени, на первый план выходят другие параметры - количество транзакций, пропустивших свои диpективные сроки, среднее опоздание транзакций и т. п. Производительность же обычно меряют при помощи величины, которая зависит от нескольких таких параметров.

Способы вычисления этих величин сильно отличаются для разных типов СУБД реального времени. Так, например, в системах с крепкими директивными сроками среднее время опоздания транзакций не играет никакой роли, в то время как в системах с мягкими директивными сроками этот параметр довольно полезен.

Отличие критериев производительности, используемых в базах данных реального времени, от тех, что используются в классических СУБД, является основной причиной далеко не лучшей производительности при применении в системах реального времени классических протоколов управления транзакциями. Это, очевидным образом, влечет необходимость использования в таких системах других протоколов, которые лучше справляются со специфическими требованиями систем реального времени.

Используемые в СУБД реального времени протоколы должны использовать приоритеты транзакций, основанные на их директивных сроках, при разрешении конфликтов, для того, чтобы гарантировать, что транзакция с большим приоритетом не будет задержана транзакцией с меньшим приоритетом. Это требование совершенно не учитывается в классических протоколах и это является одной из основных причин их неудовлетворительной производительности.

Наиболее известными пессимистическими протоколами для баз данных в системах реального времени являются модификации 2PL. Рассмотрим вкратце некоторые из них.

Основная идея первой модификации, называемой 2PL-HP (High Priority)[8] - разрешать все конфликты в пользу транзакций с большим приоритетом. Если ресурс, на который транзакция запрашивает блокировку, свободен, транзакция получает блокировку. Если он заблокирован, то возможны варианты:

· если запрашиваемая блокировка не конфликтует с уже существующими блокировками других транзакций на означенный ресурс, то она выдается, если приоритет транзакции выше, чем у всех транзакций, стоящих в очереди на блокировки этого ресурса;

· если транзакция имеет приоритет выше, чем у всех держателей блокировок на ресурс, то все они должны быть оборваны и транзакция получает блокировку;

· в остальных случаях транзакция становится в очередь на эту блокировку.

Протокол 2PL-HP гарантирует отсутствие тупиков.

Другая модификация - 2PL-WP (Wait Promote)[9] - основана на идее наследования приоритета. Когда первая транзакция с большим приоритетом запрашивает блокировку на какой-то ресурс, который в данный момент заблокирован второй транзакцией с меньшим приоритетом, то она встает в очередь (как в 2PL), при этом второй транзакции повышают приоритет до уровня приоритета первой. В результате вторая транзакция может быть выполнена быстрее, поскольку ей меньше придется простаивать дожидаясь других ресурсов, и, следовательно, приближается момент получения блокировки на означенный ресурс первой транзакцией. Однако, при применении этого метода (из-за рекурсивного повышения приоритетов) легко может возникнуть ситуация, когда большинство или даже все транзакции имеют одинаковый приоритет. В таком случае поведение этого протокола будет мало отличаться от поведения классического 2PL.

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

Протокол OPT-SACRIFICE[10] является адаптированным к СУБД реального времени вариантом протокола OCC-FV (Optimistic Concurrency Control with Forward Validation). Согласно OPT-SACRIFICE транзакция, достигшая фазы проверки, обрывается, если хотя бы одна из конфликтующих с ней транзакций имеет больший приоритет. Иначе транзакция благополучно завершается, а все конфликтующие с ней транзакции завершаются анормально. Таким образом, проверяемая транзакция, которая уже почти завершилась, приносит себя в жертву ради еще работающей транзакции с большим приоритетом. Этот протокол имеет ряд слабых мест. Обрыв транзакции в пользу более высокоприоритетной означает, что работа по ее выполнению была выполнена напрасно и ресурсы, потраченные на это, были потрачены зря. Кроме того, не гарантирован факт нормального завершения более высокоприоритетной транзакции, таким образом жертва может оказаться напрасной.

Согласно протоколу OPT-WAIT[10], также принадлежащему к классу «вперед смотрящих» протоколов, транзакция, достигнув фазы проверки и обнаружив множество конфликтующих с ней транзакций, ведет себя следующим образом:

· если ее приоритет выше, чем у всех конфликтующих с ней транзакций, то она завершается нормально, а все конфликтующие - анормально;

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

Этот протокол, в отличие от OPT-SACRIFICE, не отличается обилием бесполезных рестартов, так как все они совершаются по необходимости. Однако он также имеет ряд слабых мест. Эффект блокирования, возникающий в результате задержки транзакции на стадии проверки (вместо ее непосредственного завершения или обрыва), приводит к консервированию ресурсов, тем самым приводя к тем проблемам, с которыми сталкиваются пессимистические протоколы в системах реального времени. Кроме этого, даже в случае успешного завершения задержанной транзакции, это может вызвать анормальное завершение множества более низкоприоритетных транзакций (как работающих, так и задержанных). Более того, число анормальных завершений может возрасти за счет тех низкоприоритетных транзакций, которые конфликтовали с задержанной транзакцией, но не конфликтовали с более высокоприоритетными. Это число может сильно расти с ростом времени задержки нашей транзакции.

Традиционно протоколы управления транзакциями различаются по двум критериям: время обнаружения конфликтов и способ их обнаружения. Согласно этим критериям пессимистические и оптимистические протоколы представляют собой две крайности. Пессимистические протоколы пытаются обнаружить конфликты сразу, еще до их возникновения, и разрешают их, используя механизм блокирования. Оптимистические протоколы занимаются обнаружением конфликтов при завершении транзакции и разрешают их, перезапуская часть конфликтующих транзакций. Оба способа разрешения конфликтов имеют свои недостатки. Блокирование приводит к консервированию ресурсов, а рестарты вызывают их растрату. В системах реального времени протокол управления транзакциями должен работать с большим количеством анормально завершающихся транзакций. И, если для оптимистических протоколов это знакомая ситуация, то для пессимистических протоколов рестарты являются новым ограничением.

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

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

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

В идеале транзакции разных пользователей должны выполняться так, чтобы создавалась иллюзия, что пользователь текущей транзакции -- единственный. В этом заключается реализация свойства Isolation из набора ACID, которая не обязательна, но в случае пренебрежения ею может повлечь появление проблем. В реальности, по соображениям производительности и для выполнения некоторых специальных задач, СУБД предоставляют различные уровни изоляции транзакций: неподтвержденное или грязное чтение (Read Uncommited), подтвержденное чтение (Read Commited), повторяемое чтение (Repeatable Read, Snapshot) и самый высокий - упорядоченный уровень (Serializable). Чем выше уровень изоляции, тем больше требуется ресурсов, чтобы их поддерживать. В СУБД уровень изоляции транзакций можно выбрать как для всех транзакций сразу, так и для некоторой конкретной транзакции. Подробнее об уровнях изоляции речь пойдет позже.

Полноценная реализация уровней изоляции и свойств ACID представляет из себя нетривиальную задачу. Обработка поступающих данных приводит к большому количеству маленьких изменений, включая обновление как самих таблиц, так и индексов. Эти изменения потенциально могут потерпеть неудачу, например если закончилось место на диске, операция занимает слишком много времени (timeout) и т. д. Система должна в случае неудачи корректно вернуть базу данных в состояние до транзакции.

Первые коммерческие СУБД (к примеру, IBM DB2), пользовались исключительно механизмом блокировок доступа к данным для реализации свойств ACID. Но большое количество блокировок приводит к существенному уменьшению производительности. Есть два популярных семейства решений этой проблемы, которые снижают количество блокировок: журнализация изменений (Write Ahead Logging, WAL) и механизм теневых страниц (Shadow Paging). В обоих случаях, блокировки должны быть расставлены на всю информацию, которая обновляется. В зависимости от уровня изоляции и имплементации, блокировки записи также расставляются на информацию, которая была прочитана транзакцией.

При «упреждающей журнализации», используемой в Sybase и MS SQL Server до версии 2005, записи о некоторой операции над базой данных попадают на энергонезависимый носитель (обычно в этой роли выступает жесткий диск) раньше, чем в базу вносятся изменения, произведенные этой операцией. Это позволяет СУБД вернуться в рабочее состояние после неожиданного отказа системы.

Альтернативной техникой, используемой для восстановления в случае сбоев, является механизм «теневых страниц». Основное отличие систем, использующих теневые страницы, от систем, где для восстановления используется только журнал, заключается в том, что последние записывают изменения, внесенные в страницу базы данных в то же место, где располагалась предыдущая версия данных. При использовании же теневых страниц, измененная версия страницы данных записывается на другое место диска. В случае сбоя можно восстановить базу данных на основе старой (теневой) версии страницы и журнала. Как видно, идея, стоящая за теневым механизмом, проста и легко поддается реализации. Однако по ряду причин техника восстановления на основе теневых страниц, несмотря на всю свою простоту, считается хуже, чем восстановление с использованием упреждающей журнализации.

Дальнейшее развитие СУБД привело к появлению так называемых «безблокировочных» технологий. Идея контроля за параллельным доступом с помощью временных меток (Timestamp-Based Concurrency Control) была развита и привела к появлению многоверсионной архитектуры MVCC. Управление конкурентным доступом с помощью многоверсионности (MVCC - MultiVersion Concurrency Control) заключается в предоставлении каждому пользователю так называемого «снимка» БД, обладающего тем свойством, что вносимые данным пользователем изменения в БД невидимы другим пользователям до момента фиксации транзакции. Этот способ управления позволяет добиться того, что пишущие транзакции не блокируют читающих, а читающие транзакции не блокируют пишущих. Эти технологии не нуждаются ни в журнализации изменений, ни в теневых страницах. Архитектура, реализованная в Oracle версии 7.х и выше, записывает старые версии страниц в специальный «сегмент отката», но они все ещё доступны для чтения. Если транзакция при чтении попадает на страницу, временная метка которой новее начала чтения, данные берутся из сегмента отката (то есть используется «старая» версия). Для поддержки такой работы ведётся журнал транзакций, но в отличие от «упреждающей журнализации», он не содержит данных. Работа с ним состоит из трёх логических шагов:

1. Записать намерение произвести некоторые операции;

2. Выполнить задание, копируя оригиналы изменяемых страниц в сегмент отката;

3. Записать, что всё сделано без ошибок.

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

· Если повреждена запись, то сбой произошёл во время проставления отметки в журнале. Значит, ничего важного не потерялось, игнорируем эту ошибку;

· Если все записи помечены как успешно выполненные, то сбой произошёл между транзакциями, здесь также нет потерь;

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

Firebird вообще не имеет ни журнала изменений, ни сегмента отката, а реализует MVCC, записывая новые версии строк прямо в активное пространство данных. Также поступает MS SQL 2005. Теоретически это даёт максимальную эффективность при параллельной работе с данными, но ценой является необходимость «сборки мусора», то есть удаления старых и уже не нужных версий строк.

2.1.2 Системы управления распределенными транзакциями

Существует два главных аспекта управления транзакциями, а именно: управление восстановлением и управление параллельностью обработки. Оба этих аспекта имеют расширенную трактовку в среде распределенных систем. Чтобы разъяснить особенности этой расширенной трактовки, сначала необходимо ввести новое понятие «агент». В распределенной системе отдельная транзакция может включать в себя выполнение кода на многих узлах[11]. Поэтому говорят, что каждая транзакция содержит несколько агентов, где под агентом подразумевается процесс, который выполняется для данной транзакции на отдельном узле. Система должна знать, что два агента являются элементами одной и той же транзакции, например два агента, которые являются частями одной и той же транзакции, очевидно, не должны оказаться в состоянии взаимной блокировки.

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

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

Распределенные объектные системы обеспечивают средства размещения и взаимодействия объектов в распределенной среде. Объекты идентифицируются именами или сервисами, а также поддерживаемыми ими интерфейсами. Реализация объекта и платформа, на которой он выполняется, прозрачны для клиента.

Во многих организациях используется более чем одна система баз данных, и требуется возможность выполнять транзакции, пересекающие границы этих систем. Многие системы баз данных требуют наличия отдельного процесса операционной системы для каждого подключенного пользователя. Для приложений с сотнями пользователей не хватает мощности даже самых крупных компьютеров. Кроме всего прочего, установление соединения с базой данных часто происходит медленно. Если много пользователей часто подключается и отключается, производительность системы серьезно деградирует. Эти проблемы решаются в большинстве систем, управляющих распределенными транзакциями, следующим образом:

· Обеспечивается одновременная связь с набором различных систем баз данных;

· Поддерживается двухфазный протокол фиксации, гарантирующий завершение транзакций над несколькими базами данных;

· Пользовательские запросы обрабатываются с использованием легковесных нитей - потоков (threads) операционной системы, а не полновесных процессов. Это позволяет использовать возможности SMP-систем (Symmetric MultiProcessor), таких как Sun Enterprise, Digital Alpha и Compaq Proliant;

· Поддерживается постоянный пул подключений к базам данных, и эти подключения разделяются между пользователями. В большинстве приложений каждый пользователь реально обращается к базе данных только часть общего времени. Часто сотни «одновременно работающих» пользователей могут быть эффективно обслужены за счет наличия одной трети или даже одной десятой от числа подключений к базе данных, требуемых для прямого доступа;

· Долговременное сохранение разделяемых подключений к базе данных существенно уменьшает трафик подключений;

· Обеспечивается балансировка нагрузки путем планирования использования разделяемых ресурсов и направления запросов к наименее загруженным серверам. Возможно, также обнаруживать и обрабатывать ситуации, когда сервер или другой ресурс выходит из строя и нуждается в перезапуске;

· Запросы обрабатываются асинхронно с распределением нескольких запросов к одному и тому же серверу между разными подключениями к базе данных (так называемый «конвейерный» параллелизм);

· Запросы распределяются между несколькими серверами баз данных (так называемый «развернутый» параллелизм).

Для координации операций разделенных и распределенных приложений поддерживается одноранговая связь с другими мониторами обработки транзакций.

2.1.3 Управление транзакциями в среде .NET

Все или ничего -- в этом главный смысл транзакции. При сохранении нескольких записей либо все они должны быть записаны, либо вся операция должна быть отменена. Если происходит один единственный сбой при внесении одной записи, то все, что было выполнено к этому моменту в пределах данной транзакции, откатывается. Транзакции широко используются при работе с базами данных, но классы из пространства имен System.Transaction библиотеки классов .NET Framework позволяют выполнять транзакции с изменчивыми или находящимися в памяти объектами, такими как списки объектов[12]. Если список поддерживает транзакции, объект добавляется или удаляется и транзакция завершается неудачей, то все операции со списком автоматически отменяются. Запись в списки, находящиеся в памяти может выполняться в той же транзакции, что и запись в базу данных.

Наиболее распространено применение транзакций при внесении и обновлении информации в базе данных. Транзакции также могут выполняться при записи сообщения в очередь сообщений или при записи данных в файл или системный реестр. Несколько действий могут быть частями одной транзакции. Транзакция характеризуется набором свойств ACID, подробно описанным ранее. В типовом случае транзакции управляются и координируются диспетчером транзакций. Любой ресурс, влияющий на исход транзакции, управляется диспетчером ресурсов. Диспетчер транзакций взаимодействует с диспетчерами ресурсов, определяя исход транзакции.

Выделяют следующие фазы времени выполнения транзакции: активная, подготовительная и фаза фиксации. Во время активной фазы транзакция создается, диспетчеры ресурсов, управляющие транзакцией для ресурсов, принимают участие в транзакции. Во время подготовительной фазы каждый диспетчер ресурсов может определять исход транзакции. Эта фаза стартует, когда инициатор транзакции посылает подтверждение для того, чтобы завершить транзакцию. Диспетчер транзакции посылает сообщение Prepare (подготовиться) всем диспетчерам ресурсов. Если диспетчер ресурсов может выполнить свою работу для успешного исхода транзакции, он посылает сообщение Prepared (готов) диспетчеру транзакций. Диспетчер ресурсов может прервать транзакцию, если он не может подготовиться к своей работе, заставив диспетчер транзакций выполнить откат. После того, как сообщение Prepared отправлено, диспетчер ресурсов должен гарантировать успешное завершение работы на фазе фиксации. Чтобы это было возможно, устойчивые диспетчеры ресурсов должны писать журнал, внося в него информацию о состоянии готовности, чтобы иметь возможность продолжить работу с этого места, например, в случае отключения питания между фазами подготовки и фиксации. Фаза фиксации начинается, когда все диспетчеры ресурсов успешно подготовились к работе, а именно - когда получено сообщение Prepared от всех участвующих диспетчеров ресурсов. Затем диспетчер транзакции может завершить работу транзакции и вернуть сообщение Commited.

До того, как в библиотеке классов .NET Framework появилось пространство имен System.Transaction, приходилось создавать транзакции традиционными способами непосредственно в ADO.NET либо реализовывать их с помощью компонентов, атрибутов и исполняющей системы COM+, которые содержались в пространстве имен System.EnterpriseServices.

При использовании традиционных транзакций ADO.NET если не создавать транзакцию вручную, то возможна единственная транзакция с каждым SQL-оператором. Если несколько операторов должны участвовать в одной и той же транзакции, придется создавать транзакцию вручную. Для создания соединения используется класс SqlConnection, который определяет метод BeginTransaction(), возвращающий после выполнения объект транзакции SqlTransaction. Этот объект затем должен быть ассоциирован с каждой командой, участвующей в транзакции. Чтобы ассоциировать команду с транзакцией, необходимо установить свойство Transaction класса SqlCommand в созданный экземпляр SqlTransaction. Таким образом, если имеется несколько команд, которые должны выполняться в одной транзакции, то каждая из них должна быть ассоциирована с транзакцией. Как каждая транзакция ассоциирована с соединением, так и каждая из этих команд должна быть ассоциирована с тем же экземпляром соединения; локальная транзакция всегда ассоциирована с одним соединением. В случае возникновения ошибок перечисленными классами генерируются исключения, которые могут быть отслежены и обработаны с помощью конструкции try/catch, где обработка заключается в вызове метода Rollback() транзакции для выполнения отката. Если создать объектную модель постоянного хранения, используя множество объектов, которые должны существовать внутри одной транзакции, то в этом случае становится очень трудно использовать транзакции ADO.NET. Здесь необходимо передавать транзакцию всем объектам, принимающим участие в этой транзакции. Кроме того, транзакции ADO.NET не являются распределенными. В транзакциях ADO.NET трудно заставить работать различные объекты в пределах одной и той же транзакции.

Пространство имен System.EnterpriseServices содержит множество полезных служб, одна из которых - автоматические транзакции. Использование транзакции с System.EnterpriseServices обладает тем преимуществом, что при этом не приходится иметь дело с транзакциями непосредственно; транзакции автоматически создаются исполняющей средой. Все, что необходимо сделать - это просто добавить атрибут [Transaction] с транзакционными требованиями в класс, а атрибутом [Autocomplete] - пометить метод для автоматической установки бита состояния транзакции: если метод успешен, устанавливается бит успеха, так что транзакция может быть зафиксирована. В случае исключения транзакция автоматически откатывается. Огромное преимущество создания транзакций с помощью System.EnterpriseServices состоит в том, что множество объектов могут быть легко запущены в одной и той же транзакции, и транзакции очень легко использовать. Недостатком же является то, что требуется модель хостинга COM + , и то, что класс, использующий средства этой технологии, должен наследоваться от базового класса ServicedComponent.

Пространство имен System.Transactions, доступное, начиная с версии .NET 2.0, привнесло новую транзакционную модель в приложения .NET. Transaction -- базовый класс для всех транзакционных классов, определяет свойства, методы и события, доступные во всех транзакционных классах. CommittableTransaction -- единственный транзакционный класс, поддерживающий фиксацию. У этого класса есть метод Commit(), все прочие транзакционные классы могут только выполнять откат. Класс DependentTransaction используется с транзакциями, зависящими от других транзакций. Зависимая транзакция может зависеть от транзакции, созданной внутри другой фиксируемой транзакции. Затем зависимая транзакция добавляет свое действие к исходу фиксируемой транзакции, если она успешна или нет. Класс SubordinateTransaction применяется в сочетании с координатором распределенных транзакций (Distributed Transaction Coordinator -- DTC). Этот класс представляет транзакцию, не являющуюся корневой, но управляемой DTC.

Класс Transaction не может быть зафиксирован (commit) программно; он не имеет метода для фиксации транзакции и поддерживает только прерывание транзакции. Единственный транзакционный класс, поддерживающий фиксацию, -- это CommitableTransaction. В ADO.NET транзакция может быть получена вместе с соединением. Объект одного из трех классов-наследников System.Transactions.Transaction может быть задействован с соединением посредством вызова метода EnlistTransaction класса SqlConnection, таким образом, соединение ADO.NET ассоциируется с транзакцией.

System.Transactions, как и SQL Server 2005, поддерживает распространяемые транзакции. В зависимости от ресурсов, принимающих участие в транзакции, создается локальная или распределенная транзакция. С ресурсами, не поддерживающими распространяемые транзакции, создаются транзакции распределенные. Если множество ресурсов добавляется к единственной транзакции, то такая транзакция может начинаться как локальная и при необходимости превращаться в распределенную.

Подобное превращение происходит, когда к одной транзакции добавляется множество соединений с базой данных SQL Server 2005. Транзакция стартует, как локальная и затем превращается в распределенную, это отражает распределенный идентификатор, который приобретает значение, отличное от нуля. Распространение транзакции требует запуска координатора распределенных транзакций (DTC).

В случае зависимых транзакций появляется возможность влиять на одну транзакцию из множества потоков. Зависимая транзакция зависит от некоторой другой транзакции и влияет на ее исход. Зависимая транзакция DependantTransaction может определять исход транзакции, вызвав либо метод Complete(), либо метод Rollback(). Метод Complete() устанавливает бит успеха. Если корневая транзакция завершается, и все зависимые транзакции имеют бит успеха, установленный в true, то транзакция фиксируется. Если любая из зависимых транзакция устанавливает бит прерывания, вызывая Rollback(), то и вся корневая транзакция отменяется. Запустить зависимую транзакцию можно следующим образом: в начале создается объект CommitableTransaction, затем вызывается метод DependentClone() этого объекта, который возвращает объект DependantTransaction. Метод DependentClone() требует аргумента типа DependentCloneOption, который представляет собой перечисление, состоящее из двух возможных значений: BlockCommitUntilComplete и RollbackIfNotComplete. Эта опция важна, если корневая транзакция завершается перед зависимой транзакцией. Установив данную опцию в RollbackIfNotComplete, транзакция прерывается, если зависимая транзакция не вызывает метод Complete() перед вызовом Commit() корневой транзакции. Установив опцию BlockCommitUntilComplete, метод Commit() ожидает, пока не будет ясен исход всех зависимых транзакций.

Наибольшим преимуществом System.Transactions является средство включающих (ambient) транзакций. При использовании включающих транзакций нет необходимости вручную связывать соединение с транзакцией; это делается автоматически из включающих транзакций, поддерживающих ресурсы. Включающая транзакция ассоциируется с текущим потоком. Получать и устанавливать включающую транзакцию можно через статическое свойство Transaction.Current. API-интерфейсы, поддерживающие включающие транзакции, проверяют это свойство, чтобы получить такую транзакцию и соединить с текущей локальной транзакцией. Соединения ADO.NET поддерживают включающие транзакции. Таким образом, можно создать объект CommittableTransaction и присвоить его свойству Transaction.Current для инициализации включающей транзакции. Другой способ создания такой транзакции состоит в применении класса TransactionScope. Конструктор TransactionScope создает включающую транзакцию. Поскольку реализован интерфейс IDisposable, можно легко использовать область действия транзакции, применив оператор using. Конструктор по умолчанию создает новую транзакцию. Немедленно после создания экземпляра TransactionScope транзакция ассоциируется со средством доступа get свойства Transaction.Current для отображения информации о транзакции на консоли. Поскольку класс SqlConnection поддерживает включающие транзакции, он автоматически связывает их с соединением. Однако если соединение ADO.NET не должно связываться с включающей транзакцией, можно установить значение Enlist=false в строке соединения.

Используя класс TransactionScope, можно вкладывать области действия друг в друга. Вложенная область может располагаться непосредственно внутри другой области или внутри метода, вызванного из этой области. Вложенная область может использовать ту же транзакцию, что и внешняя область, подавлять транзакцию либо создавать новую транзакцию, независимую от внешней области. Требование для области действия заключается в том, что она должна быть определена перечислением TransactionScopeOption, передаваемым конструктору класса TransactionScope. Перечисление имеет следующие значения:

· Required - определяет, что область действия требует транзакции. Если внешняя область (контекст) уже содержит включающую транзакцию, то внутренняя область использует эту существующую транзакцию. Если же включающая транзакция не существует, то создается новая;

· RequiresNew - всегда создает новую транзакцию. Если во внешнем контексте уже определена транзакция, то транзакция из вложенной области действия полностью независима. Обе транзакции могут фиксироваться или отменяться независимо друг от друга;

· Suppress - область действия не содержит включающей транзакции, независимо от того, содержит внешняя область транзакцию или нет.

Если несколько потоков должны использовать одну и ту же включающую транзакцию, нельзя просто создать транзакционный контекст и внутри него создать новый поток. Поскольку включающие транзакции привязаны к потоку, вновь созданный поток не имеет включающей транзакции. Однако если это необходимо, можно создать зависимую транзакцию, которая будет зависеть от включающей транзакции. Внутри нового потока можно назначить зависимую транзакцию включающей транзакции.

Из всего набора свойств транзакции ACID изоляция требуется не всегда. Из соображений производительности можно снизить степень требуемой изоляции, но при этом нужно представлять себе возможные последствия изменения уровня изоляции. Проблемы, с которыми можно столкнуться, когда не полностью изолирован контекст извне транзакции, делятся на три описанных ниже категории.

· Грязное чтение. При грязном чтении другая транзакция может читать записи, измененные внутри данной транзакции. Поскольку данные, изменяемые внутри транзакции, могут быть откатаны к своему исходному состоянию, чтение такого промежуточного состояния из другой транзакции трактуется как «грязное», то есть данные не были зафиксированы. Этого можно избежать блокировкой изменяемых записей;

· Невоспроизводимое чтение. Невоспроизводимое чтение случается, когда данные читаются внутри транзакции, и пока эта транзакция выполняется, другая транзакция изменяет те же самые записи. Если запись читается повторно внутри транзакции, то получается отличающийся результат -- невоспроизводимый. Это можно предотвратить посредством блокировки чтения записей;

· Фантомное чтение. Фантомное чтение случается при чтении диапазона данных, например, с использованием конструкции WHERE. Другая транзакция может добавить новую запись, которая попадает в диапазон подлежащих чтению в транзакции. Новая запись с тем же выражением WHERE возвратит другое количество строк. Фантомное чтение может стать серьезной проблемой при выполнении оператора UPDATE для диапазона записей. Например, UPDATE Addresses SET Zip=4711 WHERE (Zip=2315) обновляет почтовый код во всех записях с 2315 на 4711. Однако после выполнения обновления в таблице могут остаться записи со значением почтового кода 2315, если другой пользователь добавит новую запись с кодом 2315 в то время, пока выполняется обновление. Этой проблемы можно избежать, если применить блокировку диапазона.

При определении требований изоляции можно установить уровень изоляции. Уровень изоляции устанавливается перечислением IsolationLevel, которое конфигурируется при создании транзакции (либо конструктором класса CommitedTransaction, либо конструктором класса TransactionScope). IsolationLevel определяет поведение блокировки. Перечисление содержит следующие значения:

· ReadUncommitted. С ReadUncommitted транзакции не изолированы друг друга. Этот уровень не предполагает ожидания блокированных записей из других транзакций. При этом незафиксированные данные могут быть прочитаны из других транзакций, то есть имеет место грязное чтение. Этот уровень обычно используется для чтения тех записей, для которых не страшно внесение промежуточных изменений, например, для отчетов;

· ReadCommitted. ReadCommitted ожидает записей, заблокированных по записи из других транзакций. При этом не может произойти никакого грязного чтения. Этот уровень устанавливает блокировку чтения текущей записи и блокировку записи тех, что должны быть записаны до завершения транзакции. Поскольку при чтении каждая запись разблокируется при переходе к следующей, при этом может случиться невоспроизводимое чтение;

· RepeatableRead. RepeatableRead удерживает блокировку чтения записей до тех пор, пока не завершится транзакция. При этом снимается проблема невоспроизводимого чтения. Однако все-таки могут возникнуть фантомные записи;

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

· Snapshot. Уровень изоляции Snapshot -- единственно возможный в SQL Server 2005. Этот уровень ограничивает блокировки, поскольку модифицируемые записи копируются. Таким образом, другие транзакции все же могут читать старые данные без необходимости ожидания разблокировки;

· Unspecified. Уровень Unspecified указывает, что поставщик использует другое значение уровня блокировки;

· Chaos. Уровень Chaos подобен ReadUncommitted, но в дополнение к действиям, характерным для ReadUncommitted, Chaos не блокирует обновляемые записи.

Уровень изоляции в классе TransactionScope может быть установлен с помощью конструктора, в котором можно установить, кроме всего прочего, TransactionOptions. Класс TransactionOptions позволяет определить уровень изоляции (IsolationLevel) и таймаут (Timeout).

2.1.4 Средства удаленного взаимодействия с объектами

Проблема связывания отдельных частей распределенных приложений существует почти столько же лет, сколько и сама вычислительная техника. Удаленный вызов процедур (Remote Procedure Call, RPC) остается важной технологией, используемой для «ручного» связывания компонентов распределенных приложений. Она опирается на синхронный режим взаимодействия между двумя прикладными модулями (клиентом и сервером), т. е. работа клиента блокируется до окончания обработки задания на сервере.

Для установки связи, передачи вызова и возврата результата клиент и сервер используют специальные программные «заглушки» (client stub и server stub). Эти процедуры не реализуют никакой прикладной логики, а лишь изолируют прикладные модули от уровня сетевых коммуникаций. Обычно описания этих stub-процедур генерируются средой разработки. И клиентская, и серверная программа могут вызывать их как обычные локально-исполняемые функции. Правда, для установления соединения необходимо проделать ряд дополнительных операций, как со стороны клиента, так и со стороны оболочки исполнения. Эти операции довольно типичны для всех подобных технологий, и о них будет сказано позднее.

В общем случае механизм RPC создает статические отношения между компонентами распределенного приложения: привязка клиентского процесса к конкретным серверным суррогатам происходит на этапе компиляции и сборки и не может быть изменена во время выполнения. Этим RPC невыгодно отличается от систем, ориентированных на обмен сообщениями (Message-Oriented Middleware, МОМ), позволяющих динамически выбирать сервер, или некоторых мониторов транзакций, поддерживающих возможности оптимального распределения нагрузки на серверы и средства восстановления при сбоях.

RPC очень широко используется в разных других технологиях. Например, на RPC базируется коммуникационный слой модели Windows COM/DCOM. Основной недостаток RPC-систем заключается в синхронности взаимодействия, из которого вытекает необходимость установления стабильного соединения между взаимодействующими приложениями (в принципе есть надстройки над RPC, эмулирующие асинхронность, но они не дают и десятой доли преимуществ МОМ). В итоге распределенные системы оказываются чувствительны к надежности и доступности каналов связи.

Компонентная модель COM (Component Object Model) является наследником средств динамического связывания приложений DDE (Dynamic Data Exchange), имевшихся еще в самых первых версиях Microsoft Windows. Она позволяет разбить приложение, работающее на отдельном ПК, на компоненты, характеризуемые четко описанными интерфейсами. Так как в таком компоненте пользователю доступен только интерфейс, то при его сохранении, сохраняется и связанность компонентного приложения, даже если отдельные компоненты заменяются на другие или, скажем, переписываются на другой язык программирования. Конечно, для сохранения работоспособности приложения в целом необходимо, чтобы каждый такой компонент вел себя в точности, как его предшественник.


Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.