• gRPC实战Demo


    老齐-gRPC实战

    介绍进程通信

    何为进程间通信
    image

    通信的演化过程

    1、传统RPC
    image

    2、SOAP
    image

    3、RESTful
    image

    RESTful架构存在的问题:

    • 它是基于文本的低效消息协议
    • 应用程序之间缺乏强类型接口
    • RESTful架构风格难以强制实施

    4、gRPC

    新一代RPC通信框架
    image

    初识Google gRPC

    前身

    长期以来,谷歌有一个名为Stubby(['stʌbi] 短粗的)的通用RPC框架,用来连接成千上万的微服务,这些微服务跨多个数据中心并且使用完全不同的技术来构建。Stubby的核心PRC层每秒能处理数百亿次的互联网请求。Stubby有许多很棒的特性,但无法标准化为业界通用的框架,因为它与谷歌内部的基础设施耦合得过于紧密。2015年谷歌发布了开源PRC框架gRPC,这个RPC基础设施具有标准化、可通用和跨平台得特点,旨在提供类似Stubby的可扩展性、性能和功能,但它主要面向社区。

    gRPC优点

    • 高效的进程间通信
      gRPC没有使用JSON或XML这样的文本化格式,而是使用一个基于Protocol buffers的二进制协议与gRPC服务和客户端通信。
    • 有简单且定义良好的服务接口和模式
      gRPC为应用程序开发提供了一种契约优先(契约驱动)的方式。也就是说,首先必须定义服务接口,然后才能去处理实现细节。
    • 属于强类型
      gRPC服务契约清晰定义了应用程序间进行通信所使用的类型。这样一来,在构建跨多个团队和技术类型的云原生应用程序时,对于其所产生的大多数运行时错误和互操作错误,可以通过静态类型来克服,因此分布式应用程序的开发更加稳定。
    • 支持双共通信
      即客户端能发送消息给服务端,服务端也能发消息给客户端,且同一时刻信息可以进行双向传输。
    • 支持多语言
    • 大厂背书,社区活跃

    gRPC缺点

    • 不太适合面向外部
      适合用在公司内部的通信,不太适合外部,因为gRPC的通信规定严格且它太新了(2015年开源),我们不可能要求客户或者已经实现好的第三方服务去配合我们改成gRPC通信。
    • 当出现巨大的服务定义变更时会产生复杂的开发流程
      在现代的服务间通信场景,模式修改很常见。如果出现巨大的gRPC服务定义变更,通常需要重新生成客户端代码和服务端代码。这需要整合到现有的持续集成过程中,可能会让整个开发生命周期复杂化。
    • gRPC生态相对较小

    gRPC传输格式Protobuf

    Google Protocol Buffers是Google提供一个具有高效的协议数据交换格式工具库(类似Json),Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。
    image

    注:Protocol buffers是在HTTP/2的基础上开发的。

    安装Protobuf环境和IDEA插件

    1、去Github下载,地址:https://github.com/protocolbuffers/protobuf/releases
    image

    1.1、配置环境变量,并打开cmd窗口验证是否安装成功,使用protoc命令
    image

    2、在IDEA中安装插件
    image


    以下是DEMO

    开发News服务端

    Maven增加gRPC依赖

    <dependencies>
            <!--grpc底层通信组件-->
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
                <version>1.42.0</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
                <version>1.42.0</version>
            </dependency>
            <!--存根-->
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
                <version>1.42.0</version>
            </dependency>
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>annotations-api</artifactId>
                <version>6.0.53</version>
                <!--provided:只能作用在编译和测试时,同时没有传递性-->
                <scope>provided</scope>
            </dependency>
        </dependencies>
    

    引入protobuf一maven-plugin插件

    <build>
            <extensions>
                <extension>
                    <groupId>kr.motd.maven</groupId>
                    <artifactId>os-maven-plugin</artifactId>
                    <version>1.6.2</version>
                </extension>
            </extensions>
            <plugins>
                <plugin>
                    <groupId>org.xolstice.maven.plugins</groupId>
                    <artifactId>protobuf-maven-plugin</artifactId>
                    <version>0.6.1</version>
                    <configuration>
                        <protocArtifact>com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}</protocArtifact>
                        <pluginId>grpc-java</pluginId>
                        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}</pluginArtifact>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    

    编写proto服务定义文件
    image

    //使用proto3语法
    syntax = "proto3";
    
    //生成多个类
    option java_multiple_files = false;
    
    //生成java类所在的包
    option java_package = "com.yuan.news.proto";
    
    //生成外层类类名
    option java_outer_classname = "NewsProto";
    
    //.proto包名
    package news;
    
    /*
    接下来,定义RPC服务RouteGuide
    */
    service NewsService{
        //list是方法名,NewsRequest代表传入参数,NewsResponse代表返回响应
        rpc list(NewsRequest) returns (NewsResponse){}
    }
    
    message NewsRequest{
        string date = 1;
    }
    
    message NewsResponse{
        //repeated说明是一个集合(数组),数组每一个元素都是News对象
        repeated News news = 1;
    }
    
    //News新闻实体对象
    message News{
        //对应java的int
        int32 id = 1;
        //新闻标题
        string title = 2;
        //新闻内容
        string content = 3;
        //对应java的long
        int64 createTime = 4;
    }
    

    实现服务端业务逻辑

    1、打开maven插件
    image

    2、点击上述两个图标,生成文件,文件在target中image

    3、打开image
    文件

    将其中的com包中的文件拖到自己的java文件夹下image

    得到这两个文件
    image

    4、编写Service类

    package com.yuan.news.service;
    
    import com.yuan.news.proto.NewsProto;
    import com.yuan.news.proto.NewsServiceGrpc;
    import io.grpc.stub.StreamObserver;
    
    import java.util.Date;
    
    /**
     * @author wuhaoyuan
     * @date 2022/5/15 18:54
     * @Description 核心业务
     *
     * 此处的NewsServiceGrpc.NewsServiceImplBase是gRPC自己生成的
     */
    public class NewsService extends NewsServiceGrpc.NewsServiceImplBase {
    
        /**
         * 此处注意,我们之前在news.proto文件中定义过,list方法的返回值应该是NewsResponse,但此处的返回值却是void。
         * 可以得知,在gRPC中,返回值是作为传入参数放在传入参数的最后一个位置上。
         * */
        @Override
        public void list(NewsProto.NewsRequest request, StreamObserver<NewsProto.NewsResponse> responseObserver) {
            String date = request.getDate();
            NewsProto.NewsResponse newList = null;
            try {
                //gRPC中有大量的构造器模式使用情景
                NewsProto.NewsResponse.Builder newListBuilder = NewsProto.NewsResponse.newBuilder();
                for (int i = 1; i <= 100; i++) {
                    NewsProto.News news = NewsProto.News.newBuilder()
                            .setId(i)
                            .setTitle("新闻标题"+i)
                            .setContent(date + "当日新闻内容:"+i)
                            .setCreateTime(new Date().getTime())
                            .build();
                    newListBuilder.addNews(news);
                }
                newList = newListBuilder.build();
            }catch (Exception e){
                responseObserver.onError(e);
            }finally {
                //相当于返回数据
                responseObserver.onNext(newList);
            }
            responseObserver.onCompleted();
        }
    }
    

    开发服务端启动器

    public class GrpcServer {
    
        //自定义一个占用端口
        private static final int port = 9999;
    
        public static void main(String[] args){
            try {
                io.grpc.Server server = ServerBuilder.forPort(port).addService(new NewsService()).build().start();
                System.out.println("gRPC服务端启动,端口号为"+port);
                server.awaitTermination();
            }catch (Exception e){
                System.out.println("服务端异常");
            }
        }
    }
    

    开发News客户端

    步骤与服务端类似:
    1、加maven依赖

    2、加maven插件

    3、复制一个proto服务定义文件,从服务端那里复制,要一模一样

    4、点击maven插件按钮(两个),生成文件(在target中),拖到自己的java文件夹下

    5、编写客户端的启动类

    package com.yuan.news;
        
        import com.yuan.news.service.NewsService;
        import io.grpc.ServerBuilder;
        
        /**
         * @author wuhaoyuan
         * @date 2022/5/15 19:34
         * @Description gRPC启动类
         */
        public class GrpcServer {
        
            //自定义一个占用端口
            private static final int port = 9999;
        
            public static void main(String[] args){
                try {
                    io.grpc.Server server = ServerBuilder.forPort(port).addService(new NewsService()).build().start();
                    System.out.println("gRPC服务端启动,端口号为"+port);
                    server.awaitTermination();
                }catch (Exception e){
                    System.out.println("服务端异常");
                }
            }
        }
    

    7、开启服务端,开启客户端

    结束

  • 相关阅读:
    Nginx启动/停止服务和各种命令
    文件权限导致Weblogic Embedded LDAP Server启动失败解决办法
    jmeter(八)非图形界面、输出html报告
    jmeter(七)服务器监控
    python中如何把一段文字中的空格替换成换行符
    jmeter(五)jpgc插件的使用
    jmeter(四)提取响应结果
    Jmeter (三)变量、参数化、函数
    jmeter(二)录制脚本
    Jmeter(一)发送http请求
  • 原文地址:https://www.cnblogs.com/whyblogs/p/16275659.html
Copyright © 2020-2023  润新知