Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the Java remote procedure call method

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article introduces the knowledge of "what is the method of Java remote procedure call". Many people will encounter this dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Question:

1) to build a new service, you inevitably need to rely on other people's services, but now that other people's services are on the remote end, how to invoke them?

2) if other teams want to use our new service, how should our service be released for others to invoke?

These two issues will be discussed below.

Public interface HelloWorldService {String sayHello (String msg);} public class HelloWorldServiceImpl implements HelloWorldService {@ Override public String sayHello (String msg) {String result = "hello world" + msg; System.out.println (result); return result;}} public class Test {public static void main (String [] args) {HelloWorldService helloWorldService = new HelloWorldServiceImpl (); helloWorldService.sayHello ("test") }} 1 how do I invoke someone else's remote service?

Because each service is deployed on different machines, the invocation between services can not avoid the process of network communication. Service consumers have to write a piece of code related to network communication for each service call, which is not only complex but also error-prone.

If there is a way for us to invoke remote services like local services, without the caller being aware of the details of network communication, it will greatly increase productivity. For example, when service consumers perform helloWorldService.sayHello ("test"), they are essentially invoking remote services. This method is actually RPC (Remote Procedure Call Protocol), which is widely used in major Internet companies, such as Alibaba's hsf, dubbo (open source), Facebook's thrift (open source), Google grpc (open source), Twitter's finagle (open source) and so on.

To make the network communication details transparent to users, we need to encapsulate the communication details. Let's first look at the communication details involved in the next RPC call:

The service consumer (client) call invokes the service in a local invocation

After receiving the call, client stub is responsible for assembling methods, parameters, etc., into a message body that can be transmitted over the network.

Client stub finds the service address and sends the message to the server

Server stub decodes the message after receiving it.

Server stub calls the local service based on the decoding result

The local service executes and returns the result to server stub

Server stub packages the returned result into a message and sends it to the consumer

Client stub receives the message and decodes it

The service consumer gets the final result.

The goal of RPC is to encapsulate these steps so that users are not aware of these details.

1.1 how to achieve imperceptible remote service invocation?

How to encapsulate the communication details so that the user can invoke the remote service like a local invocation? For java, it means using proxies! There are two ways for java agents:

Jdk dynamic agent

Bytecode generation

Although the proxy implemented by bytecode generation is more powerful and efficient, it is not easy to maintain the code, and most companies still choose dynamic proxy when implementing RPC framework.

The following is a brief introduction to how dynamic agents implement our requirements. We need to implement the RPCProxyClient proxy class. The invoke method of the proxy class encapsulates the details of communicating with the remote service. The consumer first obtains the service provider's interface from RPCProxyClient, and the invoke method is called when the helloWorldService.sayHello ("test") method is executed.

Public class RPCProxyClient implements java.lang.reflect.InvocationHandler {private Object obj; public RPCProxyClient (Object obj) {this.obj=obj;} / * get the proxied object; * / public static Object getProxy (Object obj) {return java.lang.reflect.Proxy.newProxyInstance (obj.getClass (). GetClassLoader (), obj.getClass (). GetInterfaces (), new RPCProxyClient (obj)) } / * call this method to execute * / public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {/ / result parameter; Object result = new Object (); / /. Execute communication-related logic / /. Return result;}} public class Test {public static void main (String [] args) {HelloWorldService helloWorldService = (HelloWorldService) RPCProxyClient.getProxy (HelloWorldService.class); helloWorldService.sayHello ("test");}} 1.2 how do I encode and decode messages?

1.2.1 determine the message data structure

The last section talked about the need to encapsulate communication details in invoke, and the first step in communication is to determine the message structure in which the client and server communicate with each other. The request message structure of the client generally needs to include the following:

1) Interface name

In our example, the interface name is "HelloWorldService". If you don't pass it, the server won't know which interface to call.

2) method name

There may be many methods in an interface, and if the method name is not passed, the server will not know which method to call

3) Parameter type & parameter value

There are many parameter types, such as bool, int, long, double, string, map, list, and even struct (class)

And the corresponding parameter values

4) timeout

5) requestID, which identifies the unique request id. The usefulness of requestID is described in detail in the following section.

Similarly, the message structure returned by the server generally includes the following.

1) return value

2) status code

3) requestID

1.2.2 Serialization

Once you have determined the data structure of the message, the next step is to consider serialization and deserialization. What is serialization? Serialization is the process of converting data structures or objects into binary strings, that is, the process of coding. What is deserialization? The process of converting a binary string generated during serialization into a data structure or object. Why do you need serialization? Only when converted to a binary string can it be transmitted over the network. Why do you need deserialization? Convert the binary to an object for subsequent processing!

Nowadays, there are more and more serialization solutions, and each serialization scheme has its advantages and disadvantages. They have their own unique application scenarios at the beginning of their design, so which one should they choose? From the point of view of RPC, there are three main points:

1) generality, such as whether it can support complex data structures such as Map.

2) performance, including time complexity and space complexity, as the RPC framework will be used by almost all the services of the company, if you can save a little time on serialization, the benefit to the whole company will be considerable. Similarly, if you can save a little memory on serialization, you can also save a lot of network bandwidth.

3) scalability, for Internet companies, the business changes rapidly. If the serialization protocol has good scalability and supports the automatic addition of new business fields without affecting the old services, it will greatly provide the flexibility of the system.

