java simple implementation of RPC framework

A, RPC Introduction

RPC, called the Remote Procedure Call, Remote Procedure Call that is, it is a computer communications protocol. It allows local services like calling the same remote service call. It can have different implementations. Such as RMI (Remote Method Invocation), Hessian, Http invoker and so on. In addition, RPC is language-independent.

    RPC schematic

As shown above, it is assumed the sayHi Computer1 call () method, for purposes of call Computer1 the sayHi () method of the same method as local calls, call -> return. Subsequent calls can be seen but the call is sayHi Computer2 Computer1 in () method, the RPC shields the underlying implementation details, let the caller without paying attention to the communication network, data transmission and other details.

Second, implement an RPC framework

    The above describes the core principles of RPC: RPC enables local applications simple and efficient server process (service) calls. It is mainly used in distributed systems. The IPC component in Hadoop. But how to achieve a RPC framework it?

Reflections from the following aspects, for reference:

1. Communication Model: A to B machines and machine model assumes that communication with a communication between A and B, typically in the Java-based or BIO NIO ;.

2. Process (service) Location: using a given communication mode, and determines the IP and port and method for determining the name of the specific process or method;

3. Remote proxy object: Method (service) is actually a local proxy remote method, and therefore may require a remote proxy object for Java, the Java remote proxy object can be used to achieve dynamic object that encapsulates the call to a remote method invocation of the local transfer;

4. The sequence of the object name, method name, parameters required for network transmission target information is converted into binary transmission, there may need different technical solutions serialization. Such as: protobuf, Arvo and so on.

Three, Java RPC framework to achieve

1, the technical solution

     Comparative implement an RPC frame following the original program, using Socket communication, dynamic proxies sequence reflective native and Java.

2, RPC framework architecture

RPC architecture is divided into three parts:

1) service provider, run on the server to provide services and service implementation class interface definition.

2) service center, running on the server side is responsible for local services publish to a remote service, remote management services, services provided to consumers.

3) consumer service, running on the client, call the remote service through the remote proxy object.

3, the specific implementation

The service provider defines and implements the interface code is as follows:

1

2

3

4

5

public interface HelloService {

 

    String sayHi(String name);

 

}

HelloServices interface categories:

1

2

3

4

5

6

7

public class HelloServiceImpl implements HelloService {

 

    public String sayHi(String name) {

        return "Hi, " + name;

    }

 

}

Service code implementation, the code is as follows:

1

2

3

4

5

6

7

8

9

10

11

public interface Server {

    public void stop();

 

    public void start() throws IOException;

 

    public void register(Class serviceInterface, Class impl);

 

    public boolean isRunning();

 

    public int getPort();

}

Service implementation class:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

public class ServiceCenter implements Server {

    private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

 

    private static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();

 

    private static boolean isRunning = false;

 

    private static int port;

 

    public ServiceCenter(int port) {

        this.port = port;

    }

 

    public void stop() {

        isRunning = false;

        executor.shutdown();

    }

 

