网站是数据,网站封面制作,wordpress 子分类,深圳有哪些网络公司最近在学习gRPC相关的知识#xff0c;为啥要学呢#xff1f;因为一直在用#xff0c;古人云#xff0c;“工欲善其事#xff0c;必先利其器”。为此#xff0c;花了不少时间阅读gRPC-Go的源码#xff0c;收货甚多#xff0c;比如透过服务发现和负载均衡这俩组件来学习复… 最近在学习gRPC相关的知识为啥要学呢因为一直在用古人云“工欲善其事必先利其器”。为此花了不少时间阅读gRPC-Go的源码收货甚多比如透过服务发现和负载均衡这俩组件来学习复杂模块之间低耦合高内聚的设计方法透过bdp采样与http2流量窗口自动伸缩学习网络性能优化等等。 RPC是Remote Procedure Call的缩写中文直译为远程过程调用与之相对的则是本地过程调用即本地的函数调用。我们日常在同一个服务下相互调用的函数即为本地的函数调用。与本地函数调用相比RPC的接口提供方与请求方往往不在同一台机器上或者不在同一个进程因此双方需要通过网络传输来通信。而网络的不可靠又带来了一定的复杂性。 如果让我们自己来设计RPC需要怎么做呢先来看一个简单请求的整个过程。假设Client通过网络将请求发送到Server端Server接收并处理完成之后通过网络再将响应发送回来Client接收响应则整个流程结束。在此过程中需要完成哪些操作呢 首先网络传输的是比特流对于结构化的请求和响应数据需要一个模块来完成序列化和反序列化的功能。 其次需要建立一个可靠的传输链接来通信比如说TCP连接为了提升性能我们还需要对链路进行管理如建立连接池、链接复用等等因此还需要构建一个传输层组件。 在微服务的背景下应用程序往往由很多功能不同的服务组成比如说一个购物程序可能包括搜索、推荐、订单管理服务等等。在这种情况下Client如何知道每个服务的具体地址呢总不能直接写死对应服务端口吧为此我们需要一个新的组件来提供服务发现功能告知我们服务的地址。现在假定我们知道了服务端地址还有一个问题。为了服务海量用户一般的服务都会分布式部署多个节点为了避免单一节点负载过高我们还需要一个组件来提供负载均衡功能策略可以是轮询、也可以是随机、也可以是一致性哈希等等。 通过上述讨论我们知道一个完善的RPC框架需要包含多个组件分别负责不同的功能。如果全部自己开发耗时费力不说且性能如何也无定论。可喜的是gRPC提供了上述所有功能。它由Google开发目前已开源。它默认使用protobuf序列化数据基于http2传输。另外通过插件式的设计支持多种不同的服务发现机制和负载均衡机制。 下文的分析基于gRPC-Go 1.54.0-dev 版本grpc-go/examples/helloworld/greeter_client/main.go 先来看下helloworld目录下的helloworld.proto协议定义
package helloworld;// The greeting service definition.
service Greeter {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the users name.
message HelloRequest {string name 1;
}
// The response message containing the greetings
message HelloReply {string message 1;
}该文件定义了Greeter服务对外提供一个方法SayHello请求和响应中都只包含了一个字符串。
下面贴出Client的关键代码
var (addr flag.String(addr, localhost:50051, the address to connect to)name flag.String(name, defaultName, Name to greet)
)func main() {// 解析参数flag.Parse()// 创建链接conn, err : grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))if err ! nil {log.Fatalf(did not connect: %v, err)}// 退出前关闭链接defer conn.Close()// 创建客户端c : pb.NewGreeterClient(conn)ctx, cancel : context.WithTimeout(context.Background(), time.Hour)defer cancel()// 发送请求_, err : c.SayHello(ctx, pb.HelloRequest{Name: strconv.Itoa(i)})if err ! nil {log.Fatalf(could not greet: %v, err)}
} 代码很简单就是创建链接、构造Client、发送请求。这几行代码究竟做了啥呢下面给出的流程图详细的画出了整个过程
图1 Client请求调用流程图中红色的部分表示主流程即上述的那几行代码。橙色部分表示负载均衡组件处理流程绿色表示服务发现组件处理流程。默认情况下gRPC的服务发现插件使用的是passthrough这个插件基本上啥都没做传进来的地址是啥结果就是啥默认的负载均衡插件是pickfirst即使用第一个可用的地址。除此之外gRPC还提供了其它的负载均衡插件如round_robin、weighted_target_experimental等等具体选择哪一个可以在Dial的时候通过参数传递进去。 主程序启动后先后初始化负载均衡、服务发现组件。服务发现解析地址后则将地址传递给负载均衡组件负载均衡组件则通知具体的负载均衡插件来建立连接此外负载均衡组件还负责连接的维护与管理工作。 底层链接即基于TCP的http2连接限于篇幅这里仅简单描述了下http2Client的功能详情可以参考之前一篇描述传输层的博客。链接建立OK后Client就可以通过负载均衡插件选择一个建立好的传输层开始收发信息。流程图看着很复杂主要模块就3个服务发现、负载均衡、网络传输层。具体的代码就不贴了流程图中已经给出了关键节点的函数。不过还是建议下载源码深入学习下。 参考资料
1. 深入理解grpc二grpc原理-CSDN博客
2.grpc/doc at master · grpc/grpc · GitHub