什么是微服务

    由一组程序在不同的网络位置运行,并且运用不同的通讯协议在彼此间传递消息。

    gRPC的定义

    gRPC3 是一项进程间通信技术,可以用来连接、调用、操作和调试分布式异构应用程序。就像调用本地函数一样,整个过程操作起来很简单

    开发gRPC服务时第一步要定义服务定义:

    • 消费者消费服务的方式
    • 消费者能够远程调用的方法
    • 方法的使用参数以及消息格式

    例:
    image.png

    • 服务定义在ProductInf.proto文件中声明

    服务定义:

    gRPC 使用 protocol buffers 作为 IDL 来定义服务接口。

    代码:使用protocol buffers 来定义ProducInfo服务(gRPC)

    1. //ProductInfo.proto
    2. //定义proto的版本
    3. synctax = "proto3";
    4. //用来放置协议消息类型之间发生命名冲突,也会用来生成代码
    5. package ecommmerce;
    6. //定义grpc服务的接口
    7. service ProductInfo{
    8. //定义参数是Product返回值是ProductID的远程方法
    9. rpc addProduct(Product) returns (ProductID);
    10. //基于ID获取详情的方法
    11. rpc getProduct(ProductID) returns (Product);
    12. }
    13. //定义proto的消息格式或者类型
    14. message Product{
    15. //保存商品 ID 的字段(名 – 值对),具有唯一的字段编号,该编号用来在二进制格式消息中识别字段
    16. string id = 1;
    17. string name = 2;
    18. string description = 3;
    19. }
    20. //用于商品标识号的用户定义类型。
    21. message ProductID {
    22. string value = 1;
    23. }

    注:

    • 服务就是可被远程调用的一组方法,比如addProduct和 getProduct 方法每个方法都有输入的参数和返回类型,既可以被定义为服务的一部分,也可以导入proto定义中
    • 参数以及返回既可以是用户定义类型 比如Product类型和ProductID类型 也可以是服务定义中已定义好的proto已知类型这些名-值对叫做字段,这些字段都是具有唯一编号的名-值(如string id = 1;)在二进制形式消息中可以用编号来识别相应字段

    gRPC服务器端

    借助 gRPC 的 protocol buffers 插件,可以生成 gRPC 服务器端代码从而填充、序列化和检索消息类型。

    1. 通过重载服务基类,实现所生成的服务器端骨架的逻辑。
    2. 运行 gRPC 服务器,监听来自客户端的请求并返回服务响应。

    代码

    import(
        ...
        "context"
        pb "github.com/grpc-up-and-running/samples/ch02/productinfo/go/proto"
        "google.golang.org/grpc"
        ...
    )
    // 添加商品的远程方法
    func (s *server) AddProduct(ctx context.Context, in *pb.Product) (*pb.ProductID, error) {
    // 业务逻辑
    }
    // 获取商品的远程方法
    func (s *server) GetProduct(ctx context.Context, in *pb.ProductID) (*pb.Product, error) {
    // 业务逻辑
    }
    

    gRPC客户端

    // 使用远程服务器地址创建通道
    ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
    .usePlaintext(true)
    .build();
    // 使用通道初始化阻塞式存根
    ProductInfoGrpc.ProductInfoBlockingStub stub =
    ProductInfoGrpc.newBlockingStub(channel);
    // 使用阻塞式存根调用远程方法
    StringValue productID = stub.addProduct(
    Product.newBuilder()
    .setName("Apple iPhone 11")
    .setDescription("Meet Apple iPhone 11." +
    "All-new dual-camera system with " +
    "Ultra Wide and Night mode.")
    .build());
    

    客户端-服务端的消息流

    客户端—protocol buffers编排—protocol buffers 格式—通过 HTTP/2 进行发送—通过protocol buffers解排

    • 编排是将参数和远程函数打包的过程,
    • 解排则是解包消息到对应的方法调用的过程。

    进程间的通信技术的演化

    http,gRPC对比

    http:
    优点:

    • 易读
    • 简单

    缺点:

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

    grpc:
    优点:

    • 高效
    • 具有简单且定义良好的服务接口和模式
    • 抢类型
    • 支持多语言
    • 支持双工流
    • 具备内置的商业化特性
    • 与云原生生态进行了集成

    缺点:

    • 不太适合面向外部的服务
    • 生态相对较小
    • 巨大的服务定义变更是复杂的开发流程