Э. Таненбаум, М. ван Стеен - Распределённые системы (принципы и парадигмы) (1162619), страница 31
Текст из файла (страница 31)
Соответственно, появляется возможность ссылаться на объекты системы при помощи ссылок на заглушки.Дополнительную информацию по объектному программированию в DCE можно найти в [335, 476].2.3.6. Пример 2 — Java RMIв DCE распределенные объекты были добавлены в качестве расширения вызовов удаленных процедур. Вместо того чтобы указывать удаленную процедуру насервере, клиент указывал удаленную процедуру для объекта на сервере.
Отсутствие подобающего механизма ссылок на объекты системы подчеркивало, что мыдействительно имеем дело с простым расширением RFC.Взглянем теперь на распределенные объекты с абсолютно другой точки зрения. В Java распределенные объекты интегрированы с языком. Основная цельэтого — сохранить, насколько это возможно, семантику нераспределенных объектов. Другими словами, создатели языка Java стремились к высокому уровнюпрозрачности распределения. Однако, как мы увидим, создатели Java такжерешили, что в тех случаях, когда высокая степень прозрачности может быть неэффективна, затруднительна или нереализуема, распределенность может бытьявной.Модель распределенных объектов JavaЯзык Java также поддерживает распределенные объекты исключительно в формеудаленных объектов.
Напомним, что удаленный объект — это распределенный2.3. Обращение к удаленным объектам123объект, тело которого постоянно находится на одной и той же машине, а интерфейсы доступны удаленным процессам. Интерфейсы реализованы обычным образом через заместителя, который предоставляет те же интерфейсы, что и удаленный объект. Сам заместитель имеет вид локального объекта, находящегосяв адресном пространстве клиента.Между удаленными и локальными объектами существует лишь несколькоразличий, но различия эти тонки и важны.
Во-первых, значительно различаетсяклонирование локальных и удаленных объектов. Клонирование локального объекта О приводит к появлению нового объекта такого же типа, что и О, в точнотаком же состоянии. Процедура клонирования возвращает точную копию клонированного объекта. Подобная семантика слабо применима к удаленным объектам. Если мы попытаемся создать точную копию удаленного объекта, нам потребуется клонировать не только сам объект на его сервере, но и заместитель накаждом из клиентов, которые в этот момент привязаны к удаленному объекту.Поэтому операция клонирования удаленного объекта производится только насервере. Она приводит к созданию точной копии объекта в адресном пространстве сервера. Заместитель объекта не клонируется. Если клиент на удаленной машине хочет получить доступ к клону объекта на сервере, он должен сначала выполнить повторную привязку к этому объекту.Более существенное различие между локальными и удаленными объектамив Java заключается в семантике блокировки объектов.
Java позволяет построитьлюбой объект в виде монитора. Для этого достаточно объявить один из методовсинхронизируемым {synchronized). Если два процесса одновременно вызовут синхронизируемый метод, работать будет только один из них, в то время как второйокажется заблокированным.
Таким образом, мы можем гарантировать, что доступ к внутренним данным объекта будет осуществляться только последовательно.Как и в мониторе, процесс может быть заблокирован и изнутри объекта в ожидании выполнения некоторого условия, как мы описывали в главе 1.Рассуждая логически, блокировка в удаленных объектах — дело несложное.Предположим, что клиент А вызвал синхронизируемый метод удаленного объекта. Чтобы получить доступ к удаленному объекту, который всегда выглядит также, как локальный, необходимо блокировать А на уровне клиентской заглушки,которая реализует интерфейс объекта и к которой А имеет прямой доступ.
Точнотак же и другой клиент на другой машине должен быть блокирован до пересылкизапроса на сервер. Это означает, что нам необходимо блокировать разных клиентов на различных машинах. Как мы увидим в главе 5, распределенная синхронизация может оказаться довольно сложным делом.Альтернативный подход состоит в том, чтобы производить блокировку только на сервере. В принципе это неплохо работает, но возникают проблемы с нарушениями работы клиентов в момент обработки сервером их обращений. Как мыувидим в главе 7, обработка подобных ситуаций требует достаточно хитроумного протокола и способна значительно снизить общую производительность обращений к удаленным методам.Поэтому разработчики Java RMI ограничили блокировку удаленных объектов блокировкой заместителей [494]. На практике это означает, что просто путем124Глава 2.
Связьиспользования синхронизированных методов удаленные объекты невозможнозащитить от одновременного доступа процессов, работающих через разные заместители. Вместо этого следует использовать явные методы распределеннойблокировки.Обращение к удаленным объектам в JavaПоскольку разница между локальными и удаленными объектами на уровне языка слабо заметна, Java может в ходе обращений к удаленным методам скрыватьбольшую часть различий между ними.
Так, в ходе обращения RMI в качестве параметра может быть передан любой простой или объектный тип, что предполагает возможность маршалинга типов. В терминологии Java это означает, что типысериализуемы (serializable). Хотя в принципе сериализации можно подвергнутьбольшинство объектов, она не всегда является допустимой или возможной.Обычно зависящие от платформы объекты, такие как дескрипторы файлов илисокеты, не сериализуются.Единственное различие между локальными и удаленными объектами, наблюдаемое в процессе RMI, состоит в том, что локальные объекты передаются позначению (включая большие объекты, такие как массивы), в то время как удаленные объекты передаются по ссылке. Другими словами, локальные объекты копируются, после чего копия используется в качестве параметра-значения. В случаеудаленных объектов в качестве параметра используется ссылка на объект, безвсякого копирования, как показано на рис.
2.17.При обращении RMI в Java ссылка на удаленный объект реализуется именнотак, как мы говорили в пункте 2.3.2. Эта ссылка содержит сетевой адрес и конечную точку сервера, а также локальный идентификатор необходимого объектав адресном пространстве сервера.
Как мы обсуждали, в ссылке на удаленный объект, кроме того, кодируется стек протоколов, используемых клиентом и сервером для взаимодействия. Чтобы понять, как при обращении RMI в Java кодируется стек протоколов, необходимо учитывать, что каждый объект Java представляет собой экземпляр класса. Класс же, в свою очередь, содержит реализациюодного или более интерфейсов.В сущности, удаленный объект построен из двух различных классов. Один изклассов содержит реализацию кода сервера и называется классом сервера. Класссервера содержит реализацию той части удаленного объекта, которая выполняется на сервере.
Другими словами, она содержит описание состояния (данных)объекта, а также реализацию методов обработки этого состояния. Из спецификации интерфейса объекта генерируется серверная заглушка, то есть скелетон.Другой класс содержит реализацию кода клиента и называется классом клиента. Класс клиента содержит реализацию заместителя. Как и скелетон, этот класстакже автоматически создается из спецификации интерфейса объекта. В своейпростейшей форме заместитель делает только одну вещь — превращает каждыйвызов метода в сообщение, пересылаемое реализации удаленного объекта, находящейся на сервере, а каждое ответное сообщение — в результат вызова метода.При каждом вызове он устанавливает связь с сервером, разрывая ее после завер-2.3. Обращение к удаленным объектам125шения вызова. Для этого, как уже говорилось, заместитель нуждается в сетевомадресе и конечной точке сервера.Таким образом, заместитель обладает всей информацией, необходимой дляобращения клиента к методу удаленного объекта.
В Java заместители сериализуются. Другими словами, заместитель можно подвергнуть маршалингу и переслать в виде набора байтов другому процессу, в котором он может быть подвергнутобратной операции (демаршалингу) и использован для обращения к методамудаленного объекта. Косвенным результатом этого является тот факт, что заместитель может быть использован в качестве ссылки на удаленный объект.Этот подход согласуется с методами интеграции локальных и распределенных приложений в Java. Напомним, что при обращении RMI локальный объектпередается путем создания копии, а удаленный — через общесистемную ссылкуна объект. Заместитель представляет собой просто-напросто локальный объект.Это означает, что сериализуемый заместитель можно передавать по сети как параметр RMI.
В результате появляется возможность использовать заместитель какссылку на удаленный объект.В принципе nppi маршалинге заместР1теля вся его реализация, то есть его состояние и код, превращаются в последовательность байтов. Маршалинг подобного кода не слишком эффектршен и может привести к слишком объемнымссылкам. Поэтому при маршалинге заместителя в Java на самом деле происходитгенерация дескриптора реализации, точно определяющего, какие классы необходимы для создания заместителя.
Возможно, некоторые из этих классов придетсясперва загрузить из удаленного узла. Дескриптор реализации в качестве частиссылки на удаленный объект заменяет передаваемый при маршалинге код. В результате ссылки на удаленные объекты в Java имеют размер порядка несколькихсотен байт.Такой подход к ссылкам на удаленные объекты отличается высокой гибкостью и представляет собой одну из отличительных особенностей RMI в Java[482]. В частности, это позволяет оптимизировать решение под конкретный объект.
Так, рассмотрим удаленный объект, состояние которого изменяется толькоодин раз. Мы можем превратить этот объект в настоящий распределенный объект путем копирования в процессе привязки всего его состояния на клиентскуюмашину. Каждый раз nppi обращении клиента к методу он работает с локальнойкопией. Чтобы гарантировать согласованность данных, каждое обращение проверяет, не изменилось ли состояние объекта на сервере, и при необходимости обновляет локальную копию.