Technology stack use includes:springboot,Zookeeper,netty,java spi
RPC Definition
Remote Procedure Call (RPC) is a communication mechanism that allows different services to communicate and interact with each other over the network.
Through RPC, a service can make a request to another service and obtain a response, just like a local call, without the developer having to manually handle the underlying network communication details.The RPC framework encapsulates the underlying network transport and provides functionality such as the definition of remote service interfaces, serialisation and deserialisation of data.
rpc vs. http discrimination:
HTTP is an application layer protocol used to transmit hypertext, which communicates between a client and a server. It is based on the request-response model, where the client sends an HTTP request to the server and the server processes the request and returns the corresponding HTTP response. rpc is more akin to an architectural idea, and rpc can be implemented with HTTP and implemented with TCP.
RPC process
A simple RPC architecture is shown in the diagram:
How to achieve:
A simple RPC call link:
server-side implementation based on netty and ZK
According to the diagram above, first we need to implement service registration.
Service registration:
Most current RPC frameworks support annotations for registration, and the same approach is used here.
This annotation will define the service version, the group (to distinguish between different interfaces with the same name and the same project), and the project name for service exposure.
Similarly, an annotation is needed for consumption; an annotation defining the packages to be scanned
Registering services at startup
First, the annotation with @provider needs to be registered
Get the package to be scanned and then register the annotated bean into spring
To register a service, you should at least include: the service provider (ip), the service name, and the variables in @RpcProvider``, so you can start by defining aRpcServiceConfig.
@Data @NoArgsConstructor @AllArgsConstructor @Builder publicclassRpcServiceConfig { /** * service version */ privateStringversion="";
/** * target service */ private Object service;
/** * belong to which project */ privateStringproject="";
/** * group */ privateStringgroup="";
/** * generate service name,use to distinguish different service,and * can be split to get the service name * @return */ public String fetchRpcServiceName() { returnthis.getProject() + "*" + this.getGroup() + "*" + this.getServiceName() + "*" + this.getVersion(); }
/** * get the interface name * * @return */ public String getServiceName() { returnthis.service.getClass().getInterfaces()[0].getCanonicalName(); }
}
Provides 2 methods to register a service and get the corresponding bean based on the service name
1 2 3 4 5 6 7 8 9 10 11 12 13 14
publicinterfaceRpcServiceRegistryAdapter {
/** * @param rpcServiceConfig rpc service related attributes */ voidregistryService(RpcServiceConfig rpcServiceConfig);
/** * @param rpcClassName rpc class name * @return service object */ Object getService(String rpcClassName);
}
The registration process can be divided into 3 steps, generate the address -> service registration into Zookeeper -> registration into the cache. Here a ConcurrentHashMap is used to cache the service (the api of zookeeper is called at the end of the method for registration, which is skipped because it is not very relevant to RPC, so you can directly refer to the source code).
@Override publicvoidregistryService(RpcServiceConfig rpcServiceConfig) { try { // first get address and service StringhostAddress= InetAddress.getLocalHost().getHostAddress(); // add service to zk LogUtil.info("add service to zk,service name{},host:{}", rpcServiceConfig.fetchRpcServiceName(),hostAddress); registerServiceToZk(rpcServiceConfig.fetchRpcServiceName(), newInetSocketAddress(hostAddress, PropertiesFileUtil.readPortFromProperties())); // add service to map cache registerServiceToMap(rpcServiceConfig); } catch (UnknownHostException e) { LogUtil.error("occur exception when getHostAddress", e); thrownewRuntimeException(e); }
}
@Override public Object getService(String rpcServiceName) { Objectservice= serviceMap.get(rpcServiceName); if (null == service) { thrownewRpcException(RpcErrorMessageEnum.SERVICE_CAN_NOT_BE_FOUND.getCode(),"service not found"); } return service; }