美文网首页
golang grpc

golang grpc

作者: X_4655 | 来源:发表于2019-08-14 22:11 被阅读0次

    golang grpc

    rpc种类

    1.支持多语言的rpc框架,例如Google的grpc,facebook thrift, 百度的brpc
    
    2.支持特定语言的rpc框架, 例如新浪微博的Motan
    
    3.支持服务治理微服务化特性框架,其底层仍是rpc框架,例如 阿里的Dubbo
    
    目前业内主要使用基于多语言的 RPC 框架来构建微服务,是一种比较好的技术选择,例如netflix ,API服务编排层和后端微服务之间采用微服务rpc进行通信
    
    

    grpc含义

    gRPC是Google的RPC框架,开源、高性能、跨语言,基于HTTP/2通讯协议和Protocol Buffer 3数据序列化协议

        定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
    
        直白的说就是调用的双方可以使用完全不同的两种语言来实现,分别实现client端和server端,按照约定的protobuf协议进行交互。client端会保存与server端的长连接对象或叫存根,通过这个存根可以直接调用服务端的方法。而服务端则实现了proto中指定的服务接口。
    
    

    grpc 优势

    1. 多语言
    Grpc的多语言是他做的很牛逼的地方,特别是在设备端,客户端支持ios,android,而基于http2.0的多路复用也的确让设备真正的省了流量,省了电,也省了空间
    
    2.基于Http2.0
    采用HTTP2的好处在于,因为添加了头信息,可以方便在框架层面对调用做拦截和控制(比如说限流,调用链分析,安全认证等)而且http2为标准协议,也方便以后扩展兼容其它调用端
    
    

    grpc 原理

    1.gRPC消息由netty /http/2 协议负责接入,通过grpc 注册的Http2Framelister将解码后的Http header和Http body 发送到gRPC的NettyServerHandler ,实现netty http/2的消息接入
    
    2.gRPC 的线程模型遵循 Netty 的线程分工原则,即:协议层消息的接收和编解码由 Netty 的 I/O(NioEventLoop) 线程负责;后续应用层的处理由应用线程负责,防止由于应用处理耗时而阻塞 Netty 的 I/O 线程 (因为分工原则,grpc 之间会做频繁的线程切换,如果在一次grpc调用过程中,做了多次I/O线程到应用线程之间的切换,会导致性能的下降 所以一些私有协议不太友好)
    
    

    grpc 模型

    异步非阻塞的线程模型
    
    服务端线程模型主要包括
    1.服务端的写入,客户端的接入线程(HTTP/2 Acceptor)
    2.网络I/O的读写线程
    3.服务接口调用线程
    
    客户端线程模型主要包含
    1.客户端的链接 (HTTP/2 Connector)
    2.网络I/O读写线程
    3.接口调用线程
    4.响应回调通知线程
    
    

    linux grpc 安装与使用示范

    前言:
    要编译proto文件生成go代码需要两个工具
        1.protoc :用于编译(其他语言只需要protoc足以)
        2.protoc-gen-go : 用于生成go语言的文件(go语言专用插件)
    
    

    安装

    1).安装grpc运行环境
        go get google.golang.org/grpc
    
    2).安装protoc
        1. 去官网 (https://github.com/protocolbuffers/protobuf/releases) 下载对应的linux版本 例如我下载的protobuf-cpp-3.9.1.zip
        2.unzip protobuf-cpp-3.9.1.zip 
        3.cd protobuf-3.9.1/
        4. ./configure  // 加--prefix=/路径  指定安装位置
        5.make && make install
    
    3).安装protoc-gen-go
        go get -v -u github.com/golang/protobuf/protoc-gen-go
    
        go get -v -u github.com/gogo/protobuf/gogoprot
    
    

    使用

    1). 编写proto文件

    示例:
    
    //testHello.proto
    syntax = "proto3";
    
    package protos;
    
    // 定义服务 也可以不定义 后续再用其他方法
    service Devops {
        // 定义服务 接收参数类型 返回参数类型
        rpc SayHello (HelloRequest) returns (Response) {
        }
    }
    
    // 定义接受请求参数
    message HelloRequest {
        string name = 1;
    }
    
    // 定义次一级返回格式
    message HelloReply {
        string message = 1;
    }
    
    // 也可以定义第二级返回格式
    message Tdata {
        string address = 1; //允许字符串      后续数字仅仅表示为标识符而已
        int64 telphone = 2; // 允许int
        float money = 3; // 允许浮点
        bool live = 4; //允许布尔
        bytes person = 5; // 允许字节码
    }
    // 定义次一级返回格式
    message Datas {
        int32 id = 1;
        string number = 2;
        repeated Tdata tdatas = 3; //repeated 为允许多个 Tdata 也可以继续套接
    }
    
    //还能定义更复杂的套接
    message DBS {
        repeated Datas dbs = 1;
    }
    
    // 定义最后返回参数
    message Response {
        // 定义固定返回状态吗类型 采用枚举
        enum StatusCode {
            TEST = 0;
            SUCCESS = 200;
            REDIRECT = 300;
            UNDEFINED = 404;
            FAILURE = 500;
        }
    
        // 综合定义返回
        StatusCode status = 1;
        HelloReply msg = 2;
        Datas data = 3;
        DBS db = 4;
    }
    
    

    2).在终端自动生成pb.go

    语法: protoc -I <需要编译的proto文件存放的路径> --go_out=plugins=grpc: . <读取编译文件的绝对路径/*.proto>
    
    示例:protoc -I /Users/liuxinMAC/go/src/workspace/gc/ --go_out=plugins=grpc:. /Users/liuxinMAC/go/src/workspace/gc/testhello.proto
    
    缩写: protoc -I . --go_out=plugins=grpc:. testhello.proto
    
    参数说明:
    --go_out-plugins-grpc: 固定格式 输出golang相关文件
    
    

    3).编写服务端

    示例:
    package main
    
    import (
        "context"
        "fmt"
        "google.golang.org/grpc"
        "log"
        "net"
        pb "workspace/test/protos"
        //pb "workspace/testwork/protos"
    )
    
    const (
        port = ":50051"
    )
    
    type myserver struct{}
    
    //这里myserver实现了SayHello
    func (s *myserver) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.Response, error) {
        fmt.Print("receive " + in.Name)
    
        ///////下面这一段也可以不用的 演示而已
        //也可以定义很多返回
        d1 := &pb.Datas{
            Id:     1,
            Number: "111",
            Tdatas: []*pb.Tdata{ // 直接取最底层
                {Address: "北京", Telphone: 1333333333, Money: 88888888.88, Live: true, Person: []byte("路人甲")},
                {Address: "上海", Telphone: 1444444444, Money: 9999999999999.88, Live: false, Person: []byte("路人乙")},
            },
        }
        d2 := &pb.Datas{
            Id:     2,
            Number: "222",
            Tdatas: []*pb.Tdata{ // 直接取最底层
                {Address: "广州", Telphone: 15555555555, Money: 66666666666.88, Live: true, Person: []byte("路人丁")},
                {Address: "成都", Telphone: 1666666666, Money: 9999999.88, Live: false, Person: []byte("路人丙")},
            },
        }
    
        //可以创建一个数据集合 继续复杂点
        ds := *&pb.DBS{}
        ds.Dbs = append(ds.Dbs, d1)
        ds.Dbs = append(ds.Dbs, d2)
    
        //定义返回数据
        return &pb.Response{
            Status: pb.Response_SUCCESS,
            Msg:    &pb.HelloReply{Message: "receive " + in.Name},
            Data:   &pb.Datas{Id: 99999, Number: "{'liuixn':'123456789987654321'}"}, //可以就 指定一个返回
            Db:     &ds,
        }, nil
    }
    
    func main() {
        //绑定端口
        lis, err := net.Listen("tcp", port)
        if err != nil {
            log.Fatal("fail to listen")
        }
        s := grpc.NewServer()
        pb.RegisterDevopsServer(s, &myserver{})
        s.Serve(lis)
    }
    
    

    4).编写客户端

    示例:
    package main
    
    import (
        "context"
        "fmt"
        "google.golang.org/grpc"
        "log"
        pb "workspace/test/protos"
        //pb "workspace/testwork/protos"
    )
    
    const (
        address = "localhost:50051"
    )
    
    func main() {
        conn, err := grpc.Dial(address, grpc.WithInsecure()) // 链接grpc
        if err != nil {
            log.Fatal("err;;;;;;;;;;", err)
        }
        c := pb.NewDevopsClient(conn)                                                                         // 生成grpc客户端
        res, _ := c.SayHello(context.Background(), &pb.HelloRequest{Name: "liuxintest first protobuf  hhhh"}) // 发送约定的数据
        fmt.Println(res)
    
    }
    

    相关文章

      网友评论

          本文标题:golang grpc

          本文链接:https://www.haomeiwen.com/subject/ewrojctx.html