RPC

一、RPC基础

RPC是什么?

RPC是远程过程调用(Remote Procedure Call)的缩写,简单的来说就是像调用本地方法一样调用远程方法。

RPC简化版原理:
RPC

RPC实现原理:

大概由如下几部分组成:

1. 设计

本地应用程序与远程应用程序,需要共享什么信息?

可以共享:POJO实体类定义、接口定义。当然还可以选择:WSDL/WADL/IDL

  • WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言
definitions>

<types>
   definition of types........
</types>

<message>
   definition of a message....
</message>

<portType>
   definition of a port.......
</portType>

<binding>
   definition of a binding....
</binding>

</definitions>

2. 代理

Java下,代理可以选择使用动态代理或者AOP实现。

3. 序列化

  • JSON
  • Hessian:不区分语言,简单紧凑,支持加密压缩,除了是序列化协议,也是一个RPC框架
  • avro :Avro的产生解决了JSON的冗长和没有IDL的问题
  • Thrift :Thrift并不仅仅是序列化协议,而是一个RPC框架。相对于JSON和XML而言,Thrift在空间开销和解析性能上有了比较大的提升
  • protobuf :序列化数据非常简洁,紧凑,与XML相比更快占用空间更小

速度、空间对比图:
RPC

具体数据:
RPC

4. 网络传输

TCP/SSL/HTTP/HTTPS

5. 查找实现类

通过接口去查找服务端的实现类。一般是注册方式。将实现类注册到Spring的方式

二、常用的RPC技术

Hessian、Thrift、gRPC

gRPC使用示例:

  1. 引入pom文件
<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-all</artifactId>
			<version>${grpc-version}</version>
		</dependency>
  1. 引入plugin
<build>
		<plugins>
			<plugin>
				<groupId>org.xolstice.maven.plugins</groupId>
				<artifactId>protobuf-maven-plugin</artifactId>
				<version>0.5.0</version>
				<configuration>
					<!--
                        The version of protoc must match protobuf-java. If you don't depend on
                        protobuf-java directly, you will be transitively depending on the
                        protobuf-java version that grpc depends on.
                    -->
					<protocArtifact>com.google.protobuf:protoc:3.5.0:exe:${os.detected.classifier}</protocArtifact>
					<pluginId>grpc-java</pluginId>
					<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc-version}:exe:${os.detected.classifier}</pluginArtifact>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
							<goal>compile-custom</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<extensions>
			<extension>
				<groupId>kr.motd.maven</groupId>
				<artifactId>os-maven-plugin</artifactId>
				<version>1.4.1.Final</version>
			</extension>
		</extensions>

	</build>
  1. 创建proto文件

在src/main/proto目录下创建一个proto文件:
RPC

内容为:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}
// The response message containing the greetings
message HelloReply {
  string message = 1;
}
  1. 运行插件,生成java文件
    RPC

  2. 编写server代码

package com.mmc.springbootstudy.grpc;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.stub.StreamObserver;
 
import java.io.IOException;
 
public class HelloWorldServer {
 
 
    private int port = 50051;
    private Server server;
 
    private void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService(new GreeterImpl())
                .build()
                .start();
 
        System.out.println("service start...");
 
        Runtime.getRuntime().addShutdownHook(new Thread() {
 
            @Override
            public void run() {
 
                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                HelloWorldServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }
 
    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }
 
    // block 一直到退出程序
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }
 
 
    public static void main(String[] args) throws IOException, InterruptedException {
 
        final HelloWorldServer server = new HelloWorldServer();
        server.start();
        server.blockUntilShutdown();
    }
 
 
    // 实现 定义一个实现服务接口的类
    private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
 
 
        public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
            System.out.println("service:"+req.getName());
            HelloReply reply = HelloReply.newBuilder().setMessage(("Hello: " + req.getName())).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
}
  1. 编写client代码
package com.mmc.springbootstudy.grpc;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;

import java.util.concurrent.TimeUnit;

public class HelloWorldClient {
 
    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
 
 
    public HelloWorldClient(String host,int port){
        channel = ManagedChannelBuilder.forAddress(host,port)
                .usePlaintext(true)
                .build();
 
        blockingStub = GreeterGrpc.newBlockingStub(channel);
    }
 
 
    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }
 
    public  void greet(String name){
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response = blockingStub.sayHello(request);
        System.out.println(response.getMessage());
 
    }
 
    public static void main(String[] args) throws InterruptedException {
        HelloWorldClient client = new HelloWorldClient("127.0.0.1",50051);
        for(int i=0;i<5;i++){
            client.greet("world:"+i);
        }
 
    }
}

  1. 启动server,再启动client发送请求,查看结果。

三、从RPC到分布式服务化

除了要实现远程调用方法外,还需要考虑什么?

  1. 多个相同的服务如何管理?
  2. 服务注册发现机制
  3. 负载均衡
  4. 熔断、限流
  5. 重试机制
  6. 高可用
  7. 监控

典型的分布式架构图
RPC

四、动手实现一个RPC框架

动起手来吧

上一篇:Dubbo -- RPC框架


下一篇:Hadoop各个服务端口列表