在现代微服务架构中,我们可以根据微服务的交互和通信将微服务分为两大类。第一组微服务充当面向外部的微服务,直接暴露给消费者。它们主要是基于 HTTP 的 API,使用为外部开发人员优化的常规基于文本的消息传递有效负载(JSON、XML 等),并使用表示状态传输 (REST) 作为事实上的通信技术。
创新互联凭借专业的设计团队扎实的技术支持、优质高效的服务意识和丰厚的资源优势,提供专业的网站策划、做网站、成都做网站、网站优化、软件开发、网站改版等服务,在成都十余年的网站建设设计经验,为成都上千中小型企业策划设计了网站。
REST 无处不在且丰富的生态系统在这些面向外部的微服务的成功中发挥着至关重要的作用。OpenAPI为描述、生成、使用和可视化这些 REST API 提供了定义明确的规范。API 管理系统可以很好地与这些 API 配合使用,并提供安全性、速率限制、缓存和货币化以及业务需求。GraphQL 可以替代基于 HTTP 的 REST API,但它超出了本文的范围。
另一组微服务是内部的,不与外部系统或外部开发人员通信。这些微服务相互交互以完成一组给定的任务。内部微服务使用同步或异步通信。在许多情况下,我们可以看到通过 HTTP 使用 REST API 作为同步模式,但这并不是最好的技术。在本文中,我们将仔细研究如何利用二进制协议(例如 gRPC),它可以成为服务间通信的优化通信协议
gRPC 是一种用于服务间通信的相对较新的远程过程调用 (RPC) API 范例。与所有其他 RPC 一样,它允许直接调用不同机器上的服务器应用程序上的方法,就好像它是本地对象一样。与Thrift 和Avro等其他二进制协议相同,gRPC 使用接口描述语言 (IDL) 来定义服务契约。gRPC 使用最新的网络传输协议 HTTP/2 作为默认传输协议,与基于 HTTP/1.1 的 REST 相比,这使得 gRPC 快速且健壮。
您可以使用 Protocol Buffers定义 gRPC 服务契约, 其中每个服务定义指定具有预期输入和输出消息的方法的数量以及参数和返回类型的数据结构。使用主要编程语言提供的工具,可以使用定义服务合同的相同协议缓冲区文件生成服务器端框架和客户端代码(存根)。
图 1:在线零售店微服务架构的一部分
微服务架构的主要好处之一是通过使用最合适的编程语言来构建不同的服务,而不是用一种语言构建所有东西。图 1 展示了在线零售店微服务架构的一部分,其中在Ballerina (本文其余部分称为 Ballerina)和Golang中实现了四个微服务 ,以提供在线零售店的一些功能。由于许多主流编程语言都支持 gRPC,所以当我们定义服务契约时,可以使用非常适合的编程语言来实现。
让我们为每个服务定义服务契约。
syntax="proto3";
package retail_shop;
service OrderService {
rpc UpdateOrder(Item) returns (Order);
}
message Item {
string itemNumber = 1;
int32 quantity = 2;
}
message Order {
string itemNumber = 1;
int32 totalQuantity = 2;
float subTotal = 3;
Order 微服务将获取购物项目和数量并返回小计。这里我使用 Ballerina gRPC 工具分别生成 gRPC 服务样板代码和存根/客户端。
$ ballerina grpc --mode service --input proto/order.proto --output gen_code
这将生成 OrderService 服务器样板代码。
import ballerina/grpc;
listener grpc:Listener ep = new (9090);
service OrderService on ep {
resource function UpdateOrder(grpc:Caller caller, Item value) {
// Implementation goes here.
// You should return an Order
}
}
public type Order record {|
string itemNumber = "";
int totalQuantity = 0;
float subTotal = 0.0;
|};
public type Item record {|
string itemNumber = "";
int quantity = 0;
|};
gRPC 服务完美地映射到 Ballerina 的 service 类型,gRPC rpc 映射到 Ballerina 的类型, resource function gRPC 消息映射到 Ballerina 的record 类型。
我为 Order 微服务创建了一个单独的 Ballerina 项目,并使用生成的 OrderService 样板代码来实现 gRPC 一元服务。
OrderService 在 Cart 微服务中被调用。我们可以使用以下 Ballerina 命令来生成客户端存根 和客户端代码。
$ ballerina grpc --mode client --input proto/order.proto --output gen_code
生成的客户端存根具有阻塞和非阻塞远程方法。此示例代码演示了 gRPC 一元服务如何与 gRPC 阻塞客户端交互。
public remote function UpdateOrder(Item req, grpc:Headers? headers = ()) returns ([Order, grpc:Headers]|grpc:Error) {
var payload = check self.grpcClient->blockingExecute("retail_shop.OrderService/UpdateOrder", req, headers);
grpc:Headers resHeaders = new;
anydata result = ();
[result, resHeaders] = payload;
return [result, resHeaders];
}
};
Ballerina 的远程方法抽象是一个非常适合的 gRPC 客户端存根,您可以看到 UpdateOrder 调用代码 非常干净整洁。
Checkout 微服务通过汇总从 Cart 微服务收到的所有临时订单来发出最终账单。在这种情况下,我们会将所有临时订单作为 stream Order 消息发送。
syntax="proto3";
package retail_shop;
service CheckoutService {
rpc Checkout(stream Order) returns (FinalBill) {}
}
message Order {
string itemNumber = 1;
int32 totalQuantity = 2;
float subTotal = 3;
}
message FinalBill {
float total = 1;
}
您可以使用该 ballerina grpc 命令为 checkout.proto 生成样板代码 。
$ ballerina grpc --mode service --input proto/checkout.proto --output gen_code
Cart 微服务(客户端)流式消息作为流对象参数提供,可以使用循环进行迭代,处理客户端发送的每条消息。请参阅以下示例实现:
service CheckoutService on ep {
resource function Checkout(grpc:Caller caller, streamclientStream) {
float totalBill = 0;
//Iterating through streamed messages here
error? e = clientStream.forEach(function(Order order) {
totalBill += order.subTotal;
});
//Once the client completes stream, a grpc:EOS error is returned to indicate it
if (e is grpc:EOS) {
FinalBill finalBill = {
total:totalBill
};
//Sending the total bill to the client
grpc:Error? result = caller->send(finalBill);
if (result is grpc:Error) {
log:printError("Error occurred when sending the Finalbill: " +
result.message() + " - " +result.detail()["message"]);
} else {
log:printInfo ("Sending Final Bill Total: " +
finalBill.total.toString());
}
result = caller->complete();
if (result is grpc:Error) {
log:printError("Error occurred when closing the connection: " +
result.message() +" - " +result.detail()["message"]);
}
}
//If the client sends an error instead it can be handled here
else if (e is grpc:Error) {
log:printError("An unexpected error occured: " + e.message() + " - " +
e.detail()["message"]);
}
}
}
客户端流完成后,将返回 grpc:EOS 错误,该错误可用于确定何时使用调用者对象向客户端发送最终响应消息(总计)。
CheckoutService的示例客户端代码 和客户端存根 可以使用以下命令生成:
$ ballerina grpc --mode client --input proto/checkout.proto --output gen_code
让我们看一下 Cart 微服务的实现。Cart 微服务有两个 REST API — 一个用于将商品添加到购物车,另一个用于进行最终结账。将商品添加到购物车时,它会通过对 Order 微服务进行 gRPC 调用并将其存储在内存中,从而获得带有每个商品小计的临时订单。调用 Checkout 微服务会将所有存储在内存中的临时订单作为 gRPC 流发送到 Checkout 微服务,并返回要支付的总金额。Ballerina 使用内置的 Stream 类型和客户端对象抽象来实现 gRPC 客户端流。请参见图 2,它说明了 Ballerina 的客户端流式传输是如何工作的。
图 2:Ballerina gRPC 客户端流式传输
CheckoutService 客户端流的完整实现可以在 Cart 微服务结账资源功能中找到。最后,在结账过程中,对 Golang 实现的 Stock 微服务进行 gRPC 调用,并通过扣除已售商品来更新库存。
syntax="proto3";
package retail_shop;
option go_package = "../stock;gen";
import "google/api/annotations.proto";
service StockService {
rpc UpdateStock(UpdateStockRequest) returns (Stock) {
option (google.api.http) = {
// Route to this method from POST requests to /api/v1/stock
put: "/api/v1/stock"
body: "*"
};
}
}
message UpdateStockRequest {
string itemNumber = 1;
int32 quantity = 2;
}
message Stock {
string itemNumber = 1;
int32 quantity = 2;
在这种情况下,将通过使用 REST API 调用作为面向外部的 API 来调用相同的 UpdateStock 服务,并通过使用 gRPC 调用作为服务间调用来调用。grpc-gateway 是 protoc 的插件,它读取 gRPC 服务定义并生成一个反向代理服务器,将 RESTful JSON API 转换为 gRPC。
图 3:grpc 网关
grpc-gateway 可帮助您同时提供 gRPC 和 REST 风格的 API。
以下命令生成Golang gRPC 存根:
protoc -I/usr/local/include -I. \
-I$GOROOT/src \
-I$GOROOT/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=plugins=grpc:. \
stock.proto
以下命令生成Golang grpc-gateway 代码:
protoc -I/usr/local/include -I. \
-I$GOROOT/src \
-I$GOROOT/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
stock.proto
以下命令生成stock.swagger.json:
protoc -I/usr/local/include -I. \
-I$GOROOT/src \
-I$GOROOT/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
-I$GOROOT/src \
--swagger_out=logtostderr=true:../stock/gen/. \
./stock.proto
克隆microservices-with-grpc git repo 并按照 README.md 说明进行操作。
gRPC 相对较新,但其快速发展的生态系统和社区肯定会对微服务开发产生影响。由于 gRPC 是一个开放标准,所有主流编程语言都支持它,因此非常适合在多语言微服务环境中工作。作为一般实践,我们可以使用 gRPC 进行内部微服务之间的所有同步通信,也可以使用 grpc-gateway 等新兴技术将其公开为 REST 风格的 API。除了我们在本文中讨论的内容之外,诸如 Deadlines、 Cancellation、 Channels和 xDS 支持等 gRPC 功能 将为开发人员构建有效的微服务提供强大的功能和灵活性。
文章标题:使用gRPC、Ballerina和Go构建有效的微服务
标题链接:http://www.shufengxianlan.com/qtweb/news13/487413.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联