微服务

RPC

  • 远程过程调用,一个服务去调用另一个服务的方法
遇到的问题
  • CALL id的映射
  • 序列化和反序列化
  • 网络传输

GO内置rpc

  • 服务端

type HelloService struct {
}

func (this *HelloService) SayHello(req string, reply *string) error {
	*reply = "hello"
	return nil
}

func main() {
	//实列化要给server
	listen, err := net.Listen("tcp", "localhost:1234")
	if err != nil {
		fmt.Println("Listen err:", err.Error())
	}
	//注册处理逻辑
	_ = rpc.RegisterName("HelloService", &HelloService{})
	//启动服务
	accept, _ := listen.Accept()
	rpc.ServeConn(accept)
}
  • 客户端
func main() {

	client, err := rpc.Dial("tcp", "localhost:1234")
	if err != nil {
		fmt.Println("Dial err:", err.Error())
	}
	var reply string
	err = client.Call("HelloService.SayHello", "suncc", &reply)
	fmt.Println(reply)
	if err != nil {
		fmt.Println(err)
	}

}

GRPC

  • grpc 谷歌的
  • protobuf 就是高压缩比
  • 序列化和反序列快
  • 传输速度快
  • 简单使用
  • 维护成本低
  • 向后兼容
  • 加密性好

安装

  • 要去下载protoc
  • 然后执行go get 命令

protobuf

  • 基本格式
//使用proto3的语法
syntax = "proto3";
//.表示生成的go文件在那个目录下
//serivce 表示生成的go的包名
option go_package=".;service";
//定义一个rpc服务接口
service SayHello {
    rpc SayHello(HelloRequest) returns (HelloReply);
    rpc BayHello(HelloRequest) returns (HelloReply);
}
message Person {
    string name = 1;
    int32 age = 2;
    repeated string hobbies = 3;//代表是切片
}
message HelloRequest {
    string name = 1;//消息的编号
    repeated string hobbies = 2;//代表是切片
    Person person = 3;
}
message HelloReply {
    string msg = 1;
}
//    protoc --go_out=. hello.proto
//    protoc --go-grpc_out=. hello.proto

grpc的使用

  • 客户端
package main

import (
	service "RPC/helloword/hello-server/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
)

type server struct {
	service.UnimplementedSayHelloServer //提供默认实现
}

//固定写法
func (srv *server) SayHello(ctx context.Context, in *service.HelloRequest) (*service.HelloReply, error) {
	return &service.HelloReply{Msg: "nihao"}, nil
}
func (srv *server) SayBye(ctx context.Context, in *service.HelloRequest) (*service.HelloReply, error) {
	return &service.HelloReply{Msg: "byebye"}, nil
}

func main() {
	g := grpc.NewServer()
	service.RegisterSayHelloServer(g, &server{})
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println("failed to listen: %v", err)
		return
	}
	err = g.Serve(listen)
	if err != nil {
		fmt.Println("failed to serve: %v", err)
		return
	}
}

  • client
	dial, err := grpc.Dial("localhost:8080", grpc.WithInsecure())
	if err != nil {
		return
	}
	defer dial.Close()
	client := service.NewSayHelloClient(dial)
	hello, err := client.SayHello(context.Background(), &service.HelloRequest{Name: "world"})
	if err != nil {
		return
	}
	fmt.Println(hello)

grpc 模式

  • 简单模式
  • 服务端数据流模式
  • 客户端数据流
  • 双向数据流
    https://blog.csdn.net/weixin_54984185/article/details/135378670

Protobuf

bool → bool
int32 → int32
int64 → int64
uint32 → uint32
uint64 → uint64
sint32 → int32(带符号的可变长度编码)
sint64 → int64(带符号的可变长度编码)
fixed32 → uint32(固定 4 字节)
fixed64 → uint64(固定 8 字节)
sfixed32 → int32(固定 4 字节带符号)
sfixed64 → int64(固定 8 字节带符号)
float → float32
double → float64
string → string(必须是 UTF-8 编码)
bytes → []byte

option

option go_package = “.;proto”
option java_package
“生成目录位置;包名”

protobuf中使用其他的message

-Base.proto

  • import “base.proto”
//使用谷歌自带的message
import "google/protobuf/empty.proto";
rpc Test (google.protobuf.Empty) returns (google.protobuf.Empty) {}
message 嵌套
  • 如果直接加入message 那就是会提升
message Result{
	string name
	int age
}

message Hello{
	Result value  //这个内容是会被提升的
	//变成??
	string name??
	int age??
}
//使用的时候
Hello_Result{} 这个方式来初始化

枚举类型
enum  Gender{
  MALE = 0;
  FEMALE = 1;
}
message User{
	Gender g = 2
}

如果要使用 Gender_FEMALE
map类型
message User{
	map<string,string> hooby
}
使用timestamp
import "google/protobuf/timestamp.proto";
google.protobuf.Timestamp timestamp = 2;

grpc的metadata

  • 比较重要

grpc验证器

  • 就相当于表单验证
  • protoc-gen-validate
  • 将下载exe放到bin的目录下
  • 使用 https://blog.csdn.net/weixin_50448879/article/details/136629547

grpc中的异常处理

  • status.New(codes.NotFound,“记录未找到”)

grpc客户端超时机制

  • context.WithTimeout(context.Background(),time.Second*3)

更多推荐