Недавно автору статьи довелось использовать язык WSDL (Web Services Description Language, Язык описания Web-сервисов) для нескольких существующих Web-сервисов - на одном клиенте работал сервер и клиентская реализация. У этого клиента и специалистов по обслуживание сервера уже сложились тесные рабочие отношения, но наступил момент, когда возникла необходимость в еще одной клиентской реализации, которую должна была выполнить группа разработчиков, находящихся в противоположенной точке земного шара. В связи с этим потребовалась четкая спецификация, описывающая такие сервисы, а именно для этого и предназначен WSDL. Поэтому автор вознамерился основательно изучить то, что ранее не было достаточно освещено. В результате, он приобрел ценный опыт - ему удалось вспомнить старую и добрую практику проектирования программного обеспечения и обнаружить ряд проблем, характерных для Web-сервисов, WSDL и XML Schema.
В самом начале, на этапе проектирования, было допущено несколько ошибок, которые изначально трудно заметить. Вероятно, эти недочеты не были бы допущены, если бы проектировщики дали формальное определение для своих сервисов на WSDL. Так что, вот основная мысль этих двух статей: пишите WSDL заранее, не генерируйте его потом, как это часто советуют поставщики.
При всем внимании, которым были одарены Web-сервисы, часто сложно отделить желаемое от действительного. В предлагаемом цикле статей акцент будет сделан на реальном, а не на потенциальном. В них читатель не найдет краткого обзора WSDL, кроме того предполагается, что он знаком с W3C XML Schema. В первой статье рассказывается, чем могут быть полезны при проектировании Web-сервисов практика проектирования программного обеспечения и опыт в области распределенной обработки данных. В ней рассматриваются некоторые решения, которые должен принимать проектировщик Web-сервисов, приводятся необходимые советы и рекомендации. В остальных статьях будет описан процесс проектирования: во второй статье будут перечислены некоторые "темные стороны" спецификации WSDL 1.1. В нее не войдут определения типов данных - темы третьей статьи, в которой будет представлена W3C XML Schema с позиции того, кто использует ее для определения данных, передаваемых через интерфейсы Web-сервисов.
Проектирование Web-сервисов
Употребляемый автором термин Web-сервисов относится исключительно к тому виду технологии, которая состредоточена на взаимодействии (interoperability). Это означает, что эта технология стандартизирована: гетерогенные системы работают только при наличии отрытых стандартов. В этом случае уместен вопрос: будут ли Web-сервисы решением вашей проблемы? Сегодня одного слова Web-сервисы уже недостаточно, чтобы говорить о солидности компании, их использующей, поэтому будет лучше, если имеются иные веские основания для их использования. Если вы контролируете оба конца канала, не исключено, что существуют более подходящие технологии. Сейчас - только заря эры открытых стандартов распределенной обработки данных. Поэтому цена поддержки Web-сервисов на этом еще несформировавшемся рынке остается высокой - это и снижение производительности, и увеличение затрат на разработку, и ухудшение защищенности.
Тезис о том, что Web-сервисы являются "дружественными по отношению к брандмауэру" ("firewall friendly"), обманчив. Действительно, обычные брандмауэры оберегают корпоративные ценности от "злоумышленников", которые используют слабые места в прикладном программном обеспечении, появившиеся в результате открытия портов, на которых исполняются защищённые сервисы. С другой стороны, Web-сервисы через этих порты "выставляют" прикладное программное обеспечение. Другими словами, они ослабляют безопасность, предоставляя посторонним лицам доступ к приложениям - именно то, чему сетевой брандмауэр должен был бы воспрепятствовать. Поэтому необходимо новое поколение брандмауэров. На рынке уже появилось несколько новых игроков, предлагающих такие продукты. Поставщики обычных брандмауэров также начинают обращать внимание на эту проблему. Но это только начало, и такая технология должна еще оправдать себя.
Даже если предполагается применять Web-сервисы, необходимо помнить, что необязательно использовать SOAP. Например, автор статьи видел формы, передаваемые как аргумент запроса на удаленный вызов процедуры SOAP (SOAP-RPC). Ему также попадались формы, которые возвращались как часть ответа удаленного вызова процедуры SOAP. Он так и не смог найти дополнительную пользу от применения SOAP. Разве не был бы проще обыкновенный XML или HTML через HTTP?
Недопустимость генерации WSDL
Ответим на вопрос: предназначен ли WSDL 1.1 для восприятия человеком. Типичный совет - генерировать WSDL, а не писать вручную. Автор по этому вопросу придерживается следующего мнения. Возможно, это и верно, если таким образом разрабатывается простой, демонстрационный сервис, но данный подход обречен на провал, когда он применяется к крупным системам. Даже программист, работающий самостоятельно, быстро утратит общее представление о проблеме; ситуация усложняется если разработку совместно ведут различные, территориально разнесенные группы специалистов. Большие распределенные системы требуют проектирования; ожидание того, что после объединения они будут совместно работать, приведет к катастрофе.
Если распределенные компоненты могут разрабатываться на различных языках программирования, то для того, чтобы указать, как должны быть задействованы сервисы, необходим Язык описания интерфейсов (Interface Definition Language, IDL), нейтральный по отношению к языку программирования. У CORBA (Общая архитектура посредника запросов к объектам, Common Object Request Broker Architecture), как и у DCOM (Распределенная модель компонентных объектов, Distributed Component Object Model), такой язык есть. IDL - это контракт между инициатором на обслуживание и поставщиком, но он только собирает синтаксис. Семантика остается неосвещенной: IDL оставляет открытым вопрос о том, что делает сервис.
WSDL - это IDL Web-сервисов. Он описывает, как вызывать Web-сервисы. Он также определяет ответы, которые могут быть получены как при успешном вызове, так и нет. Спецификация WSDL жестко регламентирует формат сообщений, используемые протоколы и адрес, по которому находятся сервисы. К сожалению, даже четкое и строгое описании на WSDL не гарантирует высокое качество проектирования. Подобно всем языкам IDL, WSDL силен в синтаксисе и слаб в семантике. Однако, не стоит им пренебрегать - в конечном счете важна именно семантика, синтаксис же используется просто, чтобы ее раскрывать.
Проектирование интерфейсов
Прежде чем приступить к написанию WSDL, необходимо оговорить с заказчиками то, что Web-сервис должен делать. Следует записать случаи использования, четко определив, как этот сервис взаимодействует со своей средой. Предположим, что программа-агент (actor) с какой-либо целью вызывает Web-сервис. В этом случае, нужно создать не только сценарий "солнечного дня", который реализует поставленную задачу, но сценарий "дождливого дня", когда результат отрицательный. Какие гарантии может предложить система, что цель успешно достигнута? А когда нет? Где находится граница ответственности клиентской части и сервера?
Трудно переоценить важность четкого определения требований. На этом этапа стоит задуматься о цели проекта. В чем конкретно она заключается? Какие данные необходимо получать от клиента, и что должен поставлять сервер? Совершение ошибки на этом шаге чревато большими затратами.
Например, рассмотрим Web-сервис, который в качестве параметров принимает список установленных программ и величину свободного места на диске. Затем этот сервис должен вернуть список приложений, подлежащих обновлению. В случае если места достаточно, проблем не возникает. Однако, как быть, если его недостаточно? Как выбрать продукты, для которых необходимо установить новые версии? Предполагается ли, что клиент сам удаляет старые редакции программ, чтобы освободить место для новых? Это непростые вопросы, для решения которых потребуется разрабатывать сложные алгоритмы, при реализация которых не исключены ошибки. Разумеется, ни одну систему не следует определять подобным образом. Сервер должен предоставлять список приложений, зависимости между ними и требования, которые они предъявляют к ресурсам. Решение же о том, какой пакет установить, является задачей клиента. Поэтому поручив серверу это задание, клиент ничего не выиграет, он только повысит затраты на разработку серверной части.
Таким образом, необходимо проводить анализ затрат на начальном этапе. При этом можно проигнорировать технические детали - сервис можно рассматривать как черный ящик. Но нельзя пренебрегать деталями, касающимися взаимодействия между этим сервисом и его средой.
Следующий шаг - проанализировать, как можно реализовать случаи использования. Будет ли единственный интерфейс (portType в WSDL версии 1.1), обеспечивающий всю функциональность? Или несколько интерфейсов? Каждый интерфейс может быть предложен в нескольких конечных точках, но, как правило, он должен быть неделимым. То есть конечная точка должна предоставлять либо всю функциональность, либо ничего. Аналогично, интерфейс должен быть семантически последовательным. Сказанное носит рекомендательный характер и опирается на здравый смысл, хотя ничто в спецификации WSDL не препятствует иной интерпретации.
Требуются ли какие-нибудь поддерживающие интерфейсы? Как и когда они должны вызываться? Какова природа этой зависимости? Пока нет стандартов, а только рекомендации о том, как обращаться с "хореографией сервисов" (service choreographies), как разрешать сервисам выполнять гиперссылки к другим сервисам. Другими словами, это неисследованная проблемная область.
Возвращает ли разрабатываемый сервис результат клиенту? Должен ли клиент располагать информацией о том, что сервис успешно отработал? Должен ли клиент вызывать сервис синхронно? Или асинхронно? Или же сервис будет поддерживать оба типа вызова?
Непрозрачность сети
Сеть не является прозрачной - вызов локального сервиса и его удаленный вызов существенно отличаются друг от друга. В качестве "памятки разработчику" можно порекомендовать тезисы Питера Дойча (Peter Deutsh) "Восемь заблуждений о распределенной обработке данных" (eight fallacies of distributed computing).
Неверная семантика различна для сетевого окружения и локальной реализации: при неудачном вызове не всегда известно, исполнился сервис или нет.
WSDL 1.1 описывает следующие виды вызовов: односторонний (one-way), запрос-ответ (request-response), ответ на требование (solicit-response) и уведомление (notification). Однако, связывания WSDL поддерживают только односторонний вызов и вызов вида запрос-ответ. Также следует понимать, что реально, а что - нет. Другими словами, сегодня невозможно реализовать ситуацию, когда клиент ожидает с сервера асинхронное получение практического, "промышленного качества" и согласованного со стандартами результата. Это следует расценивать как досадное обстоятельство, поскольку это именно тот механизм, который является наиболее гибким в ситуации частичного сбоя.
WSDL позволяет перемешивать и согласовывать виды вызова и транспорт (transport). На этом этапе важно прибегнуть к здравому смыслу. Первое требование - а это не всегда очевидно - необходимо четко представить, как стек протоколов предлагаемого Web-сервиса будет себя вести. В качестве примера рассмотрим, что случится если асинхронно вызвать Web-сервис поверх механизма синхронного транспорта. Предположим, что SOAP-сообщение пересылается в одну сторону по HTTP: бизнес логика на клиенте формирует SOAP сообщение, чтобы вызвать удаленный сервис. В результате запрос HTTP посылается на сервер. Когда сервер получает запрос, он должен немедленно возвратить ответ HTTP, не обслуживая этот запрос. Бизнес логика на сервере должна отрабатывать после того, как этот ответ был возвращен. Этот ответ не должен содержать SOAP-сообщение. Ответ HTTP с кодом состояния 200 или 202 не означает, что сервис успешно отработал. Код сбоя, с другой стороны, должен гарантировать, что вызов сервиса не исполнился. Слой SOAP на клиенте не формирует новых сообщений до тех пор, пока он не получит ответ, или пока не истечет время ожидания.
Таким образом, односторонний вызов не "устраняет" задержки или неисправности в сети. Самое большее - он помогает избежать задержки с бизнес логикой на сервере. Автор употребил "самое большее", подразумевая, что эту функциональность стоит протестировать на инструментальной цепочке сервера, прежде чем полагаться на нее -корректная реализация является нетривиальной задачей для любого поставщика.
Используя HTTP в в качестве транспортного протокола, клиент может быть уверен, что его запрос был доставлен. Стоит заметить, однако, что если клиент не получил ответ, это не значит, что сервер не получил и не обработал корректно этот запрос. Например, сеть может "упасть" во время отправки ответа. Другими словами, реализовать вызов просто, правильно завершенный вызов - нет.
Отличие Web-сервисов от распределенных объектов
Объекты характеризуются состоянием. Следует избегать состояния, поскольку оно связывает ресурсы и ослабляет масштабируемость. Слабосвязанная архитектура разрешает отдельным компонентам изменяться, не разрушая систему. Весьма вероятно, что в будущем потребуется расширять Web-сервис. Как же при этом сохранить обратную совместимость?
Несмотря на то, что достоинство удаленного вызова процедуры (RPC) в легкости реализации, он не очень хорошо уживается со слабой связанностью: необходимо передавать фиксированный список параметров при каждом вызове Web-сервиса. Эту проблему можно в некоторой степени сделать менее острой, разрешив некоторым параметрам "не иметь значения". Оставим без рассмотрения возникающие в этом случае проблемы, связанные с обеспечением возможности взаимодействия, - более фундаментальное ограничение заключается в том, что этот прием позволяет исключать параметры, а не добавлять их. Вызовы в стиле документа проявляют себя лучше, когда части документа могут быть определены как необязательные. Они также могут быть спроектированы для расширяемости.
Определение ограниченных интерфейсов
Следует внимательно изучить то, что предлагается: и на уровне данных, и на уровне кодирования данных. Необходимо помнить, что придется продолжить поддерживать поставляемый интерфейс. Чем ограниченнее интерфейс, тем легче его реализация. WSDL же спроектирован для гибкости.. Из-за этой гибкости легко ошибиться в спецификации Web-сервисов и оставить многие опции реализации неохваченными . Следует избегать этого - клиенты и серверы должны уметь обрабатывать все сообщения, которые допустимы по контракту.
Типичная ошибка, совершаемая при реализации серверных систем, - установление соединения с базой данных при каждом запросе к этой базе. Автор совершил такую ошибку - выяснилось, что установление соединения с базой данных занимает больше времени, чем все остальное, вместе взятое. Чтобы минимизировать это падение производительности, можно прибегнуть к одному из двух приемов: воспользоваться пулом соединений (connection pool) или хранимой процедурой.
При использовании Web-сервисов стоимость установки соединения также высока. Опять-таки дополнительные затраты на вызов могут быть уменьшены повторным использованием существующего соединения. С другой стороны, необходимо учитывать, что поддержание открытого соединения требует ресурсов. Однако, важно помнить, что расходы, связанные с вызовами Web-сервиса, гораздо более высокие по сравнению с вызовом локальной функции и, следовательно, их следует реже использовать.
Здесь уместно провести аналогию с хранимыми процедурами. Вместо отправки данных и обработки их на клиенте, только чтобы выяснить, что требуются еще данные, хранимые процедуры оперируют с данными в адресном пространстве базы данных. Применение хранимых процедур в приложениях баз данных является спорным моментом - по крайней мере, по двум причинам. Во-первых, язык написания хранимых процедур не стандартизирован, и поэтому их использование ведет к зависимости от поставщика БД. Во-вторых, бизнес логика должна находиться в отдельном слое, а не в базе данных.
Тем не менее, хранимые процедуры решают реальную проблему, и их недостатки должны быть соотнесены с достоинствами в каждом отдельном случае. Аналогично, в области Web-сервисов, клиенту предоставляется контроль над логикой за счет множества мелко структурных вызовов. Крупно структурные сервисы более напоминают хранимые процедуры. Они не только улучшат производительность, но и упросят процесс реализации, внедрения и управления всей системой.
Итак, практическая рекомендация - проектировать Web-сервисы под ограниченные, но крупно структурные интерфейсы. Ограниченность позволяет показывать как можно меньше, крупность структуры - выполнять как можно больше для одного вызова.
Разнесение бизнес логики и политики
Не следует реализовывать аутентификацию и авторизацию в бизнес логике. Безопасность транспортного уровня может быть как удовлетворительной, так и нет. В разделе Ресурсы приведены ссылки на статьи, в которых рассматривается этот вопрос. Даже если безопасность транспортного уровня и не урезается, все равно пока нет стандартов - они только разрабатываются, и из них стоит отметить создаваемые Техническим комитетом OASIS "Защищенность Web-сервисов" (OASIS Web Services Security Technical Committee). Предлагаемые подходы действительно способствуют разделению бизнес логики и политики (policy): заголовки SOAP вставляются в сервис, чтобы обеспечить характеристики безовасности, а информативная часть сообщения сохраняется для бизнес логики.
Но как же без ложки дегтя - предлагаемый стандарт применим только к Web-сервисам, использующим SOAP. Еще одна неприятность - отсутствие стандартизированного способа указать Качество защиты (Quality of Protection, QoP) сервиса в документе WSDL. Microsoft, BEA, SAP и IBM опубликовали спецификацию для "Приложений политики Web-сервисов" (Web Services Policy Attachments), в которой рассматривается этот вопрос. Насколько известно автору, этот документ еще не был передан ни в один орган стандартизации.
Разделение проектирования и реализации
В идеале при проектировании Web-сервисов следует оставить вопросы реализации в стороне. Суть проектирования -посмотреть на систему на высоком уровне абстракции, не обращая внимания на проблемы реализации. Однако, можно выбрать такой, казалось бы подходящий по всем параметрам дизайн проекта, который окажется бесполезным, если инструментальные цепочки, которые предполагается использовать, не поддерживают конструкции в разработанном WSDL. Автор настойчиво рекомендует создание макета по техническим спецификациям для проверки реальности осуществления проекта. Пока этот момент еще не проработан.
Благодарности
Автор выражает глубокую благодарность Марку Портайеру (Mark Portier) и Кэролайн Гринмен (Caroline Greenman) за их конструктивные замечания.
Ресурсы
"Мыльная опера" на тему защищенность Web-сервисов будет продолжаться еще долго. Ниже приведено "содержание первых серий":
- В цикле статей "Защищенность Web-сервисов" (Web Services Security) Билала Сиддикуи (Bilal Siddiqui) описывается "дырка", которую создали основанные на SOAP Web-сервисы;
- В своей статье "Web-сервисам необходим брандмауэр" (XML Web services need a firewall) Керри Чемпион (Kerry Champion) выступает за использование брандмауэров XML;
- В статье "Брандмауэры XML" (XML Firewalls) Престона Гралла (Preston Gralla) содержится упоминание о некоторых текущих коммерческих реализациях;
- Спецификация "Ценные качества Web-сервисов" (Web Services Goodness (WS-Goodness)) разрешает все известные проблемы защищенности.
В статье "IDL, которого нет" (The IDL That Isn't) Мартина Гуджина (Martin Gudgin) и Тимоти Иуолда (Timothy Ewald) приводится более глубокий анализ WSDL с позиций IDL.
В белой бумаге "Кто пишет контракты Ваших Web-сервисов" (Who Writes Your Web Service Contracts?) корпорации Karniak рассказывается о том, как точное описание упрощает процесс разработки Web-сервиса.