gRPC-網絡現狀及測試

本文主要介紹了gRPC,網絡現狀及測試的簡介,好很差用等相關內容。
上篇文章回顧:
golang中的切片操做

                                gRPC是什麼?

gRPC是谷歌開源的一款不那麼快的基於原型緩衝區的RPC框架。

既然不那麼快,爲何還要提它呢?相較於節儉,gRPC會慢一點,可是,本文的着眼點並不在於RPC吞吐量的極限值,也不是框架的通訊時間減小几十幾千納秒,本文要介紹的是除GraphQL外,JSON RPC優化的另外一個取向--gRPCweb。

衆所周知,GraphQL着眼的優化點在於經過移交一部分查詢的邏輯到客戶端,從而減小了數據的交換量,而RPC則着眼於使用可壓縮的二進制/文本協議,減小JSON文本傳輸帶來的沒必要要的協議損失。本文着眼於此,對比gRPCweb當前的進展,對易用性,便捷性,成本方面進行了評價,結論雖然有些武斷,可是仍然反映了當前gRPCweb仍然有待進一步發展的事實。

01gRPC web能給咱們帶來什麼?

1. 傳輸數據量減小,傳輸延遲下降

HTTP / 2天生具備頭壓縮等特性,解決了大量頻繁的RPC交互通訊帶來的頭部重複傳輸問題;使用二進制流或壓縮文本傳輸,減小了一部分稀疏編碼帶來的字節空洞,提升了信息密度。傳輸速度更快,數據量更小,不只下降成本,並且能夠減小延遲。
golang

2.可靠一致的API設計

客戶端服務端使用相同的原文件進行接口定義,雙方接口暴露徹底相同,一致性更強,相較於傳統的招搖接口管理,其數據結構更加直觀精確,再也不須要維護接口-URL間的複雜對應關係,API升級管理更加簡單

3.對傳輸基礎設施無感知的通訊協議

節儉不能推出相似gRPCweb的方案的緣由也正在於此.Thrift使用私有Tprotocol傳輸協議,與gRPC的HTTP / 2相比起來通用性大打折扣,Nginx的在最新的穩定版中已經提供了grpc_pass負載均衡支持,咱們能夠無痛使用原有的四層/七層負載均衡器提供大規模的調用支持

4.高效的序列化/反序列化支持

gRPC相較於JSON,擁有更高的序列化/反序列化效率,易於實現更高的吞吐性能

02
gRPC web能不能用?好很差用?

話很少說,接下來咱們就開始進行一套gRPCserver + envoy代理+ gRPCweb on TypeScript的echo通訊測試,做爲對比,筆者將實現一套一樣功能的websocket鏈路,用以測試雙方通訊性能,比較這些功能的實現難度並評價兩種「看似比較底層」的網絡通信協議。

                                 gRPC網站測試

首先定義一個咱們的回聲服務的原型:

syntax = "proto3";package chatman;


message ChatRequest {
    string messages = 1;
}


message ChatResponse {
    string messages = 1;
}


service Chat {    rpc chat (ChatRequest) returns (ChatResponse);
}複製代碼

而後寫服務器端代碼,此處使用的Python的實現:

生成服務器端的protobuf的的文件,使用gRPC工具生成代碼便可,而後咱們引入grpcio和這些的protobuf的庫文件:

import grpcimport service_pb2,service_pb2_grpc
from concurrent.futures import ThreadPoolExecutorimport time


class ChatServicer(service_pb2_grpc.ChatServicer):
    def chat(self,request,context):        print(request.messages)
        return service_pb2.ChatResponse(messages="Server Received: %s" % request.messages)def server_start():
    server = grpc.server(ThreadPoolExecutor(max_workers=5))
    service_pb2_grpc.add_ChatServicer_to_server(ChatServicer(),server)
    server.add_insecure_port('0.0.0.0:8800')
    server.start()
    time.sleep(3600*24)if __name__ == '__main__':
server_start()複製代碼

咱們先測試下HTTP / 2二進制流模式的gRPC:

Python中的代碼以下:

