承上启下
介绍完了Go怎么实现RESTFul api,不可避免的,今天必须得整一下rpc这个概念。rpc是什么呢,很多人都想把rpc和http一起对比,但是他们不是一个概念。RPC是一种思想,可以基于tcp,可以基于udp也可以基于http。我们详细学习下把。
开始学习
RPC,听起来是不是有点像“人品差”?别误会,这里的RPC可是“远程过程调用”的缩写,它可是一个让我们的代码能够隔空打牛、远程操控的神奇技能!
什么是RPC?
简单来说,RPC就是让你在本地调用一个函数,却能够远程执行另一台机器上的代码。想象一下,你在家里的沙发上按了一个遥控器,结果远在千里之外的咖啡机开始给你煮咖啡,是不是很神奇?RPC就是这么个神奇的“遥控器”。
Go如何实现RPC?
在Go语言中,实现RPC就跟泡方便面一样简单。以下是泡面的步骤:
- 准备调料包(定义服务):首先,你需要定义一个服务,也就是你的远程函数。这就像把调料包准备好,等着加水泡。
type HelloService struct{}
func (p *HelloService) Hello(request string, reply *string) error {
*reply = "hello, " + request
return nil
}
烧开水(注册服务):然后,你需要把服务注册到RPC服务器上,就像把调料包放进烧开的水里。
rpc.RegisterName("HelloService", new(HelloService))
泡方便面(启动服务器):接下来,启动RPC服务器,等待客户端调用。
lis, _ := net.Listen("tcp", ":1234")
rpc.Accept(lis)
品尝美味(调用服务):最后,客户端就可以远程调用你的服务了,就像品尝美味的方便面。
client, _ := rpc.Dial("tcp", "localhost:1234")
var reply string
err := client.Call("HelloService.Hello", "world", &reply)
grpc库的使用
说到RPC,怎能不提/grpc/这个库呢?它可是RPC界的“老干妈”,让RPC变得更加美味。
gRPC,这个由Google开发的高性能、开源的RPC框架。gRPC基于HTTP/2协议,使用Protocol Buffers作为接口定义语言,支持多种编程语言。以下是gRPC的详细介绍:
1. gRPC的特点
- 多语言支持:gRPC支持多种编程语言,包括C++、Java、Python、Go、Ruby、C#、Node.js等。
- 基于HTTP/2:gRPC使用HTTP/2作为传输协议,支持双向流、流控、头部压缩等特性,使得通信更加高效。
- 协议缓冲(Protocol Buffers):gRPC使用Protocol Buffers来定义服务接口和消息格式,它是一种轻量级的数据交换格式,可以跨平台和语言使用。
- 同步和异步:gRPC客户端提供了同步和异步的API,可以根据需要选择不同的调用方式。
- 负载均衡:gRPC原生支持负载均衡,可以通过名称解析来发现服务实例。
- 认证:gRPC支持多种认证机制,如SSL/TLS、JWT等。
2. gRPC的工作流程
定义服务:使用Protocol Buffers定义服务接口和消息类型。
syntax = "proto3"; service YourService { rpc YourMethod (YourRequest) returns (YourResponse); } message YourRequest { // request fields } message YourResponse { // response fields }
生成代码:使用Protocol Buffers编译器
protoc
生成服务端和客户端的代码。protoc --go_out=plugins=grpc:. your_service.proto
实现服务端:实现生成的服务端接口。
type server struct{} func (s *server) YourMethod(ctx context.Context, in *pb.YourRequest) (*pb.YourResponse, error) { // implement the method } func main() { lis, err := net.Listen("tcp", ":50051") if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterYourServiceServer(s, &server{}) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }
实现客户端:使用生成的客户端代码调用服务。
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() c := pb.NewYourServiceClient(conn) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := c.YourMethod(ctx, &pb.YourRequest{}) if err != nil { log.Fatalf("could not greet: %v", err) } log.Printf("Response: %s", r.GetField())
3. gRPC的四种调用类型
- 简单RPC:客户端发送一个请求到服务器,并等待响应,就像普通的函数调用。
- 服务器流式RPC:客户端发送一个请求到服务器,并获取一个流来读取一系列消息。客户端读取直到没有更多的消息。
- 客户端流式RPC:客户端写入一系列消息并发送到服务器,一旦客户端完成消息写入,它等待服务器读取这些消息并返回一个响应。
- 双向流式RPC:双方使用读写流发送一系列消息。两个流独立操作,因此客户端和服务器可以按照自己喜欢的顺序读写。
4. gRPC的安全性和认证
gRPC支持以下安全性措施:
- 传输安全性:通过TLS/SSL来保证传输过程中的数据加密。
- 认证:gRPC支持基于Token的认证机制,如OAuth 2.0。
- 权限和审计:可以通过中间件来添加权限检查和审计日志。
5. gRPC的负载均衡
gRPC支持以下负载均衡策略:
- 名称解析:gRPC客户端可以使用名称解析来发现服务实例。
- 轮询:简单的轮询策略,将请求轮流分配到不同的服务器。
- 基于权重的轮询:根据服务器的权重分配请求。
- 故障转移:在主服务器故障时,请求会被转发到备用服务器。
restful与rpc
通过以上的介绍,我们都了解RPC(远程过程调用)和HTTP(超文本传输协议)是完全不同的概念,我们反倒是可以跟Restful API进行对比,:
RPC与HTTP的区别:
1. 目的与设计哲学:
- RPC:旨在实现远程函数调用,让远程服务调用看起来像本地函数调用一样简单。
- HTTP:是一种用于传输超媒体文档的应用层协议,主要用于Web浏览器和服务器之间的通信。
2. 通信方式:
- RPC:通常采用二进制协议,数据传输效率较高。
- HTTP:采用文本格式(如JSON、XML),可读性较好,但传输效率相对较低。
3. 传输协议:
- RPC:可以使用多种传输协议,如TCP、UDP,甚至HTTP。
- HTTP:默认使用HTTP/1.1或HTTP/2,基于TCP。
4. 性能:
- RPC:通常提供更低的延迟和更高的吞吐量,因为它通常使用更高效的序列化/反序列化机制。
- HTTP:由于HTTP协议的文本特性,性能通常不如RPC。
5. 客户端和服务端实现:
- RPC:需要特定的客户端和服务端库来处理消息的序列化和反序列化。
- HTTP:可以直接使用标准的HTTP客户端和服务器,如Web浏览器和Web服务器。
RPC与RESTful API的优缺点:
RPC的优点:
- 性能:通常RPC框架提供更高效的序列化/反序列化机制,如Protocol Buffers或MessagePack,性能更优。
- 简单性:RPC让远程调用看起来像本地函数调用,开发体验更接近于本地编程。
- 强类型:许多RPC框架支持静态类型,有助于在编译时发现错误。
RPC的缺点:
- 耦合性:RPC可能导致客户端和服务端之间的强耦合,因为它们需要共享接口定义。
- 标准化:相比RESTful API,RPC的标准化程度较低,不同框架之间可能不兼容。
RESTful API的优点:
- 无状态:RESTful API是无状态的,有助于构建可伸缩的系统。
- 标准化:基于HTTP协议,有广泛的工具和库支持。
- 可缓存:HTTP的缓存机制可以用于优化性能。
RESTful API的缺点:
- 性能:由于HTTP的文本特性,性能可能不如二进制的RPC协议。
- 复杂性:对于复杂的操作,RESTful API可能需要多个请求来完成任务,而RPC可以一个调用完成。
总的来说,RPC和RESTful API各有适用场景。RPC更适合内部服务之间的通信,特别是对性能有高要求的场景。而RESTful API更适合面向资源的Web服务,尤其是需要被Web浏览器直接访问的场景。选择哪种协议取决于具体的应用需求、性能要求和开发团队的偏好。