Tuesday, April 27, 2010

Transparent remoting is a fable

Transparent remoting is the use of the Proxy pattern to create remote proxies, that conforms to the same interface of a remote object but instead of executing its methods locally it marshals (serializes) the parameters, send it over the network, get the marshalled result and returns it to the client code.
The idea behind this pattern's implementations is using a remote object, discovered with some kind of infrastructure service, as it were in the same address space of the current process. The most famous implementation is probably Java Remote Method Invocation (RMI).

This is nice!
However, the famous paper A Note on Distributed Computing outlines the inherent issues of treating remote and local objects with the same interface and contract:
  • latency: obviously, it takes more time (some orders of magnitude) to perform remote calls in relation to local calls.
  • memory access: it is performed via pointers and handlers on local machines, while it is more complex in remote invocations. More or less solved in Java RMI via stubs and skeletons.
  • partial failure: remote objects can suffer different failures which are not included in the original interface. For instance, they can raise RemoteExceptions which you must deal with a try/catch block. Or they can let you wait a method's return value forever (actually until a timeout is reached.)
  • concurrency: calls from different nodes can happen at the same time, and there is no single point for managing shared resources like a common operating system.
The first two are problems we can live with, while the third and the fourth have no conceptual solution. In sum, remote proxies are a leaky abstraction, and it is difficult not to notice that an object is remote.

Isn't trasparency over the network a simplification?
It is more an old myth, and often too much of a simplification. Single-machine deployment for web applications exist, and they can be transformed into multiple-machine ones. How do they tackle the problem?
These infrastructures do the job backwards. They assume a service like a database is going to be remote, and if it is local, well nothing changes, you can just stick a localhost or in the configuration. Sockets are used for communication between Unix components from the 1970s, and they are not a leaky abstraction. Even RMI forces you to throw RemoteExceptions from a local object (and this is the first failure of transparent remoting).

Isn't RMI useful?
Of course, in the correct use cases RMI can be handy. For example if you are in a LAN, and are in an hurry to separate an application server from your web servers, you will certainly use RMI to access beans on the former. As long as it is not used transparently, it is a great technology.

So should we stop doing remoting with objects?
No. Even JavaScript nowadays does remoting in Ajax applications, but it has a different model, which is asynchronous. Of course some Java infrastrucure is by nature asynchronous, Java frameworks are introducing an asynchronous model for calling remote objects (R-OSGi).
IRemoteService remoteService = (IRemoteService) reference.getProperty(REMOTE);
// This futureExec returns immediately
IFuture future = RemoteServiceHelper.futureExec(remoteService, "hello", new Object[] { CONSUMER_NAME });
// ...do other computation here...
// This method blocks until a return 
System.out.println("Called future.get() successfully");
You can wrap future.get() in a separate thread and continue with your life. This is almost like doing an Ajax call: your browser does not freeze while the request is being completed. Asynchronous method calls are an interesting innovation (not really an innovation since they are older than dirt) over transparent invocations, and open up new models for distributed computing.


Avi Block said...

Don't forget remoting with objects is necessary also for remote APIs. Two good examples are SOAP and XMLRPC. This is especially important if you already have a public facing API in code, and you don't want to reengineer that to be a RESTful API.
As for the leaky abstraction, you can't "plug up" the leak somewhat by rethrowing a service level exception.
Something like:

try {
catch(SoapFault f) {
throw new MyServiceException(f);

Giorgio said...

Although I prefer REST, I have no problems with SOAP classes as they are clearly not a transparent implementation (you never encapsulate stuff in Xml to access local objects.)