Протоколы промежуточного уровня 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Протоколы промежуточного уровня



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

 

 

92 Глава 2. Связь

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

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

В качестве другого примера рассмотрим множество протоколов распределен­ного подтверждения (commit) из главы 7. Протоколы подтверждения делают так, чтобы в группе процессов либо все процессы прошли через определенную операцию, либо операция не была применена ни к одному из них. Это явление, известное также как атомарность, широко используется при транзакциях. Как мы увидим, не только транзакции, но и другие приложения, особенно рассчитан­ные на устойчивость к сбоям, также могут нуждаться в протоколах распределен­ного подтверждения.

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

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

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

 

 

2.2. Удаленный вызов процедур 93

Такой подход к подразделению на уровни приводит нас к слегка измененной эталонной модели взаимодействия (рис. 2.5). По сравнению с моделью OSI сеан­совый уровень и уровень представления заменены одним промежуточным уров­нем, который содержит не зависящие от приложений протоколы. Как мы гово­рили, эти протоколы нельзя поместить на более низкие уровни. Истинные транспортные службы также могут быть представлены в виде служб промежу­точного уровня. Для этого не потребуется даже модификации. Этот подход ана­логичен переносу UDP на транспортный уровень. Точно так же службы проме­жуточного уровня могут включать в себя службы пересылки сообщений, схожие с теми, которые предоставляются на транспортном уровне.

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

Удаленный вызов процедур

Основой множества распределенных систем является явный обмен сообщениями между процессами. Однако процедуры send и receive не скрывают взаимодейст­вия, что необходимо для обеспечения прозрачности доступа. Эта проблема была известна давно, но по ней мало что было сделано до появления в 1980 году статьи [62], в которой предлагался абсолютно новый способ взаимодействия. Хотя идея была совершенно простой (естественно, после того как кто-то все придумал), ее реализация часто оказывается весьма хитроумной. В этом разделе мы рассмот­рим саму концепцию, ее реализацию, сильные и слабые стороны.

Если не вдаваться в подробности, в упомянутой статье было предложено по­зволить программам вызывать процедуры, находящиеся на других машинах. Когда процесс, запущенный на машине А, вызывает процедуру с машины В, вызываю-

 

94 Глава 2. Связь

щий процесс на машине А приостанавливается, а выполнение вызванной проце­дуры происходит на машине В. Информация может быть передана от вызываю­щего процесса к вызываемой процедуре через параметры и возвращена процессу в виде результата выполнения процедуры. Программист абсолютно ничего не за­метит. Этот метод известен под названием удаленный вызов процедур (Remote Procedure Call, RPC).

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

Базовые операции RPC

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

Общепринятые вызовы процедур

Для того чтобы понять, как работает RPC, важно сначала разобраться, как осуще­ствляются общепринятые (в пределах одной машины) вызовы процедур. Рас­смотрим вызов в языке типа С:

count = read(fd, buf, bytes);

Здесь fd — целое, указывающее на файл; buf — массив символов, в который будут считываться данные; bytes — другое целое, говорящее, сколько байт следует считать. Если вызов производится из главной программы, стек до вызова выгля­дит так, как показано на рис. 2.6, а. Делая вызов, вызывающая программа поме­щает параметры в стек в порядке «последний первым», как показано на рис. 2.6, б. Причина, по которой компилятор С помещает параметры в стек в обратном по­рядке, заключается в функциях типа printf. Чтобы выполняться, функция printf всегда должна знать, где искать свой первый аргумент — строку формата. После завершения read система помещает возвращаемое значение в регистр, удаляет адрес возврата и возвращает управление назад, в вызвавшую программу. Затем вызвавшая программа удаляет из стека параметры, приводя его в исходное со­стояние.

Следует особо отметить некоторые моменты. Во-первых, в С параметры мо­гут передаваться как по значению, так и по ссылке. Параметр-значение, такой как fd или bytes, просто копируется в стек, что и показано на рис. 2.6, б. Для вы­зываемой процедуры параметр-значение представляет собой просто инициали­зированную локальную переменную. Вызываемая процедура может ее изменить,

 

 

 
 

 

2.2. Удаленный вызов процедур 95

 


но все эти изменения не могут повлиять на ее оригинальное значение на вызы­вающей стороне.

Параметр-ссылка в С — это указатель на переменную (то есть адрес перемен­ной), а не ее значение. В вызове read второй параметр является параметром-ссылкой, поскольку массивы в С всегда передаются через ссылку. В стек на са­мом деле будет помещен адрес символьного массива. Если вызванная процедура использует этот параметр для помещения чего-либо в символьный массив, это приведет к изменению массива в вызывающей программе. Мы увидим, что разница между параметрами-значениями и параметрами-ссылками крайне важ­на для RPC.