At present, Internet companies widely use Protobuf, Thrift, Avro and other mature serialization solutions to build RPC framework, these are time-tested solutions.

1.3 Communication

After the message data structure is serialized into a binary string, the next step is to communicate on the network. There are two commonly used IO communication models:

1) BIO

2) NIO

General RPC framework needs to support these two IO models, the principle can be referred to: a story to tell a clear NIO. How to implement RPC's IO communication framework?

1) self-developed using the java nio method, which is more complex and likely to have hidden bug, but I have also seen some Internet companies use this method.

2) based on mina,mina, it was very popular in the early years, but the update of the version was slow in these years.

3) based on netty, many RPC frameworks are directly based on netty, the IO communication framework, which saves effort and worry, such as Alibaba's HSF, dubbo,Twitter 's finagle and so on.

1.4 Why is there a requestID in the message?

If netty is used, the channel.writeAndFlush () method is generally used to send the message binary string. After this method is called, it is asynchronous for the entire remote call (from sending the request to receiving the result), that is, for the current thread, after the request is sent, the thread can execute backwards. As for the result of the server, it is after the server has finished processing. And then sent to the client in the form of a message. So here are two problems:

1) how to make the current thread "pause", wait for the result to come back, and then execute backwards?

2) if multiple threads make remote method calls at the same time, there will be a lot of messages sent by both parties on the socket connection established between client server, and the sequence may be random. After server processes the result, it sends the result message to client,client to receive a lot of messages. How do you know which message was originally called by which thread?

As shown in the following figure, thread An and thread B simultaneously send requests to client socket requestA and requestB,socket send requestB and requestA to server, while server may return responseA first, although the requestA request arrives later. We need a mechanism to ensure that responseA is thrown to ThreadA,responseB and thrown to ThreadB.

How to solve it?

1) each time the client thread calls the remote interface through socket, it generates a unique ID, namely requestID (requestID must be unique in a Socket connection). Generally, AtomicLong is often used to accumulate numbers from 0 to generate a unique ID.

2) store the callback object callback of the processing result in the global ConcurrentHashMap put (requestID, callback)

3) when the thread calls channel.writeAndFlush () to send the message, it then executes the get () method of callback to try to get the result returned remotely. Inside get (), synchronized is used to acquire the lock of the callback object callback, and then check whether the result has been obtained, and if not, then call the wait () method of callback to release the lock on the callback, leaving the current thread in a waiting state.

4) after receiving the request and processing it, the server sends the response result (including the previous requestID) to the client. The thread on the client socket connection that listens to the message receives the message, analyzes the result, takes it to the requestID, and then get (requestID) from the previous ConcurrentHashMap to find the callback object, then use synchronized to obtain the lock on the callback, and set the method call result to the callback object. Then call callback.notifyAll () to wake up the previously waiting thread.

Public Object get () {synchronized (this) {/ / while (! isDone) {/ / whether there is a result wait (); / / No result is to release the lock, leaving the current thread in a waiting state} private void setDone (Response res) {this.res = res; isDone = true Synchronized (this) {/ / acquires the lock because the previous wait () has released callback's lock notifyAll (); / / Wake up the waiting thread}} 2 how to publish your own service?

How to let others use our service? Some students said it was very simple, just tell the user the IP and port of the service. Indeed, the crux of the problem here is whether to inform automatically or by human flesh.

Human flesh method: if you find that one machine for your service is not enough and you need to add another one, you should tell the caller that I now have two ip, and you need to poll the call to achieve load balancer. The caller grits his teeth and changes, and one day a machine dies, and the caller finds that half of the service is unavailable, and he can only manually modify the code to delete the ip that hung up that machine. Of course, human flesh will not be used in the real production environment.

Is there a way to automatically inform, that is, the addition and elimination of the machine is transparent to the caller, and the caller no longer needs to write down the address of the service provider? Of course, nowadays zookeeper is widely used to realize automatic registration and discovery of services!

To put it simply, zookeeper can act as a service registry (Service Registry), which enables multiple service providers to form a cluster and allows service consumers to obtain specific service access addresses (ip+ ports) through the service registry to access specific service providers. As shown in the following figure:

Specifically, zookeeper is a distributed file system. Every time a service provider is deployed, it registers its service to a certain path of zookeeper: / {service} / {version} / {ip:port}, for example, our HelloWorldService is deployed to two machines. Then two directories will be created on zookeeper: / HelloWorldService/1.0.0/100.19.20.01:16888 / HelloWorldService/1.0.0/100.19.20.02:16888.

Zookeeper provides a "heartbeat detection" function, which periodically sends a request to each service provider (in fact, a Socket persistent connection is established). If there is no response for a long time, the service center thinks that the service provider has "hung up" and removed it, such as 100.19.20.02 if the machine is down. Then the path on zookeeper will be / HelloWorldService/1.0.0/100.19.20.01:16888.

The service consumer will listen on the corresponding path (/ HelloWorldService/1.0.0). Once the data on the path changes (increase or decrease), the zookeeper will notify the service consumer that the service provider address list has changed and update it.

More importantly, zookeeper's inherent fault tolerance (such as leader election) can ensure the high availability of the service registry.

This is the end of the content of "what is the Java remote procedure call method". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report