我正在参加「启航计划」
前语
最近在看有关微服务的内容,今日想总结一下有关gRPC的常识.下面的图很好的解说了gRPC的特点,服务端负责完成接口来处理客户端的请求,客户端直接调用需求的服务就行.最杰出的特点便是gRPC的服务端和客户端能够支撑不同言语完成,也便是说不再有言语的障碍会啥用啥就好了(像其它一些RPC结构比如Dubbo就只支撑Java而不能跨言语通讯)
1. gRPC与ProtoBuf
假如对gRPC不熟悉能够先去看看gRPC官网的介绍
默许情况下,gRPC是使用Protocol Buffers来传递数据的,比起xml或许json更加轻量(二进制格局而不是文本格局).在这儿关于ProtoBuf和gRPC的装置配置我就不多赘述,能够参考其他博客.
惯例的步骤也很简单,根据官网的教程首要使用protobuf界说好服务,然后使用protoc
生成各自言语的proto文件进行调用完成不同言语的服务端与客户端.
2. gRPC的适用场景
- 散布式: gRPC的低延迟和高吞吐非常合适散布式微服务
- 多言语开发: gRPC支撑多种言语,因而合适不同言语的工程师们混合开发
- 轻量化音讯: gRPC发送的音讯是ProtoBuf二进制,比普通的二进制格局音讯有天然优势
3. Demo
我平时常用的几种言语便是C++ Go Python
,不过假如做服务用C++
还是比较少的,所以今日测验一下用Go
和Python
别离写服务端和客户端进行通讯.
3.1 Proto界说及转化
syntax="proto3";
option go_package="./;hello";
package hello;
service Greeter{
rpc SayHello(HelloRequest) returns (HelloReply){}
}
message HelloRequest{
string name = 1;
}
message HelloReply{
string message = 1;
}
这儿界说了Greeter
这个服务以及服务中传递的音讯,接下来需求转化为两种言语的代码
- Go
protoc --proto_path=../protos --go_out=plugins=grpc:. hello.proto
protoc --proto_path=../protos --go_out=. --go-grpc_out=. hello.proto
- Python
pip install grpcio grpcio-tools
python -m grpc_tools.protoc -I ./protos --python_out=. --pyi_out=. --grpc_python_out=. ./protos/hello.proto
3.2 服务端部分Go完成
package main
import (
pb "PRC_learning/hello"
"context"
"flag"
"fmt"
"google.golang.org/grpc"
"log"
"net"
)
type server struct{ pb.UnimplementedGreeterServer }
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
var port = flag.Int("port", 50001, "The Server Port")
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
if err != nil {
log.Fatal("fail to listen :%v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("fail to serve:%v", err)
}
}
flag能够经过命令行解析设置服务的端口号,这儿ip我设置的是本地.这儿服务主要是完成hello_grpc.pb.go
中的接口
3.3 客户端部分Python完成
import grpc
import hello_pb2
import hello_pb2_grpc
def run():
with grpc.insecure_channel(target='localhost:50001',
options=[
('grpc.lb_policy_name','pick_first'),
('grpc.enable_retries',0),
('grpc.keepalive_timeout_ms',1000)
]) as channel:
stub=hello_pb2_grpc.GreeterStub(channel)
response=stub.SayHello(hello_pb2.HelloRequest(name='xxx'),timeout=10)
print(f"Greeter client received:{response.message}")
if __name__ == '__main__':
run()
关注于run函数部分,除了为了通讯设置相同的端口,更应该注意到SayHello
这个办法.这个Demo是一元的音讯(还有流式的音讯等方式)所以对应unary_unary
这个办法
需求传入某个办法,请求的编码序列化以及回应的解序列化.上面那张图就完成了这三个参数
最终返回呼应,输出呼应值中的信息就完成了一次通讯
3.4 运转
首要运转服务端 go run server.go
然后运转客户端 python client.py