Существует еще один механизм передачи параметров, не применяющийся в С. Он называется вызов через копирование/восстановление {call-by-copy/restore). В этом случае до вызова вызывающей программой производится копирование переменной в стек, как при вызове по значению, а после завершения вызова — копирование этой переменной из стека назад, с удалением исходного значения этой переменной. В большинстве случаев это дает тот же эффект, что и при вы­зове по ссылке. Однако иногда, например, если один и тот же параметр присут­ствует в списке аргументов многократно, их семантика различается. Во многих языках вызов через копирование/восстановление отсутствует.

Решение об использовании того или иного механизма передачи параметров принимается обычно разработчиками языка и является его фиксированным свой­ством. Раньше это решение зависело от типов передаваемых данных. В С, напри­мер, как мы видели, целые и другие скалярные типы всегда передаются по значе­нию, а массивы — по ссылке. Некоторые компиляторы языка Ада поддерживают вызов через копирование/восстановление для изменяемых {in out) параметров, передавая остальные по ссылке. Определение языка позволяет выбрать любой вариант, который хоть немного упрощает семантику.

 

96 Глава 2. Связь

Заглушки для клиента и сервера

Идея, стоящая за RPC, состоит в том, чтобы удаленный вызов процедур выглядел точно так же, как и локальный. Другими словами, мы ждем от RPC прозрачно­сти — вызывающая процедура не должна уведомляться о том, что вызываемая процедура выполняется на другой машине, и наоборот. Предположим, программа хочет считать некоторые данные из файла. Для чтения из файла необходимых данных программист помещает в код вызов read. В традиционной (однопроцес­сорной) системе процедура read извлекается компоновщиком из библиотеки и вставляется в объектный код программы. Это короткая процедура, которая обыч­но реализуется путем системного вызова read. Другими словами, процедура read — это интерфейс между кодом пользователя и локальной операционной сис­темой.

Даже если read — это системный вызов, он производится аналогичным обра­зом, путем помещения параметров в стек, как показано на рис. 2.6, б. Таким обра­зом, программист так и не узнает, что read делает что-то хитрое.

RPC организует свою прозрачность аналогичным образом. Если read являет­ся удаленной процедурой (то есть будет исполняться на машине файлового сер­вера), в библиотеку помещается специальная версия read, называемая клиент­ской заглушкой {client stub). Как и оригинальная функция, она также вызывается в соответствии с последовательностью, показанной на рис 2.6, б. Как и оригинал, она также производит вызов локальной операционной системы, только в от­личие от оригинальной функции клиентская заглушка ие запрашивает данные у операционной системы. Вместо этого она упаковывает параметры в сообщение и путем вызова процедуры send требует переслать это сообщение на сервер, как показано на рис. 2.7. После вызова процедуры send клиентская заглушка вызыва­ет процедуру recei ve, блокируясь до получения ответа.

Когда сообщение приходит на сервер, операционная система сервера передает его серверной заглушке {server stub). Серверная заглушка эквивалентна клиент­ской, но работает на стороне сервера. Это фрагмент кода, который преобразует приходящие по сети запросы в вызовы локальных процедур. Обычно серверная заглушка запускает процедуру recei ve и блокируется, ожидая входящих сообще­ний. После получения сообщения серверная заглушка распаковывает его, извле­кая параметры, и традиционным способом (то есть так, как показано на рис. 2.6)

 

2.2. Удаленный вызов процедур 97

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

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

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

В блаженстве неведения, царящем на стороне клиента, и состоит прелесть та­кой схемы. Как мы видели, доступ к удаленным службам осуществляется по­средством вызова обычных (то есть локальных) процедур, без всяких там send и receive. Все детали пересылки сообщений скрыты в двух библиотечных проце­дурах, так же как в традиционных библиотеках скрыты детали реально произво­димых системных вызовов.

Подведем итоги. При удаленном вызове процедур происходят следующие действия.

1. Процедура клиента обычным образом вызывает клиентскую заглушку.

2. Клиентская заглушка создает сообщение и вызывает локальную операцион­
ную систему.

3. Операционная система клиента пересылает сообщение удаленной операцион­
ной системе.

4. Удаленная операционная система передает сообщение серверной заглушке.

5. Серверная заглушка извлекает из сообщения параметры и вызывает сервер.

6. Сервер выполняет вызов и возвращает результаты заглушке.

7. Серверная заглушка запаковывает результаты в сообщение и вызывает свою
локальную операционную систему.

8. Операционная система сервера пересылает сообщение операционной системе
клиента.

 

98 Глава 2. Связь

9. Операционная система клиента принимает сообщение и передает его клиент­ской заглушке.

10. Заглушка извлекает результаты из сообщения и передает их клиенту.

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

Передача параметров

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



Поделиться:


Последнее изменение этой страницы: 2016-09-19; просмотров: 301; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.129.19.251 (0.039 с.)