关于RPC远程过程调用,分布式架构下不同服务之间调用越来越紧密,对调用效率,可靠性,可用性要求越来越高。RPC就是在此环境下应运而生的。需要结合服务注册中心一起使用。Eureka,Zookeeper,Consul,Etcd等等。

  • 客户端,服务端,RPC之间的通讯: 一个服务自己可以是客户端同时也是服务端。最好采用TCP连接,传输层的TCP链接比应用层的HTTP链接更高效快速,远程过程调用的所有数据都在这个连接里传输。
  • 数据传输: 请求参数和响应数据都需要序列化成二进制数据在网络上传输,接收数据时反序列化。
  • 服务地址: 结合服务注册中心。请求某个服务我需要知道该服务的地址URL,端口号,方法名等等。Web服务协议栈的RPC,就要提供一个endpoint URI。
    服务调用流程,借用别人一张图:
    在这里插入图片描述
    1)服务消费方(client)调用以本地调用方式调用服务;
    2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
    3)client stub找到服务地址,并将消息发送到服务端;
    4)server stub收到消息后进行解码;
    5)server stub根据解码结果调用本地的服务;
    6)本地服务执行并将结果返回给server stub;
    7)server stub将返回结果打包成消息并发送至消费方;
    8)client stub接收到消息,并进行解码;
    9)服务消费方得到最终结果。
    RPC的目标就是要2~8这些步骤都封装起来。

参考文章:
https://blog.csdn.net/u013521220/article/details/70157956
https://blog.csdn.net/KingCat666/article/details/78577079


一、gRPC Java 实例

官方文档:http://doc.oschina.net/grpc?t=58008
本实例GitHub地址:https://github.com/MistraR/grpc-java-mistra
gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。
本文写个gRPC的小栗子。
gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。正如你将在下方例子里所看到的,你用 proto files 创建 gRPC 服务,用 protocol buffers 消息类型来定义方法参数和返回类型。本文使用“proto3”版本。
新建一个maven工程
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.grpc</groupId>
    <artifactId>mistra</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <grpc.version>1.9.1</grpc.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>${grpc.version}</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>${grpc.version}</version>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>${grpc.version}</version>
        </dependency>

        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>1.6.0</version>
        </dependency>

        <dependency>
            <groupId>io.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>1.6.0</version>
        </dependency>
    </dependencies>

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

新建proto文件,注意包结构
在这里插入图片描述
helloworld.proto
注意java_package的值最好跟你等会要拷贝这些生成类存放的目录一致。

syntax = "proto3";

option java_multiple_files = true;
//生成java代码的package
option java_package = "com.grpc.mistra.generate";
//创建的javaBean的文件名
option java_outer_classname = "MistraProto";
// 可以生成rpc接口
//option java_generic_services = true;

package mistra;

//声明一个服务名称
service MistraService {
  //请求参数MistraRequest   响应参数MistraResponse
  rpc SayHello (MistraRequest) returns (MistraResponse);
}

//请求
message MistraRequest {
  string name = 1;
}

//响应
message MistraResponse {
  string message = 1;
}

这个时候就可以根据proto文件生成基本类了,maven install,然后就在target文件夹下看见生成的类:
在这里插入图片描述
把看到的这6个类都拷贝到主目录下。然后新建一个client类,新建一个server类。最后目录结构如下:
在这里插入图片描述
编写Client

package com.grpc.mistra.client;


import com.grpc.mistra.generate.MistraRequest;
import com.grpc.mistra.generate.MistraResponse;
import com.grpc.mistra.generate.MistraServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.concurrent.TimeUnit;

/**
 * @Author: WangRui
 * @Date: 2018/11/27
 * Time: 14:46
 * Description:
 */
public class MistraClient {

    private final ManagedChannel channel;
    private final MistraServiceGrpc.MistraServiceBlockingStub blockingStub;

    public MistraClient(String host, int port) {
        channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext(true)
                .build();

        blockingStub = MistraServiceGrpc.newBlockingStub(channel);
    }

    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public void greet(String name) {
        MistraRequest request = MistraRequest.newBuilder().setName(name).build();
        MistraResponse response = blockingStub.sayHello(request);
        System.out.println(response.getMessage());

    }

    public static void main(String[] args) throws InterruptedException {
        MistraClient client = new MistraClient("127.0.0.1", 8001);
        System.out.println("-------------------客户端开始访问请求-------------------");
        for (int i = 0; i < 10; i++) {
            client.greet("你若想生存,绝处也能缝生: " + i);
        }
    }
}

server

package com.grpc.mistra.server;


import com.grpc.mistra.generate.MistraRequest;
import com.grpc.mistra.generate.MistraResponse;
import com.grpc.mistra.generate.MistraServiceGrpc;
import io.grpc.BindableService;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;

import java.io.IOException;

/**
 * @Author: WangRui
 * @Date: 2018/11/27
 * Time: 14:46
 * Description:
 */
public class MistraServer {

    private int port = 8001;
    private Server server;

    private void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService((BindableService) new MistraHelloWorldImpl())
                .build()
                .start();

        System.out.println("------------------- 服务端服务已开启,等待客户端访问 -------------------");

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {

                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                MistraServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        final MistraServer server = new MistraServer();
        //启动服务
        server.start();
        //服务一直在线,不关闭
        server.blockUntilShutdown();
    }

    // 定义一个实现服务接口的类
    private class MistraHelloWorldImpl extends MistraServiceGrpc.MistraServiceImplBase {

        @Override
        public void sayHello(MistraRequest mistraRequest, StreamObserver<MistraResponse> responseObserver) {
            // 具体其他丰富的业务实现代码
            System.err.println("server:" + mistraRequest.getName());
            MistraResponse reply = MistraResponse.newBuilder().setMessage(("响应信息: " + mistraRequest.getName())).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
}

运行server的main方法,启动服务。
运行client端访问服务。
在这里插入图片描述


在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