取得領先
VMware 提供培訓和認證,以加速您的進度。
了解更多從 3.1.0 版本開始,作為 Spring Cloud 2021.0.0(又名 Jubilee)發布列車的一部分,Spring Cloud Gateway 包含對 gRPC 和 HTTP/2 的支援。
我們將介紹 gRPC 背後的基本概念,以及如何透過兩個範例進行配置
其中一個範例展示了 Spring Cloud Gateway 如何透明地重新路由 gRPC 流量,而無需了解 proto 定義,也無需修改現有的 gRPC 伺服器。
另一個範例展示了我們如何在 Spring Cloud Gateway 中建立自定義過濾器,以將 JSON payload 轉換為 gRPC 訊息。
HTTP/2 使我們的應用程式更快、更簡單、更穩健。 透過啟用請求和回應多工、新增 HTTP header 欄位的有效壓縮,以及新增對請求優先順序和伺服器推送的支援,來減少延遲。
減少連線數對於改善 HTTPS 的效能尤其重要:這樣我們就可以減少昂貴的 TLS 交握、更有效地重複使用 session,並減少用戶端和伺服器資源。
HTTP/2 提供兩種機制來協商應用程式層級協定
H2C
HTTP/2.0 支援明文
H2
HTTP/2.0 支援 TLS
即使 reactor-netty
支援 H2C
明文協定,Spring Cloud Gateway 仍需要 H2
與 TLS 來確保傳輸安全性。
HTTP/2 新增了二進位框架層,這是 HTTP 訊息的封裝方式,並在用戶端和伺服器之間傳輸,從而能夠以更有效的方式傳輸資料。
感謝 reactor-netty 及其 HTTP/2 支援,我們才能夠擴展 Spring Cloud Gateway 以支援 gRPC。
gRPC 是一個高效能的遠端程序呼叫框架,可以在任何環境中運行。 它提供雙向串流,並且基於 HTTP/2。
gRPC 服務可以使用 Protocol Buffers(一種強大的二進位序列化工具集和語言)來定義,並提供用於跨不同語言產生用戶端和伺服器的工具。
為了在 Spring Cloud Gateway 中啟用 gRPC,我們需要在我們的專案中透過新增 keystore 來啟用 HTTP/2 和 SSL,這可以透過以下配置來完成
server:
http2:
enabled: true
ssl:
key-store-type: PKCS12
key-store: classpath:keystore.p12
key-store-password: password
key-password: password
enabled: true
現在我們已經啟用了它,我們可以建立一個 route,將流量重新導向到 gRPC 伺服器,並利用現有的過濾器和 predicates,例如,這個 route 會將來自任何以 grpc
開頭的路徑的流量重新導向到埠 6565
上的本機伺服器,並新增 header X-Request-header
,其值為 header-value
spring:
cloud:
gateway:
routes:
- id: grpc
uri: https://localhost:6565
predicates:
- Path=/grpc/**
filters:
- AddResponseHeader=X-Request-header, header-value
可以在此儲存庫中找到一個端到端範例,其中包含以下部分
grpc-server
,它公開一個 HelloService
和 gRPC 端點,以接收 HelloRequest
並返回 HelloResponse
syntax = "proto3";
message HelloRequest { string firstName = 1; string lastName = 2; }
message HelloResponse { string greeting = 1; }
service HelloService { rpc hello(HelloRequest) returns (HelloResponse); }
伺服器將把問候語與 firstName
和 lastName
連接起來,並以 greeting
回應。
例如,這個輸入
firstName: Saul
lastName: Hudson
將輸出
greeting: Hello, Saul Hudson
一個 grpc-client
,負責將 HelloRequest
發送到 HelloService
。
grpc-simple-gateway
路由請求並新增具有上述配置的 header。 請注意,此 gateway 應用程式沒有任何對 gRPC 或用戶端和伺服器使用的 proto 定義的依賴性。
目前只有一個 route 會將所有內容轉發到 grpc-server
routes:
- id: grpc
uri: https://localhost:6565
predicates:
- Path=/**
filters:
- AddResponseHeader=X-Request-header, header-value
要啟動將監聽請求的伺服器
./gradlew :grpc-server:bootRun
然後,我們啟動將重新路由 gRPC 請求的 gateway
./gradlew :grpc-simple-gateway:bootRun
最後,我們可以使用指向 gateway 應用程式的用戶端
./gradlew :grpc-client:bootRun
gateway 的 routes 和過濾器可以在 grpc-simple-gateway/src/main/resources/application.yaml 中修改
感謝 Spring Cloud Gateway 的靈活性,可以建立自定義過濾器,以將 JSON payload 轉換為 gRPC 訊息。
即使它會對效能產生影響,因為我們必須在 gateway 中序列化和反序列化請求並從中建立通道,但如果您想要公開 JSON API 同時保持內部相容性,這是一種常見的模式。
為此,我們可以擴展我們的 grpc-json-gateway
,以包含具有我們要傳送的訊息的 proto
定義。
Spring Cloud Gateway 包含一種建立自定義過濾器的機制,允許我們攔截請求並向其中新增自定義邏輯。
對於這種特定情況,我們將反序列化 JSON 請求並建立一個 gRPC 通道,該通道會將訊息傳送到 grpc-server
。
static class GRPCResponseDecorator extends ServerHttpResponseDecorator {
@Override
public Mono<Void> writeWith(Publisher<?extends DataBuffer> body) {
exchange.getResponse().getHeaders().set("Content-Type", "application/json");
URI requestURI = exchange.getRequest().getURI();
ManagedChannel channel = createSecuredChannel(requestURI.getHost(), 6565);
return getDelegate().writeWith(deserializeJSONRequest()
.map(jsonRequest -> {
String firstName = jsonRequest.getFirstName();
String lastName = jsonRequest.getLastName();
return HelloServiceGrpc.newBlockingStub(channel)
.hello(HelloRequest.newBuilder()
.setFirstName(firstName)
.setLastName(lastName)
.build());
})
.map(this::serialiseJSONResponse)
.map(wrapGRPCResponse())
.cast(DataBuffer.class)
.last());
}
}
完整的實作可以在這裡找到: grpc-json-gateway/src/main/java/com/example/grpcserver/hello/JSONToGRPCFilterFactory.java
使用相同的 grpc-server
,我們可以使用以下命令啟動具有自定義過濾器的 gateway
./gradlew :grpc-json-gateway:bootRun
並使用例如 curl
將 JSON 請求發送到 grpc-json-gateway
curl -XPOST 'https://localhost:8091/json/hello' -d '{"firstName":"Duff","lastName":"McKagan"}' -k -H"Content-Type: application/json" -v
我們看到 gateway 應用程式如何轉發請求並以新的 Content-Type
header 返回 JSON payload
< HTTP/2 200
< content-type: application/json
< content-length: 34
<
* Connection #0 to host localhost left intact
{"greeting":"Hello, Duff McKagan"}
在這篇文章中,我們看了一些 gRPC 如何整合到 Spring Cloud Gateway 中的範例。 我很想知道您發現的其他用法在您的經驗中很有幫助。