go微服务之grpc组件

grpc使用

要想知道grpc,先了解rpc(文章中这些都是我自己,学习中的小笔记不详细。想详细了解请百度,有很多资料。)

什么是rpc?

定义:

远程过程调用协议和http请求类似,只不过协议不同,rpc使用的大多数为TCP,http请求使用的为HTTP协议。

可以简单的理解为一个节点调用另外一个节点。

组成:

  • 客户端:Client,服务调用方。
  • 客户端存根:Client Stub,存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端
  • 网络传输模块:Network Service,底层传输,可以是TC 或HTTP
  • 服务端存根:Server Stub,接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
  • 服务端等:server服务的真正提供者。

执行过程:

  • Client 客户端通过本地调用的方式调用服务。
  • 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体。
  • 客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
  • 网络传输
  • 服务端存根(Server Stub)收到消息后进行解码(反序列化操作)。
  • 服务端存根(Server Stub)根据解码结果调用本地的服务进行相关处理
  • 服务端(Server)本地服务业务处理。
  • 处理结果返回给服务端存根(Server Stub)。
  • 服务端存根(Server Stub)序列化结果。
  • 服务端存根(Server Stub)将结果通过网络发送至消费方。
  • 客户端存根(Client Stub)接收到消息,并进行解码(反序列化)。
  • 客户端得到最终结果。

什么是grpc

定义:

  • 是一个高性能、开源、通用的RPC框架。
  • gRPC中采用的是HTTP2协议
  • 谷歌的产品
  • gRPC默认使用protoBuf

组成:类似rpc

执行过程:类似rpc

注意:

rpc和grpc详细了解,请百度搜索
文章中如有错误,请联系我.

go实现rpc

服务端:

rpc_sample/go_rpc_server.go

package main

import (
	"fmt"
	"net"
	"net/http"
	"net/rpc"
)

type Say struct{
    
    }

/*
注意:对外暴露的服务方法定义
1、对外暴露的方法有且只能有两个参数,这两个参数只能是输出类型或内建类型,两种类型中的一种。
2、方法的第二个参数必须是指针类型。
3、方法的返回类型为error。
*/
func (s *Say) Hello(inputArg string, outputArg *string) error {
    
    
	*outputArg = "hello " + inputArg
	return nil
}

func main() {
    
    
	// new一个对象
	say := new(Say)

	// 将对象注册到rpc服务中
	rpc.Register(say)

	// 把say中的服务注册到HTTP协议上,方便调用者可以利用http的方式进行数据传递
	rpc.HandleHTTP()
	listen, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
    
    
		fmt.Printf("net.Listen failed ,%v\n", err)
		return
	}

	http.Serve(listen, nil)
}

运行:go run go_rpc_server.go

客户端:

rpc_sample/go_rpc_client.go

package main

import (
	"fmt"
	"net/rpc"
)

func main() {
    
    
	// DialHTTP:使用http去拨号,与服务端创建连接
	client, err := rpc.DialHTTP("tcp", "127.0.0.1:8080")
	if err != nil {
    
    
		fmt.Printf("rpc.DialHTTP failed ,%v\n", err)
		return
	}
	// 返回值
	var say string

	/*
		远程调用函数:被调用的方法,传入值 ,返回值
	*/
	err = client.Call("Say.Hello", "world!", &say)
	if err != nil {
    
    
		fmt.Printf("client.Call failed ,%v\n", err)
		return
	}
	fmt.Println("结果为:", say)
}
/*
结果为: hello world!
*/

go run go_rpc_client.go

grpc使用

grpc安装

GO111MODULE=on
GOPROXY=https://goproxy.io,direct

# 设置GO111MODULE、GOPROXY下载无压力
go get google.golang.org/[email protected]
go get google.golang.org/genproto

proto内容定义

grpc_sample/grpc_protoBuf_sample/say_hi_sample.proto

syntax = "proto3";
option go_package = ".;hello";
package hello;
// 上面跟rpc基本一样定义

