Э. Таненбаум, М. ван Стеен - Распределённые системы (принципы и парадигмы) (1162619), страница 80
Текст из файла (страница 80)
Первая из них содержала полныесведения о товарах на момент открытия утром текущего дня, а вторая — список5.6. Распределенные транзакции307изменений за день: продукты, купленные покупателями, и продукты, возвращенные поставщикам. Компьютер считывал информацию с обеих лент и создавалновую основную ленту инвентаризации, как показано на рис. 5.16.ПредыдущаяинвентаризацияНоваяинвентаризацияИсходные Jленты)^ ^^Н^I/"^NКомпьютер [—•(^ )Лента с результатомСегодняшниеизмененияРис. 5.16. Внесение изменений в основную ленту защищено от сбоевОсновное преимущество этой схемы (несмотря на то, что люди, вынужденные этим заниматься, тогда часто не могли этого оценить) состояло в том, чтопри любых сбоях все ленты можно было перемотать на начало и начать работуснова без каких-либо проблем. Такие примитивные старые магнитные ленты обладали свойством, характерным для транзакции, — «все или ничего».Взглянем теперь на современное банковское приложение, которое вносит изменения в сетевую базу данных.
Клиент звонит в банк, используя компьютерс модемом, намереваясь снять деньги с одного счета и положить их на другой.Операция осуществляется в два приема.1. Снять сумму а со счета 1.2. Положить сумму а на счет 2.В том случае, если модемное соединение после выполнения первого этапа, нодо выполнения второго разорвется, деньги с первого счета будут сняты, но навторой не перечислены. Деньги просто растворятся в воздухе.Проблему решает объединение этих операций в одну транзакцию. Либо обеони будут выполнены, либо не будет выполнена ни одна.
Ключевой, следовательно, является возможность отката к исходному состоянию при невозможности завершить транзакцию. Что нам действительно нужно — так это способ «отмотать к началу» базу данных, как мы это проделывали с магнитной лентой. Этувозможность дает нам транзакция.Программирование с использованием транзакций требует специальных примитивов, которые могут поддерживаться как базовой распределенной системой,так и исполняющей системой языка программирования. Типичные примеры приводятся в табл. 5.2. Полный список примитивов зависит от того, какие объектыиспользуются в транзакции. В почтовой системе примитивами могут быть отправление, прием и пересылка почты.
В банковских системах примитивы могутбыть совершенно другими. Однако, как правило, там присутствуют команды READи WRITE. Обычные инструкции, вызовы процедур и пр. также могут включатьсявнутрь транзакций.308Глава 5. СинхронизацияТ а б л и ц а 5 . 2 . Некоторые п р и м и т и в ы , используемые в транзакцияхПримитивОписаниеBEGINTRANSACTIONПометить начало транзакцииENDTRANSACTIONПрекратить транзакцию и попытаться завершить ееABORT_TRANSACTIONПрервать транзакцию и восстановить прежние значенияREADСчитать данные из файла, таблицы или другого источникаWRITEЗаписать данные в файл, таблицу или другой приемникДля ограничения области действия транзакции используются примитивыBEGIN_TRANSACTION и END_TRANSACTION. Операции, расположенные между ними, формируют тело транзакции.
Все эти операции либо выполняются, либо не выполняются. Это могут быть системные вызовы, библиотечные процедуры или инструкции на языке реализации.Рассмотрим в качестве примера процесс резервирования посадочных мест отБелых равнин, штат Нью-Йорк, до Малинди, Кения, в авиационной системе резервирования мест.
Один из возможных маршрутов: из Белых равнин в аэропортим. Джона Кеннеди, из аэропорта им. Джона Кеннеди в Найроби, из Найробив Малинди. На листинге 5.1 мы видим, что резервирование билетов на эти трирейса выполняется тремя различными операциями.Листинг 5 . 1 . Подтверждение транзакции резервирования билетовна три авиарейсаBEGIN_TRANSACTIONзарезервировать WP -> JFK:зарезервировать JFK -> Nairobi:зарезервировать Nairobi -> Malindi;END_TRANSACTIONТеперь представим, что билеты на первые два рейса зарезервированы, а третий, если судить по документам, оказался переполнен.
Транзакция прерывается,и результаты первых двух резервирований отменяются — база данных по билетам на авиарейсы возвращается к тем значениям, которые были в ней до началатранзакции (листинг 5.2). Все выглядит так, будто нршего не происходило.Листинг 5 . 2 . Транзакция прервана по причине невозможности заказа билетана третий самолетBEGIN_TRANSACTIONзарезервировать WP -> JFK;зарезервировать JFK -> Nairobi;Nairobi -> Malindi переполнен =>ABORTJRANSACTIONСвойство транзакций «все или ничего» — это лишь одно из характерныхсвойств транзакции. Говоря более конкретно, транзакции:> атомарны {atomic) — для окружающего мира транзакция неделима;4 непротиворечивы {consistent) — транзакция не нарушает инвариантов системы;5.6. Распределенные транзакции3094 изолированы (isolated) — одновременно происходящие транзакции не влияют друг на друга;"¥ долговечны {durable) — после завершения транзакции внесенные ею изменения становятся постоянными.На эти свойства часто ссылаются по их первым буквам — ACID.Первое ключевое свойство, которое проявляется во всех транзакциях, — атомарность.
Это свойство гарантирует, что всякая транзакция либо полностью выполняется, либо полностью не выполняется, причем если она выполняется, товыполняется как одна неделимая одновременная операция. Пока транзакция находится в процессе выполнения, другие процессы (независимо от того, вовлечены они сами в транзакцию или нет) не могут наблюдать каких-либо промежуточных состояний.Представим, например, что транзакция начинается для того, чтобы добавитьданные в некий файл с начальной длиной 10 байт. Если этот файл в ходе транзакции пожелает прочитать другой процесс, он увидит только исходные 10 байтнезависимо от того, сколько байт было добавлено в файл в ходе транзакции. Если транзакция завершится успешно, файл мгновенно вырастет до нового размера, размера на момент завершения без промежуточных состояний независимо оттого, сколько операций внутри транзакции привело к его увеличению.Второе свойство, о котором мы говорим, это непротиворечивость. Это значит,что если у системы до начала транзакции имелись некие инварианты, которыеона постоянно должна хранить, они будут сохраняться и после ее завершения.Так, например, в банковской системе ключевым инвариантом является закон сохранения денег.
После любых внутренних переводов количество денег в банкедолжно сохраняться таким же, каким оно было до перевода, хотя на краткий момент в ходе транзакции этот инвариант и может нарушаться, но такое нарушениене будет заметно извне.Третье свойство, о котором мы говорили, — это изолированность, или сериализуемость. В том случае, если две или более транзакций происходят одновременно, для каждой из них и для других процессов итоговый результат выглядиттак же, как если бы все транзакции выполнялись последовательно в некотором(зависящем от системы) порядке. Ниже мы еще вернемся к этому свойству.Четвертое свойство гласит, что транзакции долговечны. Это свойство отражаеттот факт, что после завершения транзакций последующие действия не имеют никакого значения, транзакция закончена, ее результаты неизменны.
Никакие сбоипосле завершения транзакции не могут привести к отмене результатов транзакции или их потере. Долговечность подробно обсуждается в главе 7.5.6.2. Классификация транзакцийИтак, мы считаем транзакцией серию операций, удовлетворяющую свойствамACID. Этот тип транзакции именуется также плоской транзакцией {flat transaction).
Плоские транзакции — это наиболее простой и наиболее часто используемый тип транзакций. Однако плоские транзакции имеют множество ограниче-310Глава 5. СинхронизацияНИИ, которые вынуждают нас заняться поисками альтернативных моделей. Нижемы обсудим два важных класса транзакций — вложенные транзакции и распределенные транзакции. Другие классы широко рассмотрены в [177].Ограничения плоских транзакцийОсновное ограничение плоских транзакций состоит в том, что они не могут давать частичного результата в случае завершения или прерывания. Другими словами, сила атомарности плоских транзакций является в то же время и их слабостью.Рассмотрим снова полет из Нью-Йорка в Кению, проиллюстрированный листингами 5.1 и 5.2.
Предположим, что билеты на всю поездку продавались в видеотносительно дешевого единого пакета, в результате чего три операции были собраны в единую транзакцию. Обнаружив невозможность заказать билеты толькона третью часть пути, мы могли бы согласиться на резервирование только первых двух билетов. Однако при этом можем обнаружить, что зарезервировать билет на самолет из аэропорта Кеннеди в Найроби уже невозможно. Прерываниевсей транзакции означает, что нам придется предпринять вторую попытку зарезервировать билеты на самолет, которая также может закончиться неудачей. Таким образом, в данном случае нам бы хотелось частично завершить нашу транзакцию.
Плоская транзакция не позволит нам этого сделать.В качестве другого примера рассмотрим web-сайт, гиперссылка в которомдвунаправленная. Другими словами, если web-страница W\ содержит URL страницы W2J ТО Wi знает, что W2 ссылается на нее [224]. Теперь представим себе, чтостраница W перенесена в другое место или заменена другой страницей. В этомслучае все гиперссылки на W должны быть обновлены, причем желательно одной атомарной операцией, в противном случае мы можем получить (временно)потерянные ссылки на W.
Теоретически здесь можно использовать плоскуютранзакцию. Транзакция состоит из внесения изменений в W и серии операций, каждая из которых изменяет одну web-страницу, содержащую гиперссылкуПроблема, однако, состоит в том, что такая транзакция может потребоватьдля выполнения нескольких часов. Страницы, ссылающиеся на W, могут бытьразбросаны по всему Интернету, а таких страниц, нуждающихся в правке, можетбыть тысячи. Производить правку отдельными транзакциями не слишком хорошо,потому что в этом случае некоторые web-страницы будут содержать правильныессылки, а некоторые нет. Возможным решением в этом случае было бы завершение изменений с сохранением старой ссылки на 1^ для тех страниц, ссылки накоторые еще не изменились.Вложенные транзакцииНекоторые из тех ограничений, о которых мы говорили выше, могут быть снятыпри использовании вложенных транзакций (nested transactions).
Транзакцияверхнего уровня может разделяться на дочерние транзакции, работающие параллельно, на различных машинах, для повышения производительности или упрощения программирования. Каждая из этих дочерних транзакций также может со-5.6. Распределенные транзакции311стоять из одной или более транзакций или, в свою очередь, делиться на дочерниетранзакции.Вложенные транзакции поднимают перед нами небольшую, но важную проблему. Представьте себе, что транзакция запускает несколько параллельныхдочерних транзакций, и одна из них завершается, делая результат видимым дляродительской транзакции. В ходе дальнейших вычислений родительская транзакция прерывается, возвращая систему в то состояние, в котором она была дозапуска транзакции верхнего уровня.