华为快速建站,wordpress sns插件,个人摄影网站制作,佛山网站建设专业主修课程1什么是RPC
RPC#xff1a;Remote Procedure Call#xff0c;远程过程调用。简单来说就是两个进程之间的数据交互。正常服务端的接口服务是提供给用户端(在Web开发中就是浏览器)或者自身调用的#xff0c;也就是本地过程调用。和本地过程调用相对的就是#xff1a;假如两个…1什么是RPC
RPCRemote Procedure Call远程过程调用。简单来说就是两个进程之间的数据交互。正常服务端的接口服务是提供给用户端(在Web开发中就是浏览器)或者自身调用的也就是本地过程调用。和本地过程调用相对的就是假如两个服务端不在一个进程内怎么进行数据交互使用RPC。尤其是现在微服务的大量实践服务与服务之间的调用不可避免RPC更显得尤为重要 上图描述了一个RPC的完整调用流程 1client向client stub发起方法调用请求。 2client stub接收到请求后将方法名请求参数等信息进行编码序列化。 3client stub通过配置的ip和端口使用socket通过网络向远程服务器server发起请求。 4远程服务器server接收到请求解码反序列化请求信息。 5server将请求信息交给server stubserver stub找到对应的本地真实方法实现。 6本地方法处理调用请求并将返回的数据交给server stub。 7server stub 将数据编码序列化交给操作系统内核使用socket将数据返回。 8client端socket接收到远程服务器的返回信息。 9client stub将信息进行解码反序列化。 10client收到远程服务器返回的信息。 上图中有一个stub(存根)的概念。stub负责接收本地方法调用并将它们委托给各自的具体实现对象。server端stub又被称为skeleton(骨架)。可以理解为代理类。而实际上基于Java的RPC框架stub基本上也都是使用动态代理。我们所说的client端和server端在RPC中一般也都是相对的概念。 而所谓的RPC框架也就是封装了上述流程中2-9的过程让开发者调用远程方法就像调用本地方法一样。
2. gRPC的原理
gRPC是Google的开源产品是跨语言的通用型RPC框架使用Go语言编写。 Java语言的应用同样使用了Netty做网络通信Go采用了Goroutine做网络通信。序列化方式采用了Google自己开源的Protobuf。请求的调用和返回使用HTTP2的Stream。
一个RPC框架必须有两个基础的组成部分数据的序列化和进程数据通信的交互方式。
对于序列化gRPC采用了自家公司开源的Protobuf。Google Protocol Buffer(简称 Protobuf)是一种轻便高效的结构化数据存储格式平台无关、语言无关、可扩展可用于通讯协议和数据存储等领域。似乎和我们熟悉的JSON类似但其实着重点有些本质的区别。JSON主要是用于数据的传输因为它轻量级可读性好解析简单。Protobuf主要是用于跨语言的IDL它除了和JSON、XML一样能定义结构体之外还可以使用自描述格式定于出接口的特性并可以使用针对不同语言的protocol编译器产生不同语言的stub类。所以天然的适用于跨语言的RPC框架中(非常重要)
而关于进程间的通讯无疑是Socket。Java方面gRPC同样使用了成熟的开源框架Netty。使用Netty Channel作为数据通道。传输协议使用了HTTP2。 通过以上的分析我们可以将一个完整的gRPC流程总结为以下几步
● 通过.proto文件定义传输的接口和消息体。 ● 通过protocol编译器生成server端和client端的stub程序。 ● 将请求封装成HTTP2的Stream。 ● 通过Channel作为数据通信通道使用Socket进行数据传输。
3 实践开始
下面我们使用代码基于以上的步骤来实现一个简单gRPC。我们用Go实现server端Java作为client端来实现。
3.1 安装Protocol Buffers定义.proto文件
下载Protocol Buffershttps://github.com/protocolbuffers/protobuf/releases 检查安装
protoc --version定义一个simple.proto这也是后续实现gRPC的基础
syntax proto3; //定义了我们使用的Protocol Buffers版本。option go_package ./;simple;//***在java端请注释本行***//表明我们定义了一个命名为Simple的服务(接口)内部有一个远程rpc方法名字为SayHello。//我们只要在server端实现这个接口在实现类中书写我们的业务代码。在client端调用这个接口。service Simple{rpc SayHello(HelloRequest) returns (HelloReplay){}}//请求的结构体message HelloRequest{string name 1;}//返回的结构体message HelloReplay{string message 1;}3.2 在Go端实现server
根据官方文档使用如下命令安装针对Go的gRPC:
go get -u google.golang.org/grpc建立Go的projectgo-server-grpc然后将前面写的simple.proto放入项目proto的package中。 cd到proto目录执行如下命令
protoc --go_outpluginsgrpc:. simple.proto这样就将simple.proto编译成了Go语言对应的stub程序了。
随后我们就可以写我们server端的代码了main.go。 以下的代码都是模板代码main函数是socket使用Go的标准实现。作为开发者我们只关注远程服务提供的具体接口实现即可。 我们可以在生成的simple.pb.go中发现需要实现的接口
// 客户端调用的接口
type SimpleClient interface {SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error)
}type simpleClient struct {cc grpc.ClientConnInterface
}func NewSimpleClient(cc grpc.ClientConnInterface) SimpleClient {return simpleClient{cc}
}func (c *simpleClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error) {out : new(HelloReplay)err : c.cc.Invoke(ctx, /Simple/SayHello, in, out, opts...)if err ! nil {return nil, err}return out, nil
}// 服务端需要实现的接口
type SimpleServer interface {SayHello(context.Context, *HelloRequest) (*HelloReplay, error)
}之后我们在main.go中实现接口
package mainimport (contextgrpc-server/proto//引入对应的包fmtnetloggoogle.golang.org/grpcgoogle.golang.org/grpc/reflection
)
//定义接下来要开放的socket的端口
const(port :50051
)type server struct{}func (s *server) SayHello(ctx context.Context,req *simple.HelloRequest) (*simple.HelloReplay, error){fmt.Println(req.Name)return simple.HelloReplay{Message:hello req.Name},nil
}之后填写main方法
func main() {//创建一个socket监听lis, err : net.Listen(tcp, port)if err ! nil {log.Fatal(fail to listen)}//新建一个grpc服务器s : grpc.NewServer()//使用 simple.RegisterSimpleServer 函数将实现了 SimpleServer 接口的 server 对象注册到 gRPC 服务器(s)上simple.RegisterSimpleServer(s, server{})//使用 reflection.Register 函数将 gRPC 服务器(s)注册到反射服务中。这样可以通过 gRPC 提供的工具来动态地查看和调用服务器上的服务。reflection.Register(s)//使用 s.Serve 方法启动 gRPC 服务器(s)开始接受来自客户端的连接请求并提供服务。如果启动过程中出现错误程序会输出一条错误信息并终止运行。if err : s.Serve(lis); err ! nil {log.Fatal(fail to server)}
}目前服务端已经完成了。
3.3 在Go端实现client
package mainimport (contextfmtsimple go-server-grpc/protologgoogle.golang.org/grpc
)const (address localhost:50051
)func main() {// 创建与服务器的连接conn, err : grpc.Dial(address, grpc.WithInsecure())if err ! nil {log.Fatalf(无法连接到服务器%v, err)}defer conn.Close()// 创建一个新的 gRPC 客户端client : simple.NewSimpleClient(conn)// 构建请求request : simple.HelloRequest{Name: John,}// 调用 gRPC 方法response, err : client.SayHello(context.Background(), request)if err ! nil {log.Fatalf(调用 gRPC 方法失败%v, err)}// 打印响应fmt.Println(response.Message)
}需要先启动服务端再启动客户端就可以看到效果。 输出helloJohn
4.下次预告
实现Java作为客户端调用go服务端的服务