Многие из этих технологий, такие как Java RMI, Thrift или Protocol Buffers, являются двоичными по своей природе, в то время как в SOAP для форматов сообщений используется язык XML. Некоторые реализации привязаны к конкретному сетевому протоколу (например, SOAP, который номинально использует HTTP), в то время как другие могут допускать использование различных типов сетевых протоколов, которые сами по себе могут обеспечить дополнительные возможности. Например, TCP предоставляет гарантии доставки, а UDP их не дает, но имеет намного меньше издержек. Это может позволить применять различные сетевые технологии для различных вариантов использования.
Те RPC-реализации, которые позволяют создавать клиентские и серверные заглушки, содействуют весьма быстрому старту. Я могу в два счета отправлять контекст через сетевую границу. Зачастую это служит одним из основных аргументов в пользу RPC — эта технология проста в использовании. Тот факт, что я могу просто сделать обычный вызов метода и теоретически проигнорировать все остальное, является существенным подспорьем.
Но некоторые RPC-реализации не лишены недостатков, которые могут вызвать проблемы. Изначально эти проблемы могут быть не столь очевидными, но тем не менее могут оказаться довольно серьезными, чтобы это перевесило преимущества от простоты получения реализации и ее быстрой работы.
Некоторые RPC-механизмы, такие как Java RMI, сильно привязаны к конкретной платформе, что может ограничить выбор технологий для применения на клиенте и сервере. У Thrift и Protocol Buffers имеется впечатляющий диапазон поддержки альтернативных языков, что может некоторым образом сгладить данный недостаток, но при этом следует иметь в виду, что у некоторых RPC-технологий существуют ограничения по возможностям взаимодействия.
В известном смысле эта технологическая связанность может быть одной из форм обнажения деталей внутренней технической реализации. Например, при использовании RMI осуществляется привязка к JVM не только клиента, но и сервера.
Основной замысел RPC заключается в скрытии сложности удаленного вызова. Но многие реализации RPC скрывают их слишком сильно. Управление в некоторых разновидностях RPC с целью сделать удаленный вызов метода похожим на локальный вызов скрывает тот факт, что эти два вызова очень не похожи друг на друга. Можно сделать огромное количество локальных вызовов в рамках одного и того же процесса, практически не переживая о потере производительности. Но при использовании RPC затраты на маршализацию и обратный ей процесс могут быть весьма существенными, даже если не обращать внимания на пересылку по сети. Это означает, что конструкцию удаленного API нужно продумывать иначе, чем конструкцию локальных интерфейсов. Нельзя просто взять локальный API и попытаться без дополнительных размышлений сделать из него границу сервиса, поскольку, скорее всего, ничего, кроме проблем, вы не получите. Если абстракция слишком непрозрачна, то в самых худших примерах разработчики могут использовать удаленные вызовы, даже не зная об этом.
Нужно подумать и о самой сети. Когда речь идет о распределенном вычислении, самым распространенным первым заблуждением является уверенность в надежности сети. Сети не могут быть абсолютно надежными. Они могут и будут отказывать, даже если речь идет о вполне благополучных клиентах и серверах. Они могут сбоить часто или редко, а могут и вовсе портить ваши пакеты. Всегда нужно предполагать, что сети могут подвергнуться воздействию недоброжелателей, готовых в любой момент излить на вас свою злость. Поэтому можно ожидать всяческих отказов. Сбой может быть вызван тем, что удаленный сервер возвратил ошибку, или тем, что вы составили неверный вызов. Можете вы отличить одно от другого, и если да, то можете ли что-то с этим сделать? А что делать, когда удаленный сервер просто начинает медленно реагировать на ваши вызовы? К этой теме мы еще вернемся, когда в главе 11 будем рассматривать эластичность системы.
Некоторые из наиболее популярных реализаций RPC могут стать причиной опасных форм хрупкости, и хорошим примером этого может послужить Java RMI. Рассмотрим весьма простой Java-интерфейс, который мы решили сделать удаленным API для нашего сервиса клиентов. В примере 4.1 объявляются методы, которые мы собираемся удаленно представить на всеобщее обозрение. Затем Java RMI сгенерирует клиентскую и серверную заглушки для нашего метода.