import grpcimport service_pb2_grpcimport service_pb2


channel = grpc.insecure_channel('0.0.0.0:8800')
stub = service_pb2_grpc.ChatStub(channel)


message = service_pb2.ChatRequest(messages="test message")
msg = stub.chat(message)
print(msg)複製代碼

返回消息:「Server Received:test message」。測試成功,抓包結果以下:

能夠看到,兩方使用「不安全「的HTTP協議交換了數據,通訊成功完成。

接下來,咱們使用gRPC的網絡實現相同功能。值得注意的一點是,目前gRPC幅還不能直接運行在瀏覽器上,由於瀏覽器還沒有提供裸HTTP協議的接口,所以須要進行一層簡單的封裝,並經過代理剝去這層封裝才能與真正的gRPC後端通訊,這種通訊方式被稱爲gRPC的網頁文本。

同理,使用gRPC的工具生成打字稿文件,生成文件包含一個原始的JS庫,一個描述文件以及一個TS客戶端庫,編寫代碼:

import { ChatRequest,ChatResponse } from './service_pb'import { ChatClient } from './ServiceServiceClientPb'const client1 = new ChatClient("http://127.0.0.1:8001",{},{});

let req = new ChatRequest()

req.setMessages("messages")

client1.chat(req,{},(err: any, res)=>{

    console.log(res);

});複製代碼

在HTML中直接引用這個JS,並使用特使代理進行gRPC的網頁文本到gRPC協議的轉換,配置以下:

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }


static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 127.0.0.1, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  cluster: echo_service
                  max_grpc_timeout: 0s
              cors:
                allow_origin:
                - "*"
                allow_methods: GET, PUT, DELETE, POST, OPTIONS
                allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
                max_age: "1728000"
                expose_headers: custom-header-1,grpc-status,grpc-message
                enabled: true
          http_filters:
          - name: envoy.grpc_web
          - name: envoy.cors
          - name: envoy.router
  clusters:
  - name: echo_service
    connect_timeout: 0.25s
    type: logical_dns
    http2_protocol_options: {}
    lb_policy: round_robin
hosts: [{ socket_address: { address: 127.0.0.1, port_value: 8800 }}]複製代碼

如今進行測試,訪問剛纔的網頁,能夠看到通訊狀況:

一看就知道是的的base64編碼,果斷解碼:

果真不出所料,是一個封裝在HTTP裏的HTTP通信

                                Web Socket的測試

接下來,使用的WebSocket的進行對比:

編寫服務端程序:

console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server
    , wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
        ws.on('message', function(message) {
        console.log('Received: %s', message);
        ws.send('Server received: ' + message);
    });
 });複製代碼

使用節點啓動後,在瀏覽器的控制檯裏鏈接並訪問:

const ws_echo = new WebSocket("ws://127.0.0.1:8081/")
ws_echo.addEventListener('message', (event) => {
    console.log(event.data);
})
ws_echo.send("Hello!")複製代碼

控制檯返回服務器收到:您好!

通訊完成,查看協議:

能夠看到,通過一次通訊後,服務器直接返回升級升級鏈接的報頭,隨後雙方使用的WebSocket的進行通訊,比起gRPC的協議,更加簡易直白。

                                       結論

在測試前我一直在思考,gRPCweb到底是一個怎樣的存在第一眼看到gRPCweb文本這個詞,個人第一感受是這個?

在Gmail中的郵箱裏,充滿了這種極其相似的的protobuf的XHR請求,當看到須要使用專用代理進行轉發的時候,我一度覺得是這種高度壓縮的文本協議正式出如今了通用的框架裏,然而事實是,不管是gRPC-web仍是gRPCweb-text,不管是易用性仍是請求響應體長度,比起jon over brotli over websocket都仍然有很大的進步空間,要實現經過CDN分發js節省API服務器帶寬的構思目前仍然須要本身造輪子,gRPCweb並非銀彈,至少目前不是。

本文首發於公衆號」小米運維「,點擊查看原文web

相關文章
相關標籤/搜索