新聞中心
關(guān)鍵要點(diǎn)
- 根據(jù)交互和溝通方式,我們可以將微服務(wù)分為兩類(lèi):面向外部的微服務(wù)和內(nèi)部微服務(wù)。
- RESTful API 是面向外部的微服務(wù)事實(shí)上的通信技術(shù)(REST 的普遍性和豐富的支持生態(tài)系統(tǒng)在其持續(xù)成功中發(fā)揮著至關(guān)重要的作用)。
- gRPC 是遠(yuǎn)程過(guò)程調(diào)用 (RPC) API 范式的一個(gè)相對(duì)較新的實(shí)現(xiàn)。它可以在內(nèi)部微服務(wù)之間的所有同步通信中發(fā)揮主要作用
- 在這里,我們通過(guò)使用真實(shí)世界的微服務(wù)用例來(lái)檢查關(guān)鍵 gRPC 概念、它們的用法以及將 gRPC 作為服務(wù)間通信的好處。
- 許多主要的編程語(yǔ)言都支持 gRPC。我們將討論使用 Ballerinalang 和 Golang 作為編程語(yǔ)言的示例實(shí)現(xiàn)。
在現(xiàn)代微服務(wù)架構(gòu)中,我們可以根據(jù)微服務(wù)的交互和通信將微服務(wù)分為兩大類(lèi)。第一組微服務(wù)充當(dāng)面向外部的微服務(wù),直接暴露給消費(fèi)者。它們主要是基于 HTTP 的 API,使用為外部開(kāi)發(fā)人員優(yōu)化的常規(guī)基于文本的消息傳遞有效負(fù)載(JSON、XML 等),并使用表示狀態(tài)傳輸 (REST) 作為事實(shí)上的通信技術(shù)。

