A4. gRPC的简单实践
Posted artikell
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了A4. gRPC的简单实践相关的知识,希望对你有一定的参考价值。
a. 前言
公司内部各个服务调用会使用各式各样的rpc协议,而gRPC逐步的开始成为协议的热门,本期来了解一下gRPC的发展,并进行相关的实验。
b. gRPC的历史
众所周知:gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。
这是所有介绍里面都会说的一句话,里面有3个核心点:高性能、面向移动、HTTP/2。所以问题在于gRPC是如何实现这3个特点。
相对官方的文档有2个:
官网:https://www.grpc.io/docs/what-is-grpc/
开源中国组织翻译的《gRPC 官方文档中文版》:http://doc.oschina.net/grpc
b.1 gRPC的特性
从相关文章中,能摘录出一下3个特性。
基于HTTP/2
HTTP/2 提供了连接多路复用、双向流、服务器推送、请求优先级、首部压缩等机制。可以节省带宽、降低TCP链接次数、节省CPU,帮助移动设备延长电池寿命等。gRPC 的协议设计上使用了HTTP2 现有的语义,请求和响应的数据使用HTTP Body 发送,其他的控制信息则用Header 表示。
IDL使用ProtoBuf
gRPC使用ProtoBuf来定义服务,ProtoBuf是由Google开发的一种数据序列化协议(类似于XML、JSON、hessian)。ProtoBuf能够将数据进行序列化,并广泛应用在数据存储、通信协议等方面。压缩和传输效率高,语法简单,表达力强。
多语言支持(C, C++, Python, php, Nodejs, C#, Objective-C、Golang、Java)
gRPC支持多种语言,并能够基于语言自动生成客户端和服务端功能库。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它语言的版本正在积极开发中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等语言,grpc-java已经支持android开发。
基于上述几个特性,gRPC已经应用在Google的云服务和对外提供的API中,其主要应用场景如下:
低延迟、高扩展性、分布式的系统
同云服务器进行通信的移动应用客户端
设计语言独立、高效、精确的新协议
便于各方面扩展的分层设计,如认证、负载均衡、日志记录、监控等
也可以看出gRPC和thrift之间的区别:
[tcp/udp [http2 [PrototBuf [gRPC Data ]]]]
[tcp [TTransport[TProtocal [thrift Data ]]]]
在数据和TCP链接中,分别把传输方式和编码协议给替换。
既然如此,那2者直接的核心差异都有哪些?
c. gRPC实践
首先,需要搭建gRPC的基本环境。当然存在2种方法:apt包管理安装、原生安装。这就不过多赘述。直接进入proto文件的编写。
proto文件就类比thrift文件的IDL文件,英文全称是:交互式数据语言Interactive Data Language
,下面是一个简单的实例:
syntax = "proto3"; //语法声明
package protodemo; //包名
// DemoHello 微服务
service DemoHello {
// Sends a message
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// HelloRequest 请求数据格式
message HelloRequest {
string name = 1;
}
// HelloReply 响应数据格式
message HelloReply {
string message = 1;
}
这简单的实例中存在几个关键点:
syntax,当前版本协议
service,定义一个服务
rpc,定义一个rpc接口
message,定义一个结构体类型
至此,我们就拥有了一个简单的proto文件,接下来就可以使用下面的命令来生成一个golang的代码。
protoc --go_out=plugins=grpc:. hello.proto
这样就可以在当前目录下面生成一个hello.pb.go的文件。
既然是rpc,那肯定是存在client和server2个端,于是我们需要分别写下2端的代码逻辑。
客户端代码如下:
/**
client/main.go 文件
> mkdir client
> cd client
> go mod init github.com/demo/client
> mkdir protodemo
> cp ../hello.proto protodemo
**/
package main
import (
"context"
"log"
"os"
"time"
"google.golang.org/grpc"
pb "github.com/demo/client/protodemo"
)
const (
address = "localhost:11423"
defaultName = "world"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewDemoHelloClient(conn)
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Hello world: %s", r.Message)
}
服务端代码如下:
/**
server/main.go 文件
> mkdir server
> cd server
> go mod init github.com/demo/server
> mkdir protodemo
> cp ../hello.proto protodemo
**/
package main
import (
"context"
"log"
"net"
"time"
"google.golang.org/grpc"
pb "github.com/demo/server/protodemo"
"google.golang.org/grpc/reflection"
)
const (
port = ":11423"
)
type server struct{} //服务对象
// SayHello 实现服务的接口 在proto中定义的所有服务都是接口
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
t := time.Now()
return &pb.HelloReply{Message: "Hello " + in.Name + "\n Now Time is: " + t.Format("20060102150405")}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer() //起一个服务
pb.RegisterDemoHelloServer(s, &server{})
// 注册反射服务 这个服务是CLI使用的 跟服务本身没有关系
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
其中当然是直接使用最新的gomod来管理。
在启动server端后,我们就可以调用client来进行通信。
至此是gRPC的基础实践,但在实践过程中,会存在多种疑问,如下:
thrift和pb的优缺点
pb的版本兼容
gRPC的性能情况
http2的高效
thrift和gRPC的使用场景
pb在移动端的使用
... ...
这些疑问在后续将逐步了解并整理。
z. 相关链接
https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html
http://hengyunabc.github.io/thinking-about-grpc-http2/
https://zhuanlan.zhihu.com/p/148139089
以上是关于A4. gRPC的简单实践的主要内容,如果未能解决你的问题,请参考以下文章