NGINX 官方博客正式宣布 NGINX 支持原生的 gPRC

NGINX 官方博客正式宣佈 NGINX 支持原生的 gPRC,現在就可以從代碼倉庫拉取快照版本。該特性將會被包含在 NGINX OSS 1.13.10、NGINX Plus R15 以及 NGINX 1.13.9 當中。

NGINX 已經能夠代理 gRPC TCP 連接,用戶可以用它:

  • 發佈 gRPC 服務,並應用 NGINX 提供的 HTTP/2 TLS 加密機制、速率限定、基於 IP 的訪問控制以及日誌等功能。

  • 在單個端點上發佈多個 gRPC 服務,使用 NGINX 檢查方法調用,將各個方法調用路由到相應的服務上。

  • 對一組 gRPC 服務進行負載均衡,可以使用輪詢算法、最少連接數原則或其他方式在集群上分發流量。

什麼是 gRPC?

gRPC 是一種遠程過程調用協議,用於客戶端和服務器端之間的通信。gRPC 緊湊小巧,跨多種編程語言,同時支持請求與響應式的交互方式和流式交互方式。gRPC 因其跨語言特性和簡潔的設計變得越來越流行,其中服務網格的實現就使用了 gRPC。

NGINX 官方博客正式宣佈 NGINX 支持原生的 gPRC

gRPC 通過 HTTP/2 傳輸數據,可以傳輸明文文本數據和 TLS 加密過的數據。gRPC 調用是通過 HTTP POST 請求來實現的,每個請求裡包含了一個編碼過的消息體(protocol buffer 是默認的編碼方式)。gRPC 的響應消息裡也包含一個編碼過的消息體,並在消息尾部帶上狀態碼。

gRPC 不能通過 HTTP 進行傳輸,而必須使用 HTTP/2,這是因為要充分利用 HTTP/2 連接的多路複用和流式特性。

通過 NGINX 來管理 gRPC 服務

下面的示例對 gRPC 的 Hello World 快速入門教程進行了修改,用它來創建一個簡單的客戶端到服務器端應用。例子中提供了 NGINX 的配置信息,而把應用程序的實現留給讀者,不過文中還是會給出一些提示。

1、暴露簡單的 gRPC 服務

首先,在客戶端和服務器端之間安插 NGINX,NGINX 為服務器端的應用程序提供了一個穩定可靠的網關。

NGINX 官方博客正式宣佈 NGINX 支持原生的 gPRC

然後開始部署包含了 gRPC 更新包的 NGINX。如果要從源代碼開始編譯 NGINX,要記得把 http_ssl 和 http_v2 兩個模塊包含進去:

$ auto/configure --with-http_ssl_module —with-http_v2_module

NGINX 使用一個 HTTP 服務器來監聽 gRPC 流量,並使用 grpc_pass 指令來代理 gRPC 流量。像下面的配置那樣,在 80 端口上監聽未加密的 gRPC 流量,並把請求重定向到 50051 端口上:

http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent"'; server { listen 80 http2; access_log logs/access.log main; location / { # Replace localhost:50051 with the address and port of your gRPC server # The 'grpc://' prefix is optional; unencrypted gRPC is the default  grpc_pass grpc://localhost:50051; } }}

要確保 grpc_pass 的地址是正確的。然後重新編譯客戶端,讓它指向 NGINX 的 IP 地址和端口。

在運行新的客戶端時,可以看到與之前一樣的響應消息,不過這時 NGINX 會終斷和轉發事務。這個可以從訪問日誌中看出來:

$ tail logs/access.log192.168.20.1 - - [01/Mar/2018:13:35:02 +0000] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-go/1.11.0-dev"192.168.20.1 - - [01/Mar/2018:13:35:02 +0000] "POST /helloworld.Greeter/SayHelloAgain HTTP/2.0" 200 24 "-" “grpc-go/1.11.0-dev"

要注意,NGINX 不支持在同一個明文(非 TLS)端口上同時使用 HTTP/1 和 HTTP/2,如果一定要同時使用兩種版本的協議,需要分別為它們創建不同的端口。