創(chuàng)新互聯(lián)憑借專(zhuān)業(yè)的設(shè)計(jì)團(tuán)隊(duì)扎實(shí)的技術(shù)支持、優(yōu)質(zhì)高效的服務(wù)意識(shí)和豐厚的資源優(yōu)勢(shì),提供專(zhuān)業(yè)的網(wǎng)站策劃、做網(wǎng)站、成都做網(wǎng)站、網(wǎng)站優(yōu)化、軟件開(kāi)發(fā)、網(wǎng)站改版等服務(wù),在成都十余年的網(wǎng)站建設(shè)設(shè)計(jì)經(jīng)驗(yàn),為成都上千中小型企業(yè)策劃設(shè)計(jì)了網(wǎng)站。
REST 無(wú)處不在且豐富的生態(tài)系統(tǒng)在這些面向外部的微服務(wù)的成功中發(fā)揮著至關(guān)重要的作用。OpenAPI為描述、生成、使用和可視化這些 REST API 提供了定義明確的規(guī)范。API 管理系統(tǒng)可以很好地與這些 API 配合使用,并提供安全性、速率限制、緩存和貨幣化以及業(yè)務(wù)需求。GraphQL 可以替代基于 HTTP 的 REST API,但它超出了本文的范圍。
另一組微服務(wù)是內(nèi)部的,不與外部系統(tǒng)或外部開(kāi)發(fā)人員通信。這些微服務(wù)相互交互以完成一組給定的任務(wù)。內(nèi)部微服務(wù)使用同步或異步通信。在許多情況下,我們可以看到通過(guò) HTTP 使用 REST API 作為同步模式,但這并不是最好的技術(shù)。在本文中,我們將仔細(xì)研究如何利用二進(jìn)制協(xié)議(例如 gRPC),它可以成為服務(wù)間通信的優(yōu)化通信協(xié)議
什么是 gRPC?
gRPC 是一種用于服務(wù)間通信的相對(duì)較新的遠(yuǎn)程過(guò)程調(diào)用 (RPC) API 范例。與所有其他 RPC 一樣,它允許直接調(diào)用不同機(jī)器上的服務(wù)器應(yīng)用程序上的方法,就好像它是本地對(duì)象一樣。與Thrift 和Avro等其他二進(jìn)制協(xié)議相同,gRPC 使用接口描述語(yǔ)言 (IDL) 來(lái)定義服務(wù)契約。gRPC 使用最新的網(wǎng)絡(luò)傳輸協(xié)議 HTTP/2 作為默認(rèn)傳輸協(xié)議,與基于 HTTP/1.1 的 REST 相比,這使得 gRPC 快速且健壯。
您可以使用 Protocol Buffers定義 gRPC 服務(wù)契約, 其中每個(gè)服務(wù)定義指定具有預(yù)期輸入和輸出消息的方法的數(shù)量以及參數(shù)和返回類(lèi)型的數(shù)據(jù)結(jié)構(gòu)。使用主要編程語(yǔ)言提供的工具,可以使用定義服務(wù)合同的相同協(xié)議緩沖區(qū)文件生成服務(wù)器端框架和客戶(hù)端代碼(存根)。
gRPC 的實(shí)用微服務(wù)用例
圖 1:在線(xiàn)零售店微服務(wù)架構(gòu)的一部分
微服務(wù)架構(gòu)的主要好處之一是通過(guò)使用最合適的編程語(yǔ)言來(lái)構(gòu)建不同的服務(wù),而不是用一種語(yǔ)言構(gòu)建所有東西。圖 1 展示了在線(xiàn)零售店微服務(wù)架構(gòu)的一部分,其中在Ballerina (本文其余部分稱(chēng)為 Ballerina)和Golang中實(shí)現(xiàn)了四個(gè)微服務(wù) ,以提供在線(xiàn)零售店的一些功能。由于許多主流編程語(yǔ)言都支持 gRPC,所以當(dāng)我們定義服務(wù)契約時(shí),可以使用非常適合的編程語(yǔ)言來(lái)實(shí)現(xiàn)。
讓我們?yōu)槊總€(gè)服務(wù)定義服務(wù)契約。
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;
清單 1:Order 微服務(wù)的服務(wù)契約 ( order.proto )
Order 微服務(wù)將獲取購(gòu)物項(xiàng)目和數(shù)量并返回小計(jì)。這里我使用 Ballerina gRPC 工具分別生成 gRPC 服務(wù)樣板代碼和存根/客戶(hù)端。
$ ballerina grpc --mode service --input proto/order.proto --output gen_code
這將生成 OrderService 服務(wù)器樣板代碼。
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;
|};
清單 2:生成的樣板代碼的代碼片段 ( OrderService_sample_service.bal )
gRPC 服務(wù)完美地映射到 Ballerina 的 service 類(lèi)型,gRPC rpc 映射到 Ballerina 的類(lèi)型, resource function gRPC 消息映射到 Ballerina 的record 類(lèi)型。
我為 Order 微服務(wù)創(chuàng)建了一個(gè)單獨(dú)的 Ballerina 項(xiàng)目,并使用生成的 OrderService 樣板代碼來(lái)實(shí)現(xiàn) gRPC 一元服務(wù)。
一元阻塞
OrderService 在 Cart 微服務(wù)中被調(diào)用。我們可以使用以下 Ballerina 命令來(lái)生成客戶(hù)端存根 和客戶(hù)端代碼。
$ ballerina grpc --mode client --input proto/order.proto --output gen_code
生成的客戶(hù)端存根具有阻塞和非阻塞遠(yuǎn)程方法。此示例代碼演示了 gRPC 一元服務(wù)如何與 gRPC 阻塞客戶(hù)端交互。
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];
}
}; 清單 3: 為阻塞模式生成的遠(yuǎn)程對(duì)象代碼片段
Ballerina 的遠(yuǎn)程方法抽象是一個(gè)非常適合的 gRPC 客戶(hù)端存根,您可以看到 UpdateOrder 調(diào)用代碼 非常干凈整潔。
Checkout 微服務(wù)通過(guò)匯總從 Cart 微服務(wù)收到的所有臨時(shí)訂單來(lái)發(fā)出最終賬單。在這種情況下,我們會(huì)將所有臨時(shí)訂單作為 stream Order 消息發(fā)送。
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;
}
清單 4:Checkout 微服務(wù)的服務(wù)合同 ( checkout.proto )
您可以使用該 ballerina grpc 命令為 checkout.proto 生成樣板代碼 。
$ ballerina grpc --mode service --input proto/checkout.proto --output gen_code
gRPC 客戶(hù)端流式傳輸
Cart 微服務(wù)(客戶(hù)端)流式消息作為流對(duì)象參數(shù)提供,可以使用循環(huán)進(jìn)行迭代,處理客戶(hù)端發(fā)送的每條消息。請(qǐng)參閱以下示例實(shí)現(xiàn):
service CheckoutService on ep {
resource function Checkout(grpc:Caller caller, stream clientStream) {
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"]);
}
}
} 清單 5:( CheckoutService_sample_service.bal )的Service 示例實(shí)現(xiàn)的代碼片段 CheckoutService
客戶(hù)端流完成后,將返回 grpc:EOS 錯(cuò)誤,該錯(cuò)誤可用于確定何時(shí)使用調(diào)用者對(duì)象向客戶(hù)端發(fā)送最終響應(yīng)消息(總計(jì))。
CheckoutService的示例客戶(hù)端代碼 和客戶(hù)端存根 可以使用以下命令生成:
$ ballerina grpc --mode client --input proto/checkout.proto --output gen_code
讓我們看一下 Cart 微服務(wù)的實(shí)現(xiàn)。Cart 微服務(wù)有兩個(gè) REST API — 一個(gè)用于將商品添加到購(gòu)物車(chē),另一個(gè)用于進(jìn)行最終結(jié)賬。將商品添加到購(gòu)物車(chē)時(shí),它會(huì)通過(guò)對(duì) Order 微服務(wù)進(jìn)行 gRPC 調(diào)用并將其存儲(chǔ)在內(nèi)存中,從而獲得帶有每個(gè)商品小計(jì)的臨時(shí)訂單。調(diào)用 Checkout 微服務(wù)會(huì)將所有存儲(chǔ)在內(nèi)存中的臨時(shí)訂單作為 gRPC 流發(fā)送到 Checkout 微服務(wù),并返回要支付的總金額。Ballerina 使用內(nèi)置的 Stream 類(lèi)型和客戶(hù)端對(duì)象抽象來(lái)實(shí)現(xiàn) gRPC 客戶(hù)端流。請(qǐng)參見(jiàn)圖 2,它說(shuō)明了 Ballerina 的客戶(hù)端流式傳輸是如何工作的。
圖 2:Ballerina gRPC 客戶(hù)端流式傳輸
CheckoutService 客戶(hù)端流的完整實(shí)現(xiàn)可以在 Cart 微服務(wù)結(jié)賬資源功能中找到。最后,在結(jié)賬過(guò)程中,對(duì) Golang 實(shí)現(xiàn)的 Stock 微服務(wù)進(jìn)行 gRPC 調(diào)用,并通過(guò)扣除已售商品來(lái)更新庫(kù)存。
grpc-網(wǎng)關(guān)
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;
清單 6:Stock 微服務(wù) ( stock.proto )的服務(wù)合同
在這種情況下,將通過(guò)使用 REST API 調(diào)用作為面向外部的 API 來(lái)調(diào)用相同的 UpdateStock 服務(wù),并通過(guò)使用 gRPC 調(diào)用作為服務(wù)間調(diào)用來(lái)調(diào)用。grpc-gateway 是 protoc 的插件,它讀取 gRPC 服務(wù)定義并生成一個(gè)反向代理服務(wù)器,將 RESTful JSON API 轉(zhuǎn)換為 gRPC。
圖 3:grpc 網(wǎng)關(guān)
grpc-gateway 可幫助您同時(shí)提供 gRPC 和 REST 風(fēng)格的 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
樣品運(yùn)行
克隆microservices-with-grpc git repo 并按照 README.md 說(shuō)明進(jìn)行操作。
結(jié)論
gRPC 相對(duì)較新,但其快速發(fā)展的生態(tài)系統(tǒng)和社區(qū)肯定會(huì)對(duì)微服務(wù)開(kāi)發(fā)產(chǎn)生影響。由于 gRPC 是一個(gè)開(kāi)放標(biāo)準(zhǔn),所有主流編程語(yǔ)言都支持它,因此非常適合在多語(yǔ)言微服務(wù)環(huán)境中工作。作為一般實(shí)踐,我們可以使用 gRPC 進(jìn)行內(nèi)部微服務(wù)之間的所有同步通信,也可以使用 grpc-gateway 等新興技術(shù)將其公開(kāi)為 REST 風(fēng)格的 API。除了我們?cè)诒疚闹杏懻摰膬?nèi)容之外,諸如 Deadlines、 Cancellation、 Channels和 xDS 支持等 gRPC 功能 將為開(kāi)發(fā)人員構(gòu)建有效的微服務(wù)提供強(qiáng)大的功能和靈活性。
當(dāng)前名稱(chēng):使用gRPC、Ballerina和Go構(gòu)建有效的微服務(wù)
網(wǎng)頁(yè)鏈接:http://www.5511xx.com/article/dpgspcp.html


咨詢(xún)
建站咨詢(xún)