    public void start() throws IOException {

        ServerSocket server = new ServerSocket();

        server.bind(new InetSocketAddress(port));

        System.out.println("start server");

        try {

            while (true) {

                // 1.监听客户端的TCP连接,接到TCP连接后将其封装成task,由线程池执行

                executor.execute(new ServiceTask(server.accept()));

            }

        finally {

            server.close();

        }

    }

 

    public void register(Class serviceInterface, Class impl) {

        serviceRegistry.put(serviceInterface.getName(), impl);

    }

 

    public boolean isRunning() {

        return isRunning;

    }

 

    public int getPort() {

        return port;

    }

 

    private static class ServiceTask implements Runnable {

        Socket clent = null;

 

        public ServiceTask(Socket client) {

            this.clent = client;

        }

 

        public void run() {

            ObjectInputStream input = null;

            ObjectOutputStream output = null;

            try {

                // 2.将客户端发送的码流反序列化成对象,反射调用服务实现者,获取执行结果

                input = new ObjectInputStream(clent.getInputStream());

                String serviceName = input.readUTF();

                String methodName = input.readUTF();

                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();

                Object[] arguments = (Object[]) input.readObject();

                Class serviceClass = serviceRegistry.get(serviceName);

                if (serviceClass == null) {

                    throw new ClassNotFoundException(serviceName + " not found");

                }

                Method method = serviceClass.getMethod(methodName, parameterTypes);

                Object result = method.invoke(serviceClass.newInstance(), arguments);

 

                // 3.将执行结果反序列化,通过socket发送给客户端

                output = new ObjectOutputStream(clent.getOutputStream());

                output.writeObject(result);

            catch (Exception e) {

                e.printStackTrace();

            finally {

                if (output != null) {

                    try {

                        output.close();

                    catch (IOException e) {

                        e.printStackTrace();

                    }

                }

                if (input != null) {

                    try {

                        input.close();

                    catch (IOException e) {

                        e.printStackTrace();

                    }

                }

                if (clent != null) {

                    try {

                        clent.close();

                    catch (IOException e) {

                        e.printStackTrace();

                    }

                }

            }

 

        }

    }

}

 Remote client proxy object:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

public class RPCClient<T> {

    public static <T> T getRemoteProxyObj(final Class<?> serviceInterface, final InetSocketAddress addr) {

        // 1.将本地的接口调用转换成JDK的动态代理,在动态代理中实现接口的远程调用

        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface},

                new InvocationHandler() {

                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        Socket socket = null;

                        ObjectOutputStream output = null;

                        ObjectInputStream input = null;

                        try {

                            // 2.创建Socket客户端,根据指定地址连接远程服务提供者

                            socket = new Socket();

                            socket.connect(addr);

 

                            // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者

                            output = new ObjectOutputStream(socket.getOutputStream());

                            output.writeUTF(serviceInterface.getName());

                            output.writeUTF(method.getName());

                            output.writeObject(method.getParameterTypes());

                            output.writeObject(args);

 

                            // 4.同步阻塞等待服务器返回应答,获取应答后返回

                            input = new ObjectInputStream(socket.getInputStream());

                            return input.readObject();

                        } finally {

                            if (socket != null) socket.close();

                            if (output != null) output.close();

                            if (input != null) input.close();

                        }

                    }

                });

    }

}

Finally, as a test class:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class RPCTest {

 

    public static void main(String[] args) throws IOException {

        new Thread(new Runnable() {

            public void run() {

                try {

                    Server serviceServer = new ServiceCenter(8088);

                    serviceServer.register(HelloService.class, HelloServiceImpl.class);

                    serviceServer.start();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }).start();

        HelloService service = RPCClient.getRemoteProxyObj(HelloService.class, new InetSocketAddress("localhost", 8088));

        System.out.println(service.sayHi("test"));

    }

}

operation result:

1

2

3

regeist service HelloService

start server

Hi, test

IV Summary

      RPC is the essence of the message processing model, shielding RPC communication between different hosts underlying details so remote procedure call service are like local services.

Five areas for improvement

     RPC simple framework to achieve here is to use the Java language development, highly coupled with the Java language, and Socket communication used is based on BIO achieved, IO is not efficient, as well as native Java serialization mechanism to account for too much memory, the operating efficiency It is not high. Improvement may be considered from the following methods.

  1. It can be based RPC JSON data frame transmission;
  2. NIO can be used directly or alternatively Netty BIO implemented;
  3. The use of open source serialization mechanism, such as Hadoop Avro and Google protobuf and so on;
  4. Zookeeper service registry can be used to manage, can make application more stable.

Transfer: https://www.cnblogs.com/codingexperience/p/5930752.html 

Guess you like

Origin blog.csdn.net/sinat_22808389/article/details/87974822