Understanding RPC: Principles, Implementation Details, and Code Walkthrough
This article explains the fundamentals of Remote Procedure Call (RPC), covering its definition, core challenges, service registration and discovery with Zookeeper, client proxy generation, network transmission using Netty, serialization and compression, server-side request handling via reflection or Javassist, and performance comparisons between proxy strategies.
RPC Definition
Remote Procedure Call (RPC) enables invoking remote methods as if they were local, providing a simple abstraction for distributed systems.
Core Problems of RPC
To achieve this, an RPC framework must solve four key issues: service discovery, data serialization, network transmission, and method invocation on the server side.
Service Registration and Discovery
The implementation uses Zookeeper as a registration center. Services register their nodes as persistent paths, while each instance creates an ephemeral node for its address.
public void exportService(Service serviceResource) {
String name = serviceResource.getName();
String uri = GSON.toJson(serviceResource);
String servicePath = "rpc/" + name + "/service";
if (!zkClient.exists(servicePath)) {
zkClient.createPersistent(servicePath, true);
}
String uriPath = servicePath + "/" + uri;
if (zkClient.exists(uriPath)) {
zkClient.delete(uriPath);
}
zkClient.createEphemeral(uriPath);
}A Zookeeper child listener clears the local cache when service nodes change.
public void handleChildChange(String parentPath, List
childList) throws Exception {
String[] arr = parentPath.split("/");
SERVER_MAP.remove(arr[2]);
}Client Proxy Generation
The client creates dynamic proxies for remote interfaces, builds request objects, and sends them over the network.
public
T getProxy(Class
clazz, String group, String version, boolean async) {
if (async) {
return (T) asyncObjectCache.computeIfAbsent(clazz.getName() + group + version,
clz -> Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz},
new ClientInvocationHandler(clazz, group, version, async)));
} else {
return (T) objectCache.computeIfAbsent(clazz.getName() + group + version,
clz -> Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz},
new ClientInvocationHandler(clazz, group, version, async)));
}
}The ClientInvocationHandler obtains service nodes, selects one, constructs an RpcRequest , serializes and compresses it, and sends it via Netty.
Network Transmission, Serialization, and Compression
Requests are marshalled to byte arrays using a selected protocol (e.g., Protobuf, Kryo) and then compressed with Gzip before being transmitted over TCP.
public interface MessageProtocol {
byte[] marshallingRequest(RpcRequest request) throws Exception;
RpcRequest unmarshallingRequest(byte[] data) throws Exception;
byte[] marshallingResponse(RpcResponse response) throws Exception;
RpcResponse unmarshallingResponse(byte[] data) throws Exception;
}Server-Side Request Handling
On the server, the request is decompressed, deserialized, and the target method is invoked either via Java reflection or a Javassist‑generated proxy.
public RpcResponse invoke(ServiceObject serviceObject, RpcRequest request) throws Exception {
Method method = serviceObject.getClazz().getMethod(request.getMethod(), request.getParametersTypes());
Object value = method.invoke(serviceObject.getObj(), request.getParameters());
RpcResponse response = new RpcResponse(RpcStatusEnum.SUCCESS);
response.setReturnValue(value);
return response;
}When using Javassist, the proxy implements InvokeProxy and delegates the call to the generated invoke method.
Performance Comparison
Benchmarks on a MacBook Pro M1 show that reflection and Javassist proxy modes have similar latency, with Javassist being marginally faster in some cases.
Conclusion
The article provides a comprehensive walkthrough of building a simple RPC framework in Java, covering service registration, client proxy creation, network communication, serialization, compression, and server-side method invocation, along with practical code examples.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.