2、發佈基於 TLS 的 gRPC 服務

Hello World 快速入門教程使用的是未加密的 HTTP/2,這樣方便測試和部署,但要部署到生產環境就不能這麼簡單了。可以通過 NGINX 來增加一個加密層:

NGINX 官方博客正式宣佈 NGINX 支持原生的 gPRC

創建一個自簽名的證書對,然後修改 NGINX 服務器的配置如下:

server { listen 1443 ssl http2; ssl_certificate ssl/cert.pem; ssl_certificate_key ssl/key.pem; #...}

讓 gRPC 客戶端使用 TLS,連接到 1443 端口,並禁用證書檢查——這在使用自簽名證書或未經信任的證書時是一個必要的步驟。例如,如果使用了 Go 語言編寫的示例,就需要導入 crypto/tls 和 google.golang.org/grpc/credentials,並修改 grpc.Dial() 方法:

creds := credentials.NewTLS( &tls.Config{ InsecureSkipVerify: true } )// 記得修改地址,使用新的端口conn, err := grpc.Dial( address, grpc.WithTransportCredentials( creds ) )

這樣就可以加密 gRPC 流量了。在部署到生產環境時,需要將自簽名證書換成由可信任證書機構發佈的證書,客戶端也需要配置成信任該證書。

3、代理加密的 gRPC 服務

有時候可能需要在內部對 gRPC 流量進行加密,那麼就要修改服務器端應用程序的配置,把原先監聽未加密(grpc)連接改為監聽 TLS 加密(grpcs)連接。

cer, err := tls.LoadX509KeyPair( "cert.pem", "key.pem" )config := &tls.Config{ Certificates: []tls.Certificate{cer} }lis, err := tls.Listen( "tcp", port, config )

在 NGINX 的配置裡,需要將 grpc-pass 配置成上游服務器的地址:

# Use grpcs for TLS-encrypted gRPC trafficgrpc_pass grpcs://localhost:50051;

4、路由 gRPC 流量

如果同時存在多個 gRPC 服務,並且每個服務是由不同的服務器應用程序提供的,那麼該怎麼辦?如果能夠將這些服務通過單個 TLS 端點暴露出來是不是更好?

NGINX 官方博客正式宣佈 NGINX 支持原生的 gPRC

在 NGINX 裡,可以對服務和它的方法稍作修改,然後使用 location 指令來路由流量。gRPC 的請求 URL 是使用包名、服務名和方法名來生成的。比如這個叫作 SayHello 的 RPC 方法:

package helloworld;service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {}}

調用這個方法就會生成一個 POST 請求,URL 是 /helloworld.Greeter/SayHello,這個可以從日誌中看出來:

192.168.20.1 - - [01/Mar/2018:13:35:02 +0000] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" “grpc-go/1.11.0-dev"

要使用 NGINX 來路由流量,可以這樣配置:

location /helloworld.Greeter { grpc_pass grpc://192.168.20.11:50051;}location /helloworld.Dispatcher { grpc_pass grpc://192.168.20.21:50052;}location / { root html; index index.html index.htm;}

6、對 gRPC 流量進行負載均衡

那麼該如何增加 gRPC 服務的容量,以便提供高可用性?

可以使用 NGINX 的 upstream 組:

upstream grpcservers { server 192.168.20.21:50051; server 192.168.20.22:50052;}server { listen 1443 ssl http2; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; location /helloworld.Greeter { grpc_pass grpc://grpcservers; error_page 502 = /error502grpc; } location = /error502grpc { internal; default_type application/grpc; add_header grpc-status 14; add_header grpc-message "unavailable"; return 204; }}

當然,如果上游監聽的是 TLS 端口,可以使用 grpc_pass grpcs://upstreams。

NGINX 支持多種負載均衡算法,其內置的健康檢測機制可以檢測到無法及時響應或發生錯誤的服務器,並把它們移除。如果沒有可用的服務器,就會返回 /error502grpc 指定的錯誤消息。


分享到:


相關文章: