gRPC概述

RPC

说到gRPC就不得不提RPC,所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,简单点来说就是我A机器上写的函数可以在B机器上通过RPC协议直接调用。

它与http不同的是:

  • RPC是基于TCP实现的,RESTFUL是基于HTTP来实现的。
  • 从传输速度上来看,因为HTTP封装的数据量更多所以数据传输量更大,所以RPC的传输速度是比RESTFUL更快的。

为什么内部(约定情况下的服务与服务)使用rpc,而外部(to customer)使用http

  • 因为HTTP协议是各个框架都普遍支持的。在toC情况下,因为不知道情况来源的框架、数据形势是什么样的,所以在网关可以使用Restful利用http来接受。而在微服务内部的各模块之间因为各协议方案是公司内部自己定的,所以知道各种数据方式,可以使用TCP传输以使各模块之间的数据传输更快。所以可以网关和外界的数据传输使用RESTFUL,微服务内部的各模块之间使用RPC。

gRPC又是什么呢

gRPCRPCStubbyRPCGoogleStubbygRPC

在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的方法,就像它是本地对象一样,使您可以更轻松地创建分布式应用程序和服务。与许多 RPC 系统一样,gRPC 基于定义服务的思想,指定可以通过参数和返回类型远程调用的方法。在服务器端,服务器实现了这个接口并运行一个 gRPC 服务器来处理客户端调用。在客户端,客户端有一个存根(在某些语言中简称为客户端),它提供与服务器相同的方法。

安装

Golang IDE(Goland)

Protocol Buffer

Protocol Buffer

下载Protocal Buffer

在GitHub的protocolbuffers项目下,下载ProtocalBuffer编译器

配置Protocal Buffer编译器环境变量

将下载好的Protocal Buffer压缩包解压,并将运行目录配置到环境变量

cmdprotoc --version

protoc-gen-go

protoc-gen-go是protobuf编译插件系列中的Go版本,protoc-gen-go可以将Protocol Buffer写的接口定义转换封装为Golang代码

在下载protoc-gen-go之前,我们先设置下Golang代理地址

# 七牛云
go env -w GOPROXY=https://goproxy.cn,direct

下载protoc-gen-go

go get -u github.com/golang/protobuf/protoc-gen-go

如果GOPATH的bin目录下有这个文件即表示下载成功

定义Protocal Buffer
pbfilesproduct.proto
syntax = "proto3";
package pbfiles;

option go_package = "../services";

message Product{
    int32 id = 1;
    string name = 2;
    int32 count = 3;
    string description = 4;
}

service pdService{
    rpc GetProduct(Product) returns(Product);
}
protoc
protoc --go_out=plugins=grpc:./ *.proto
servicesprotoproduct.pb.go
google.golang.orgmod
go mod init gRPCdemo
go mod tidyproduct.pb.go
添加gRPC服务

Golang服务端实现

grpc-server.go
package main

import (
	"context"
	"fmt"
	"gRPCdemo/services"
	"google.golang.org/grpc"
	"net"
)

type productRequest struct {
}

func (this *productRequest) GetProduct(context context.Context, request *services.Product) (*services.Product, error) {
	var product services.Product
	switch request.Id {
	case 1:
		product.Id = 1
		product.Name = "苹果"
		product.Description = "小苹果"
	case 2:
		product.Id = 1
		product.Name = "西瓜"
		product.Description = "大西瓜"
	default:
		product.Id = 3
		product.Name = "香蕉"
		product.Description = "香蕉"
	}
	return &product, nil
}

func main() {
	grpcService := grpc.NewServer()
	services.RegisterPdServiceServer(grpcService, new(productRequest))

	listen, err := net.Listen("tcp", ":5000")
	if err != nil {
		fmt.Println("listen err:", err)
		return
	}
	grpcService.Serve(listen)
}

go run grpc-server.go

Golang客户端实现

grpc-client.go
package main

import (
	"context"
	"fmt"
	"gRPCdemo/services"
	"google.golang.org/grpc"
)

func main() {
	grpcCnn, err := grpc.Dial(":5000", grpc.WithInsecure())
	if err != nil {
		fmt.Println("grpc.dial err:", err)
		return
	}

	grpcClient := services.NewPdServiceClient(grpcCnn)

	var request services.Product
	request.Id = 1

	res, err := grpcClient.GetProduct(context.TODO(), &request)
	if err != nil {
		fmt.Println("GetProduct err:", err)
		return
	}

	fmt.Println(res)
}

go run grpc-client.go


此时可以看到,已成功访问gRPC服务

.NetCore访问Golang搭建的gRPC服务
grpcClient管理Nuget程序包Protosproduct.proto
syntax = "proto3";
package pbfiles;

option csharp_namespace = "grpcClient";

message Product{
    int32 id = 1;
    string name = 2;
    int32 count = 3;
    string description = 4;
}

service pdService{
    rpc GetProduct(Product) returns(Product);
}
grpcClient.csprojgreet.proto
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.18.0" />
    <PackageReference Include="Grpc.Net.Client" Version="2.39.0" />
    <PackageReference Include="Grpc.Tools" Version="2.41.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    
    <!--添加Protobuf元素组-->
    <Protobuf Include="Protos\product.proto" GrpcServices="Client" />
  </ItemGroup>

</Project>

grpcClientGrpcGreetergrpcClient
using Grpc.Net.Client;
using System;

namespace grpcClient
{
    class Program
    {
        static void Main(string[] args)
        {
            // 只有 .NET Core 3.x 需要 System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport 开关。 .NET 5 中不需要任何额外配置,也没有这项要求。
            AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
            
            using var channel = GrpcChannel.ForAddress("http://localhost:5000");
            var client = new pdService.pdServiceClient(channel);
            var reply = client.GetProduct(new Product { Id = 1 });
            Console.WriteLine(reply);

            Console.ReadKey();
        }
    }
}


启动程序后,.NetCore完美访问Golang搭建的gRPC服务

参考