Читаем Создание микросервисов полностью

Но некоторые 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 сгенерирует клиентскую и серверную заглушки для нашего метода.

Пример4.1. Определение конечной точки сервиса с помощью Java RMI

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface CustomerRemote extends Remote {

  public Customer findCustomer(String id) throws RemoteException;

  public Customer createCustomer(String firstname, String surname, String emailAddress)

   throws RemoteException;

}

В данном интерфейсе findCustomer получает имя, фамилию и адрес электронной почты. А что произойдет, если будет принято решение разрешить объекту Customer также быть созданным лишь с адресом электронной почты? В данном случае мы без особого труда можем добавить следующий новый метод:

...

public Customer createCustomer(String emailAddress) throws RemoteException;

...

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

Но есть еще одна разновидность хрупкости. Посмотрим, на что похож наш объект Customer:

public class Customer implements Serializable {

private String firstName;

private String surname;

Перейти на страницу:

Похожие книги