Многораздельные транзакции
Вообще говоря, между фрагментами многораздельных транзакций могут иметься произвольные зависимости по данным. Например, транзакции может потребоваться прочитать некоторое значение, сохраняемое в разделе P1, чтобы изменить некоторое другое значение в разделе P2.
Чтобы обеспечить сериализуемый порядок выполнения многораздельных транзакций без возможности возникновения синхронизационных тупиков, они направляются в систему через центральный координатор, который определяет им глобальный порядок. Достоинством этого подхода является его простота, но понятно, что наличие центрального координатора ограничивает число одновременно выполняемых многораздельных транзакций. Чтобы обеспечить возможность одновременного выполнения большего числа транзакций, необходимо использовать несколько координаторов. В прошлые годы изучались методы глобального упорядочения транзакций с применением нескольких координаторов, например, на основе использования слабо синхронизированных часов [2]. Мы оставляем выбор лучшего варианта на будущие исследования, и в этой работе оцениваем систему с одним координатором.
Центральный координатор разбивает транзакцию на фрагменты и посылает их в разделы. После получения ответов координатор выполняет код приложения, чтобы определить, как следует продолжать выполнение транзакции, для чего может потребоваться посылка дополнительных фрагментов. В каждом разделе фрагменты данной транзакции выполняются последовательно.
Многораздельные транзакции выполняются с использованием буфера отката, а для принятия решения об успешности завершения транзакций применяется двухфазный протокол фиксации (two-phase commit, 2PC). Это позволяет системе сохранять работоспособность при выходе из строя отдельных разделов. Если при выполнении транзакции один из разделов выходит из строя, или если сеть теряет связность, то другие участники транзакции могут откатиться и продолжить выполнение транзакций, не зависящих от отказавшего раздела. При отсутствии информации, требуемой для отката, системе пришлось бы заблокироваться до восстановления работоспособности отказавшего раздела.
Координатор присоединяет сообщение "подготовиться" ("prepare") протокола 2PC к последнему фрагменту транзакции. Когда процесс основного раздела получает заключительный фрагмент, он отсылает все фрагменты транзакции процессам резервных разделов и ожидает их подтверждения до отправки окончательных результатов координатору. Это эквивалентно принуждению участника 2PC к выталкиванию на диск своего решения о фиксации транзакции. Наконец, когда у координатора имеются все решения участников, он завершает транзакию, посылая сообщение "фиксация" ("commit") процессам разделов и возвращая окончательный результат приложению.
При выполнении многораздельных транзакций при ожидании данных от процессов других разделов в процессе основного раздела могут возникнуть сетевые задержки. Этот простой может стать фактором, ограничивающим производительность, даже если многораздельные транзакции составляют лишь малую долю рабочей нагрузки. В нашей экспериментальной системе, описываемой в разд. 5, минимальное время на передачу и подтверждение приема (измеряемое с использованием ping) между двумя машинами в сети, подключенными к одному и тому же коммутатору гигабитного Ethernet, составляет примерно 40 миллисекунд. Среднее процессорное время выполнения транзакции TPC-C в нашей системе – 26 миллисекунд. Таким образом, за время ожидания сетевого подтверждения процесс раздела смог бы выполнить почти две однораздельных транзакции. Что обеспечить системе возможность выполнения полезной работы в то время, которое иначе было бы временем простоя, требуется некоторая разновидность управления параллелизмом. Проблема состоит в том, чтобы это не привело к снижению эффективности простых однораздельных транзакций. В следующем разделе описываются две схемы управления параллелизмом, которые мы разработали для преодоления этой проблемы.