/*
	grpc + protobuf
	定义一个service类型
	SayHi暴露函数名
	可以定义多个服务,每个服务内可以定义多个接口
*/
service TestService {
  // 定义接口 (结构体可以复用)
  // 方法 (请求消息结构体) returns (返回消息结构体) {}
  //rpc 服务端对外的函数名(传入参数)returns(返回参数)
  rpc SayHi (HiRequest) returns (HiResponse){}
}

// 定义HiRequest消息结构
message HiRequest {
  string name = 1;
}

// 定义HiResponse消息结构
message HiResponse {
  string ret = 1;
}

proto生成go语言文件(grpc)

注意:grpc使用grpc插件

# 直接到say_hi_sample.proto文件目录执行
protoc --go_out=plugins=grpc:. say_hi_sample.proto

# 会生成say_hi_sample.pb.go文件

grpc服务端(server)

grpc_sample/go_grpc_server.go

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
	hello "sample/grpc_sample/grpc_protoBuf_sample"
)

type Server struct{
    
    } //服务对象

/*
	SayHi实现在proto中定义的TestServiceServer interface接口
	
	type TestServiceServer interface {
	//rpc 服务端对外的函数名(传入参数)returns(返回参数)
	SayHi(context.Context, *HiRequest) (*HiResponse, error)
	}
	
	TestServiceServer接口是如何来的?
	1.grpc_sample/grpc_protoBuf_sample/say_hi_sample.proto
	  proto文件中定义service类型的名为:TestService

	2.proto转成go文件就会生成2个接口:
    生成规律也很明显,就是proto文件中定义service类型的名后面加Client、Server
		TestServiceClient
		TestServiceServer
		看名称很明显肯定关于客户端、服务端
*/
func (s *Server) SayHi(ctx context.Context, in *hello.HiRequest) (*hello.HiResponse, error) {
    
    
	res := &hello.HiResponse{
    
    Ret: "hello " + in.Name}
	return res, nil
}

// name  -->   "hello name"
func main() {
    
    
	// 创建grpc服务
	server := grpc.NewServer()

	/*
		**注册接口服务:
		 * 以定义proto时的service为单位注册,服务中可以有多个方法
		 * (proto编译时会为每个service生成Register***Server方法)
		 * 包.注册服务方法(gRpc服务实例,包含接口方法的结构体[指针])
			hello.RegisterTestServiceServer
			grpc注册服务:
				1.hello是包名
				2.RegisterTestServiceServer注册服务一个方法
			RegisterTestServiceServer:
				1.参数一:grpc服务
				2.参数二:服务对象
	*/
	hello.RegisterTestServiceServer(server, &Server{
    
    })

	listen, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
    
    
		fmt.Printf("监听失败: %v\n", err)
	}
	fmt.Println("监听8080端口...")

	// 用grpc服务启动
	server.Serve(listen)
}

运行:go run go_grpc_server.go

grpc客户端(client)

grpc_sample/go_grpc_client.go

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	hello "sample/grpc_sample/grpc_protoBuf_sample"
)

func main() {
    
    
	/*
		**建立连接到gRPC服务:
		 * WithInsecure:跳过证书的验证
	*/
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
    
    
		fmt.Printf("grpc.Dial failed, :%v\n", err)
	}

	// 结束时关闭连接
	defer conn.Close()

	// 创建TestService服务的客户端
	client := hello.NewTestServiceClient(conn)

	// 调用gRPC接口
	rep, err1 := client.SayHi(context.Background(), &hello.HiRequest{
    
    Name: "world!"})
	if err1 != nil {
    
    
		fmt.Printf("client.SayHi failed, :%v\n", err1)
		return
	}
	fmt.Println(rep.Ret)
}

/* 运行结果:
hello wrold!
*/

运行:go run go_grpc_client.go

注意:

开启go module
用GoLand创建项目会有个go.mod,没有go mod init。详细go mod自行百度
grpc演示中hello "sample/grpc_sample/grpc_protoBuf_sample"
我这个go.mod中module sample是sample,引入同项目不同目录下包就是sample/...
后面使用micro会使用go module导入不同项目下包。前面先了解下,大神可以略过。

再次说明:这些都是我自己学习过程中小笔记,如有错误望告知。还有就是一些相关介绍少,想详细了解请自行百度。

猜你喜欢

转载自blog.csdn.net/Maggie_up/article/details/108702287