Э. Таненбаум, М. ван Стеен - Распределённые системы (принципы и парадигмы) (1162619), страница 81
Текст из файла (страница 81)
Вместе с другими промежуточными результатами теряются и результаты завершившейся дочерней транзакции. Таким образом, долговечность, о которой мы говорили, применима только к транзакциямверхнего уровня.Поскольку глубина вложенности транзакций может быть произвольно глубокой, для сохранения правильности необходимо серьезное администрирование.Однако семантика ясна. Когда начинается любая транзакция или вложеннаятранзакция, создается закрытая копия данных всей системы. Если транзакцияпрерывается, ее внутренняя вселенная исчезает, как будто ее никогда и не было.Если она завершается, ее внутренняя вселенная замещает родительскую. Такимобразом, если дочерняя транзакция завершается и начинается новая дочерняятранзакция, вторая из них получает возможность работать с результатами, созданными первой. Таким же образом, если прерывается объемлющая (верхнегоуровня) транзакция, все вложенные в нее дочерние транзакции также прерываются.Распределенные транзакцииВложенные транзакции важны для распределенных систем, потому что OHPI предоставляют естественный способ распределения транзакций по нескольким машинам.
Однако вложенные транзакции обычно делят работу исходной транзакции логически. Например, транзакция, в ходе которой следовало зарезервироватьбилеты на три различных самолета (см. листинги 5.1 и 5.2), может быть логически разделена на три вложенные транзакции. Каждая из этих вложенных транзакций может управляться отдельно, независимо от остальных двух.Однако логическое разделение вложенных транзакций на вложенные транзакции не обязательно означает, что все распределение в этом и состоит.
Так, вложенная транзакция резервирования места в самолете от Нью-Йорка до Найробиможет нуждаться в доступе к двум базам данных, по одной для каждого из этихгородов. В этом случае вложенная транзакция может разделяться дальше, наменьшие вложенные транзакции, которые логически уже не существуют, поскольку резервирование само по себе является неделимой операцией.В этом случае вложенные транзакции (плоские) работают с данными, распределенными по нескольким машинам.
Такие транзакции известны под названиемраспределенных транзакций {distributed transactions). Разница между вложенными и распределенными транзакциями невелика, но существенна. Вложенныетранзакции — это транзакции, которые логически разделяются на иерархическиорганизованные дочерние транзакции. В противоположность им распределенные транзакции логически представляют собой плоские, неделимые транзакции,312Глава 5. Синхронизациякоторые работают с распределенными данными. Эту разницу иллюстрируетрис. 5.17.Вложенная транзакцияДочерняятранзакцияРаспределенная транзакцияДочерняятранзакцияДочерняятранзакцияБаза данных \ / База данныхавиарейсов\ /отелейДве различные (независимые)базы данныхДочерняятранзакцияРаспределеннаябаза данных1У„^Д^® физически разделенные частиодной базы данныхабРис.
5.17. Вложенная транзакция (а), распределенная транзакция (б)Основная проблема распределенных транзакций в том, что для блокировкиданных и подтверждения транзакции необходимы отдельные распределенныеалгоритмы. Распределенную блокировку данных мы рассмотрим ниже. Детальное рассмотрение распределенных протоколов подтверждения транзакции мы отложим до главы 7, в которой рассмотрим отказоустойчивость и механизмы восстановления, к которым относится и протокол подтвержденрш.5.6.3. РеализацияТранзакции кажутся отличной идеей, но как их реализовать? Этот вопрос мысейчас и рассмотрим. Чтобы упростить дело, мы ограничимся транзакциями вфайловой системе. Должно быть понятно, что если каждый процесс, выполняющий транзакцию, просто обновляет файл там же, где файл используется, транзакция не будет атомарной и при прерывании транзакции все изменения не исчезнутволшебным образом.
Понятно, что нужен другой метод. Обычно используются тедва метода, которые описаны ниже.Закрытое рабочее пространствоКонцептуально, когда процесс начинает транзакцию, он получает закрытое рабочее пространство, содержащее все файлы, к которым он хочет получить доступ.Пока транзакция не завершится или не прервется, все операции чтения и записибудут происходить не в файловой системе, а в закрытом рабочем пространстве.Это утверждение прямо приводит нас к первому методу реализации — созданиюдля процесса, в момент начала транзакции, закрытого рабочего пространства.Проблема этой методики состоит в том, что цена копирования всего подрядв закрытое рабочее пространство такова, что равносильна запрету.
Возможна, однако, различная оптимизация. Первый вариант оптимизации основан на том соображении, что если процесс только читает файл, но не изменяет его в создании5.6. Распределенные транзакции313закрытой копии нет необходимости. Он может использовать реальный объект(если только тот не меняется в процессе транзакции). Соответственно, когдапроцесс начинает транзакцию, он должен создать закрытое рабочее пространство,в котором ничего нет, за исключением указателя на рабочее пространство своегородителя.
Если это транзакция верхнего уровня, рабочим пространством родителя будет файловая система. Когда процесс открывает файл на чтение, он следуетза указателямр!, пока файл не обнаружится в рабочем пространстве родителя(или более дальнего предка).Когда файл открывается на запись, он может быть найден таким же образом,как и при чтении, за исключением того, что сначала он будет скопирован в закрытое рабочее пространство. Однако при втором варианте оптимизации удаетсяотказаться и от большей части копирования. Вместо копирования целого файлав закрытое рабочее пространство можно копировать только индекс файла. Индекс — это блок данных, ассоциированных с каждым файлом и хранящий информацию о том, где на диске расположены его блоки. В UNIX индекс — это индексный узел (inode). При использовании внутреннего индекса файл можетбыть считан точно так же, поскольку диск, к которому происходит адресация, —это тот же самый диск с исходным расположением блоков.
Однако когда блокфайла модифицируется, создается копия этого блока, и в индекс вставляется адрес копии, как показано на рис. 5.18, а. После этого блок можно изменять, неоказывая влияния на оригинал. Добавляемые блоки обрабатываются точно также. Новые блоки иногда называют теневыми блоками {shadow blocks).ИндексЗакрытоерабочеепространствоИсходный ^---индексШ 0П П П)Ь^Свободные блокиРис. 5.18. Индекс файла и дисковые блоки для файла из трех блоков (а).
Ситуация после того,как транзакция модифицировала блок О и добавила блок 3 (б).Ситуация после подтверждения транзакции {в)Как молшо видеть на рис. 5.18, б, процесс, выполняющий транзакцию, видитмодифицированный файл, а все остальные процессы продолжают работать с ис-314Глава 5. Синхронизацияходным файлом. В особенно сложных транзакциях закрытое рабочее пространство может содержать не один, а большое количество файлов. Если транзакцияпрерывается, закрытое рабочее пространство просто удаляется и все закрытыеблоки, которые оно содержало, возвращаются в список свободных.
Если транзакция завершается, закрытые блоки в ходе атомарной операции перемещаютсяв рабочее пространство родителя, как показано на рис. 5.18, в. Блоки, которыебольше не нужны, возвращаются в список свободных.Эта схема работает также и для распределенных транзакций. В этом случаеаналогичный процесс начинается на каждой машине, содержащей файлы, к которым в ходе транзакции будет производиться доступ.
Каждый процесс получает свое собственное закрытое рабочее пространство так, как описано выше. Еслитранзакция прерывается, все процессы просто отказываются от своих закрытыхрабочих пространств. С другой стороны, при подтверждении транзакции производятся локальные обновления, после чего транзакции можно считать полностью завершенными.Журнал с упреждающей записьюДругой традиционный метод реализации транзакций — это журнал с упреждающей записью {write-ahead log). Согласно этому методу файлы действительно модифицируются там же, где находятся, но перед тем, как какой-либо блок действительно будет изменен, в журнал заносится запись со сведениями о том, какаятранзакция вносит изменения, какой файл и блок изменяются, каковы прежние иновые значения.
Только после успешной записи в журнал изменения вносятся вфайл.Ниже описано, как работает этот метод. В листинге 5.3 представлена простаятранзакция, которая использует две общие переменные (или другие объекты), хи у, инициализированные нулями.Листинг 5.3. ТранзакцияX = 0:У = 0:BEGINJRANSACTION:X = X + 1:У = У + 2;X = у * у:ENDJRANSACTION;Для каждой из трех инструкций тела транзакции до начала ее выполнениясоздается запись в журнале, которая содержит прежнее и новое значения, разделенные косой чертой:4- содержимое журнала перед выполнением первой инструкции (х=х+1:):[х=0/1]4 содержимое журнала перед выполнением второй инструкции (у=у+2:):[х=0/1][у=0/2]5.6. Распределенные транзакции315> содержимое журнала перед выполнением третьей инструкции (х=у*у;):[х=0/1][у=0/2][х=1/4]Если транзакция успешна, она подтверждается и в журнал добавляется запись о подтверждении, но структуры данных не изменяются, поскольку онии так изменены.