Accidentally implemented RPC

Accidentally implemented RPC
Preface
Accidentally implemented RPC

With the increasing number of people paying attention to the cim project recently, the number of questions and bugs raised has also increased, and it is inevitable that the code cleanliness will come up again in the process of fixing the problems.

Looking at what I wrote a year or two ago, I always suspect that it really came from my own hands? In some places, I couldn't help it and started a long road to reconstruction.

Before and after comparison
, I will briefly introduce the cim project before starting. The following is its architecture diagram:

Accidentally implemented RPC

Simply put, it is an IM instant messaging system, mainly composed of the following parts:

  • IM-server is naturally the server, used to maintain a long connection with the client.

  • The IM-client client can be simply regarded as a client tool similar to QQ; of course, the functions are certainly not so rich, and only provide some simple message sending and receiving functions.

  • Route routing service, mainly used for client authentication, message forwarding, etc.; provides some http interfaces, which can be used to view the system status, online number and other functions.

Of course, both the server and routing can be expanded horizontally.

Accidentally implemented RPC

This is a flow chart of message sending. Assume that two servers A and B and a routing service are now deployed; among them, ClientA and ClientB maintain long connections with servers A and B, respectively.

When ClientA sends a hello world to ClientB, the entire message flow is shown in the figure:

  1. First send the message to the Route service via http.

  2. The routing service knows that ClientB is connected to ServerB; then it sends the message to ServerB via http.

  3. Finally, ServerB pushes the message through the long connection channel with ClientB, and the message is sent successfully.

Here I intercepted the code for ClientA to initiate a request to Route:

Accidentally implemented RPC

You can see that this is the use of okhttp to initiate an http request. Although this function can be implemented, it is not elegant.

For example: suppose we need to connect to Alipay's interface, sending an http request here is naturally no problem; but for Alipay internal departments to directly call each other's interface, then the original http request should not be used anymore.

The service provider should provide an api package, and service consumers only need to rely on this package to implement interface calls.

Of course, http or a custom private protocol can be used in the end.

It is also similar to when we use Dubbo or SpringCloud, we usually directly rely on an api package, so that we can call remote services like calling a local method, and completely shield the underlying details, whether it is using http or other private protocols. It doesn't matter, it doesn't matter to the caller at all.

Does that have an internal taste? Isn't this the official explanation of RPC?

Corresponding to this is the same reason, Client, Route, Server are essentially a system, and their mutual interface calls should also be RPC.

So my refactoring became like this:

Accidentally implemented RPC

Is the code a lot more concise, just like calling a local method, and this also has several advantages:

  • The underlying details are completely shielded, and the business can be better realized and the code maintained.

  • Even if the service provider modifies the parameters, it can be quickly discovered during compilation, and the call is completely unaware as before, so it also increases the risk.

Now
let’s talk about how it is implemented.

In fact, as mentioned in the "Practical Application of Dynamic Agents" above, the principle is similar.

If you want to be unaware of the caller, you have to create an interface proxy object; the process of encoding, calling, and decoding is implemented in this proxy object.

Accidentally implemented RPC

Corresponding to here is actually to create a routeApi proxy object, the key is this code:


RouteApi
 routeApi 
=

new

ProxyManager
<>(
RouteApi
.
class
,
 routeUrl
,
 okHttpClient
).
getInstance
();

The complete source code is as follows:
Accidentally implemented RPC

The getInstance() function returns the interface object that needs to be proxied; and the ProxyInvocation is a class that implements the InvocationHandler interface. This set of codes is a three-pronged approach to using JDK to implement dynamic proxy.

Accidentally implemented RPC

Looking at the source code of ProxyInvocation, you will find that when we call any method of the proxy interface, the invoke() method here will be executed.

The invoke() method naturally implements the process of encoding, remote calling, and decoding mentioned in the above figure; I believe it is easy for everyone to understand, because it is not the focus of this discussion, I will not introduce it too much.

Summary
In fact, understanding these makes it easy to understand the core source code of RPC frameworks such as Dubbo. The overall idea is similar, except that the private protocol is used, so the codec will be different.

So if you want to implement an RPC framework by yourself, you may wish to refer to this idea and try it. When you run an RPC helloworld with your own code, the feeling is that you have integrated a third-party framework such as Dubbo and SpringCloud with yourself. Totally different.

All source code of this article:

https://github.com/crossoverJie/cim

Guess you like

Origin blog.51cto.com/15049794/2562746
RPC
RPC