微服务:一套小的服务通过通讯机制互联。
RPC:远程调用,想本地函数一样调用另外一个程序的函数。
RPC go的实现:net/rpc,基于http和tcp协议,使用gob解编码仅支持golang。
net/rpc/jsonrpc,基于tcp 协议,支持多用语言。
grpc:使用protobuf协议进行rpc调用,在HTTP2支持多路复用,支持跨语言。
grpc使用:用protobuf声明gRPC服务定义、生成服务器端骨架和客户端存根、
然后实现服务的业务逻辑、
我只简单的使用过golang的内置库net/rpc做个golang多个服务之间的调用。
《gRPC与云原生应用开发》
微服务
微服务概述
微服务架构
- 微服务架构下数据交互一般是对内 RPC,对外 REST
- 将业务按功能模块拆分到各个微服务,具有提高项目协作效率、降低模块耦合度、提高系统可用性等优点,但是开发门槛比较高,比如 RPC 框架的使用、后期的服务监控等工作
- 一般情况下,我们会将功能代码在本地直接调用,微服务架构下,我们需要将这个函数作为单独的服务运行,客户端通过网络调用
在中国,使用 Go 语言开发微服务的趋势非常明显,得益于 Go 语言在并发处理、简洁性和性能方面的优势。针对 Go 语言的微服务框架,以下是几个在中国使用较为广泛的:
gRPC:gRPC 是一个高性能、通用的开源RPC框架,由 Google 主导开发。它使用 Protocol Buffers 作为接口定义语言,支持多种语言,能够在不同语言的应用程序之间提供强大的跨语言服务。在中国,gRPC 被许多公司用于构建微服务架构。
Go-Micro:Go-Micro 是一个易于使用的 Go 微服务框架,致力于简化微服务的开发。它提供了服务发现、负载均衡、故障转移、同步通信(RPC)和异步通信(消息传递)等核心功能。Go-Micro 因其简洁性和强大的功能,在中国的 Go 微服务领域受到了广泛的欢迎。
Gin:虽然 Gin 主要是一个 HTTP Web 框架,但由于其高性能和易用性,许多开发者将其用于微服务的开发,特别是在构建 HTTP API 服务方面。Gin 提供了一个简洁的 API,可以轻松地与其他 Go 微服务框架或库集成,实现微服务架构。
Dubbo-Go:受到 Java 版本 Dubbo 的启发,Dubbo-Go 是 Alibaba 为 Go 语言开发的高性能和轻量级的 RPC 框架。它支持多种协议,提供服务发现、负载均衡、容错等功能,适合构建大型的微服务架构。Dubbo-Go 在中国得到了许多公司和开发者的青睐。
Kitex:由字节跳动开源的 Kitex 是一个高性能和强大的 Go 微服务框架,专注于通信性能和服务治理。Kitex 支持多种 RPC 协议和消息格式,提供服务发现、负载均衡、熔断、限流等微服务必需功能。Kitex 的性能和可扩展性使其在中国的 Go 微服务领域受到关注。
Kratos:Kratos 是 Bilibili 开源的一款 Go 微服务框架,它提供了完整的服务治理解决方案,包括服务发现、配置管理、消息通信等功能。Kratos 设计了一套微服务框架规范,旨在帮助开发者构建可维护和可扩展的服务。
RPC
RPC概述
RPC(Remote Procedure Call)是一种是一种通信模式。
它允许一个程序调用另一个程序上的函数或过程,就像调用本地函数一样,而不需要开发者显式地处理底层网络通信细节。
Go中如何实现RPC
golang中实现RPC非常简单,官方提供了封装好的库,还有一些第三方的库
golang官方的net/rpc库使用encoding/gob进行编解码,支持tcp和http数据传输方式,由于其他语言不支持gob编解码方式,所以golang的RPC只支持golang开发的服务器与客户端之间的交互
官方还提供了net/rpc/jsonrpc库实现RPC方法,jsonrpc采用JSON进行数据编解码,因而支持跨语言调用,目前jsonrpc库是基于tcp协议实现的,暂不支持http传输方式
net/rpc
客户端代码
package main
import (
"fmt" // 用于格式化输出
"log" // 用于记录错误日志
"net/rpc" // 用于RPC(远程过程调用)通信
)
// ArithRequest 定义了请求的结构,包括两个整数 A 和 B
type ArithRequest struct {
A, B int
}
// ArithResponse 定义了返回给客户端的结果结构
type ArithResponse struct {
Pro int // 乘积
Quo int // 商
Rem int // 余数
}
func main() {
// 使用rpc.DialHTTP连接到服务器,":8000"是服务器地址
conn, err := rpc.DialHTTP("tcp", ":8000")
if err != nil {
log.Fatal(err) // 连接失败时记录错误并退出
}
// 初始化请求数据
req := ArithRequest{9, 2}
var res ArithResponse // 用于存储响应的结果
// 调用远程的Arith.Multiply方法
err2 := conn.Call("Arith.Multiply", req, &res)
if err2 != nil {
log.Fatal(err2) // 调用失败时记录错误并退出
}
// 输出乘法结果
fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
// 调用远程的Arith.Divide方法
err3 := conn.Call("Arith.Divide", req, &res)
if err3 != nil {
log.Fatal(err3) // 调用失败时记录错误并退出
}
// 输出除法结果,包括商和余数
fmt.Printf("%d / %d 商 %d,余数 = %d\n", req.A, req.B, res.Quo, res.Rem)
}
服务端代码
package main
import (
"errors" // 用于创建错误信息
"log" // 用于记录日志
"net/http" // 用于HTTP服务器
"net/rpc" // 用于RPC通信
)
// Arith 结构体没有成员,仅用于注册为RPC服务的方法的容器
type Arith struct{}
// ArithRequest 定义了客户端请求的结构体,包括两个整数 A 和 B
type ArithRequest struct {
A, B int
}
// ArithResponse 定义了返回给客户端的结果结构体
type ArithResponse struct {
Pro int // 乘积
Quo int // 商
Rem int // 余数
}
// Multiply 是Arith的方法,执行乘法操作
func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B // 将乘积结果赋值给响应结构体的Pro字段
return nil
}
// Divide 是Arith的方法,执行除法操作
func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
if req.B == 0 {
return errors.New("除数不能为0") // 如果除数为0,返回错误信息
}
// 正常情况下,计算商和余数
res.Quo = req.A / req.B // 商
res.Rem = req.A % req.B // 余数
return nil
}
// 主函数
func main() {
// 创建Arith的实例
rect := new(Arith)
// 注册Arith服务,使其方法可以通过RPC调用
rpc.Register(rect)
// 将RPC服务绑定到HTTP协议
rpc.HandleHTTP()
// 监听并在8000端口提供HTTP服务 并通过 HTTP 协议接收 RPC 调用
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal(err) // 如果启动服务失败,则记录错误信息并退出程序
}
}
net/rpc/jsonrpc
grpc框架
grpc概述
grpc概述
gRPC(gRPC Remote Procedure Call):gRPC 是一个开源的 RPC 框架,它构建在HTTP/2之上,服务间使用高效的protobuf协议进行RPC调用,使用 Protocol Buffers(ProtoBuf)进行消息序列化。
gRPC 提供了一种强类型、高效和多语言支持的远程通信机制。
它不仅支持基本的 RPC 调用,还支持流式传输和双向流式传输等高级通信模式。
gRPC的优势
提供高效的进程间通信:gRPC没有使用JSON或XML这样的文本化格式,而是使用一个基于protocol buffers的二进制协议与gRPC服务和客户端通信。同时,gRPC在HTTP/2之上实现了protocol buffers,从而能够更快地处理进程间通信。
具有简单且定义良好的服务接口和模式:
属于强类型:
支持多语言:gRPC支持多种编程语言。基于protocol buffers的服务定义是语言中立的。
支持双工流:
gRPC的劣势
gRPC可能不太适合面向外部的服务:
巨大的服务定义变更是复杂的开发流程:
gRPC生态系统相对较小:浏览器和移动应用程序对gRPC的支持依然处于初级阶段。
RPC和GRPC的区别
RPC 是一种通用的远程通信模式,而 gRPC 是一个特定的 RPC 框架,它使用了一些现代化的技术和标准来实现高性能、跨语言的远程调用。开发者可以选择使用标准的 RPC 实现,也可以选择使用 gRPC 这种更高级、更现代化的远程调用框架,具体取决于项目需求和技术栈。
grpc运行配置
1. protoc下载
下载链接:Releases · protocolbuffers/protobuf · GitHub
2. protoc-gen-go下载
下载:go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
最后在GOPATH/bin中看到protoc-gen-go.exe文件说明安装成功。
注意
go env 配置成win才能生成exe文件
把生成的protoc-gen-go.exe文件放到生成服务GOROOT里面运行
3. 生成
-I 参数: -I 参数应该指定包含 .proto 文件的目录。确保 -I 后面跟的是包含 .proto 文件的目录路径,而不是 .proto 文件的完整路径。
--go_out 参数: --go_out 参数应该指定生成 Go 代码的输出目录。确保你有权限在指定的目录中写入文件。
protoc -I=D:\study\go\study_go\go\grpc --go_out=. D:\study\go\study_go\go\grpc\user.proto
注意
生成到当前目录上
grpc使用
如何使用protocol buffers声明gRPC服务定义、生成服务器端骨架和客户端存根、
实现服务的业务逻辑、
在gRPC服务器上运行我们实现的服务并通过gRPC客户端应用程序调用该服务。
2.1 创建服务定义
开发gRPC应用程序时,要先定义服务接口,其中包含允许远程调用的方法、方法参数以及调用这些方法所使用的消息格式等。这些服务定义都以protobuffers定义的形式进行记录,也就是gRPC中所使用的接口定义语言。
2.1.1 定义消息类型
消息(message)是客户端和服务器端交换的数据结构。
2.1.2 定义服务类型
服务(service)是暴露给客户端的远程方法集合。
syntax="proto3"; ➊
package ecommerce; ➋
option go_package = "/proto";
service ProductInfo { ➌
rpc addProduct(Product) returns (ProductID); ➍
rpc getProduct(ProductID) returns (Product); ➎
}
message Product { ➏
string id=1; ➐
string name=2;
string description=3;
}
message ProductID { ➑
string value=1;
}
注意
PS D:\study\go\study_go\go\grpc> protoc -I=D:\study\go\study_go\go\grpc --go_out=. D:\study\go\study_go\go\grpc\a.proto
protoc-gen-go: unable to determine Go import path for "a.proto"
Please specify either:
• a "go_package" option in the .proto source file, or
• a "M" argument on the command line.See https://protobuf.dev/reference/go/go-generated#package for more information.
--go_out: protoc-gen-go: Plugin failed with status code 1.
加入option go_package = "/proto"; 指定生成文件名称
2.2 实现
- 客户端存根(Stubs):这是客户端使用的代码,包含了调用服务方法的函数。客户端可以通过这些存根像调用本地函数一样发起 RPC 调用。
- 服务器端骨架(Skeletons):这是服务端的代码基础,定义了服务接口的实现框架。开发者需要在此基础上填充具体的业务逻辑。
实现Go服务分为3步:首先,生成服务定义的存根文件;其次,实现该服务中远程方法的业务逻辑;最后,创建服务器,监听特定的端口并注册该服务,从而接受来自客户端的请求。
生成客户端存根或服务器端骨架。现在,使用protocol buffers编译器来手动生成客户端存根或服务器端骨架。
实现业务逻辑。首先需要在Go模块(productinfo/service)中创建名为productinfo_service.go的Go文件,然后实现如代码清单2-6所示的远程方法。
package main
import (
"context"
"errors"
"log"
"github.com/gofrs/uuid"
pb "productinfo/service/ecommerce" ➊
)
// 用来实现ecommerce/product_info的服务器
type server struct{ ➋
productMap map[string]*pb.Product
}
// 实现ecommerce.AddProduct的AddProduct方法
func (s *server) AddProduct(ctx context.Context,
in *pb.Product) (*pb.ProductID, error) { ➌➎➏
out, err:=uuid.NewV4()
if err !=nil {
return nil, status.Errorf(codes.Internal,
"Error while generating Product ID", err)
}
in.Id=out.String()
if s.productMap==nil {
s.productMap=make(map[string]*pb.Product)
}
s.productMap[in.Id]=in
return &pb.ProductID{Value: in.Id}, status.New(codes.OK, "").Err()
}
// 实现ecommerce.GetProduct的GetProduct方法
func (s *server) GetProduct(ctx context.Context, in *pb.ProductID)
(*pb.Product, error) { ➍➎➏
value, exists:=s.productMap[in.Value]
if exists {
return value, status.New(codes.OK, "").Err()
}
return nil, status.Errorf(codes.NotFound, "Product does not exist.", in.Value)
}
创建Go服务器。要用Go语言创建服务器,需要在相同的Go包(productinfo/service)中创建名为main.go的新Go文件,并实现如代码清单2-7所示的main方法。
package main
import (
"log"
"net"
pb "productinfo/service/ecommerce" ➊
"google.golang.org/grpc"
)
const (
port=":50051"
)
func main() {
lis, err:=net.Listen("tcp", port) ➋
if err !=nil {
log.Fatalf("failed to listen: %v", err)
}
s:=grpc.NewServer() ➌
pb.RegisterProductInfoServer(s, &server{}) ➍
log.Printf("Starting gRPC listener on port "+port)
if err:=s.Serve(lis); err !=nil { ➎
log.Fatalf("failed to serve: %v", err)
}
}
第3章 gRPC的通信模式
第1章和第2章介绍了gRPC进程间通信技术的基础知识,其中还涉及构建简单的gRPC应用程序。到目前为止,我们已经完成了定义服务接口、实现服务、运行gRPC服务器以及通过gRPC客户端应用程序远程调用服务等操作。客户端和服务器端之间的通信模式是简单的请求–响应风格的通信,这里每个请求都会得到一个响应。但是,借助gRPC,可以实现不同的进程间通信模式(也称RPC风格),而不仅仅是简单的请求–响应模式
gRPC应用程序的4种基础通信模式:一元RPC、服务器端流RPC、客户端流RPC以及双向流RPC
3.2 服务器端流RPC模式
在一元RPC模式中,gRPC服务器端和gRPC客户端在通信时始终只有一个请求和一个响应。在服务器端流RPC模式中,服务器端在接收到客户端的请求消息后,会发回一个响应的序列。
3.3 客户端流RPC模式
在客户端流RPC模式中,客户端会发送多个请求给服务器端,而不再是单个请求。服务器端则会发送一个响应给客户端。但是,服务器端不一定要等到从客户端接收到所有消息后才发送响应。
3.4 双向流RPC模式
在双向流RPC模式中,客户端以消息流的形式发送请求到服务器端,服务器端也以消息流的形式进行响应。

810

被折叠的 条评论
为什么被折叠?



