Grpc 跨語言遠程調用 python demo

grpc介紹

gRPC 一開始由 google 開發,是一款語言中立、平臺中立、開源的遠程過程調用(RPC)系統。java

在 gRPC 裏客戶端應用能夠像調用本地對象同樣直接調用另外一臺不一樣的機器上服務端應用的方法,使得您可以更容易地建立分佈式應用和服務。與許多 RPC 系統相似,gRPC 也是基於如下理念:定義一個服務,指定其可以被遠程調用的方法(包含參數和返回類型)。在服務端實現這個接口,並運行一個 gRPC 服務器來處理客戶端調用。在客戶端擁有一個存根可以像服務端同樣的方法。由於 gRPC 對 HTTP/2 協議的支持使其在 Android、IOS 等客戶端後端服務的開發領域具備良好的前景。gRPC 提供了一種簡單的方法來定義服務,同時客戶端能夠充分利用 HTTP2 stream 的特性,從而有助於節省帶寬、下降 TCP 的鏈接次數、節省CPU的使用等。python

Grpc 跨語言遠程調用  python demo

特性

  • 基於HTTP/2 nginx

    • HTTP/2 提供了鏈接多路複用、雙向流、服務器推送、請求優先級、首部壓縮等機制。能夠節省帶寬、下降TCP連接次數、節省CPU,幫助移動設備延長電池壽命等。gRPC 的協議設計上使用了HTTP2 現有的語義,請求和響應的數據使用HTTP Body 發送,其餘的控制信息則用Header 表示。
  • IDL使用ProtoBuf json

    • gRPC使用ProtoBuf來定義服務,ProtoBuf是由Google開發的一種數據序列化協議(相似於XML、JSON、hessian)。ProtoBuf可以將數據進行序列化,並普遍應用在數據存儲、通訊協議等方面。壓縮和傳輸效率高,語法簡單,表達力強。
  • 多語言支持 ( C, C++, Python, PHP, Nodejs, C#, Objective-C、Golang、Java)後端

    • gRPC支持多種語言,並可以基於語言自動生成客戶端和服務端功能庫。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它語言的版本正在積極開發中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等語言,grpc-java已經支持Android開發。

gRPC已經應用在Google的雲服務和對外提供的API中,其主要應用場景以下: 服務器

  • 低延遲、高擴展性、分佈式的系統
  • 同雲服務器進行通訊的移動應用客戶端
  • 設計語言獨立、高效、精確的新協議
  • 便於各方面擴展的分層設計,如認證、負載均衡、日誌記錄、監控等

gRPC優缺點:

優勢:

protobuf二進制消息,性能好/效率高(空間和時間效率都很不錯)
proto文件生成目標代碼,簡單易用
序列化反序列化直接對應程序中的數據類,不須要解析後在進行映射(XML,JSON都是這種方式)
支持向前兼容(新加字段採用默認值)和向後兼容(忽略新加字段),簡化升級
支持多種語言(能夠把proto文件看作IDL文件) 併發

Netty等一些框架集成負載均衡

缺點:
  • GRPC還沒有提供鏈接池,須要自行實現 框架

  • 還沒有提供「服務發現」、「負載均衡」機制 分佈式

  • 由於基於HTTP2,絕大部多數HTTP Server、Nginx都尚不支持,即Nginx不能將GRPC請求做爲HTTP請求來負載均衡,而是做爲普通的TCP請求。(nginx1.9版本已支持)

  • Protobuf二進制可讀性差(貌似提供了Text_Fromat功能)
  • 默認不具有動態特性(能夠經過動態定義生成消息類型或者動態編譯支持)

grpc坑:

http2只容許單個連接傳輸10億流數據。緣由在於:  htt2使用31位×××標示流,服務端使用奇數,客戶端使用偶數,因此總共10億可用

解決思路:超過必定數量的流,須要重啓連接。

gRPC通訊方式

gRPC有四種通訊方式:

一、 Simple RPC

簡單rpc  這就是通常的rpc調用,一個請求對象對應一個返回對象 

proto語法:

rpc simpleHello(Person) returns (Result) {}

二、 Server-side streaming RPC

服務端流式rpc  一個請求對象,服務端能夠傳回多個結果對象 

proto語法 :

rpc serverStreamHello(Person) returns (stream Result) {}

三、 Client-side streaming RPC

客戶端流式rpc  客戶端傳入多個請求對象,服務端返回一個響應結果 

proto語法 :

rpc clientStreamHello(stream Person) returns (Result) {}

四、 Bidirectional streaming RPC

雙向流式rpc  結合客戶端流式rpc和服務端流式rpc,能夠傳入多個對象,返回多個響應對象 

proto語法 :

rpc biStreamHello(stream Person) returns (stream Result) {}

服務定義及ProtoBuf

gRPC使用ProtoBuf定義服務, 咱們能夠一次性的在一個 .proto 文件中定義服務並使用任何支持它的語言去實現客戶端和服務器,反過來,它們能夠在各類環境中,從雲服務器到你本身的平板電腦—— gRPC 幫你解決了不一樣語言及環境間通訊的複雜性。使用 protocol buffers 還能得到其餘好處,包括高效的序列號,簡單的 IDL 以及容易進行接口更新。

安裝:

gRPC 的安裝: pip install grpcio

安裝 ProtoBuf 相關的 python 依賴庫: pip install protobuf

安裝 python grpc 的 protobuf 編譯工具: pip install grpcio-tools

demo

新建data.proto文件,定義傳輸的數據格式和grpc服務要實現的函數

syntax = "proto3";
package example;

service FormatData {   //定義服務,用在rpc傳輸中
  rpc DoFormat(actionrequest) returns (actionresponse){}
}
message actionrequest {
  string text = 1;
}
message actionresponse{
  string text=1;
}

生成proto數據的python調用格式和grpc服務接口

在proto文件目錄下 調用下列命令

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./data.proto

會生成:data_pb2.py 與 data_pb2_grpc.py, 其中data_pb2.py是數據格式調用的文件,data_pb2_grpc.py是grpc傳輸協議接口調用的文件.

建立實現了grpc傳輸協議的服務器端

在服務器端代碼中須要實現proto文件中編寫的服務接口,並重寫處理函數,將重寫後的服務類實例化之後添加到grpc服務器中,這樣建立的grpc服務器就能夠實現自定義的proto傳輸服務了

# 實現了 server 端用於接收客戶端發送的數據,並對數據進行大寫處理後返回給客戶端

# ! /usr/bin/env python
# -*- coding: utf-8 -*-
import grpc
import time
from concurrent import futures
from example import data_pb2, data_pb2_grpc

_ONE_DAY_IN_SECONDS = 60 * 60 * 24
_HOST = 'localhost'
_PORT = '8080'
import json

# 實現一個派生類,重寫rpc中的接口函數.自動生成的grpc文件中比proto中的服務名稱多了一個Servicer
class FormatData(data_pb2_grpc.FormatDataServicer):
    # 重寫接口函數.輸入和輸出都是proto中定義的Data類型
    def DoFormat(self, request, context):
        str = request.text
        print(str, type(str))

        return data_pb2.actionresponse(text=json.dumps(str.upper()))  # 返回一個類實例

def serve():
    # 定義服務器並設置最大鏈接數,corcurrent.futures是一個併發庫,相似於線程池的概念
    grpcServer = grpc.server(futures.ThreadPoolExecutor(max_workers=4))  # 建立一個服務器
    data_pb2_grpc.add_FormatDataServicer_to_server(FormatData(), grpcServer)  # 在服務器中添加派生的接口服務(本身實現了處理函數)
    grpcServer.add_insecure_port(_HOST + ':' + _PORT)  # 添加監聽端口
    grpcServer.start()  # 啓動服務器
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        grpcServer.stop(0)  # 關閉服務器

if __name__ == '__main__':
    serve()

建立實現能識別proto數據類和實現grpc傳輸協議.

# 實現了客戶端用於發送數據並打印接收到 server 端處理後的數據

# ! /usr/bin/env python
# -*- coding: utf-8 -*-
import grpc
from example import data_pb2, data_pb2_grpc

_HOST = 'localhost'
_PORT = '8080'
import json

def run():
    conn = grpc.insecure_channel(_HOST + ':' + _PORT)  # 監聽頻道
    print(conn)
    client = data_pb2_grpc.FormatDataStub(channel=conn)  # 客戶端使用Stub類發送請求,參數爲頻道,爲了綁定連接
    print(client)
    data = {'name': 'xjt', 'age': 18}
    response = client.DoFormat(data_pb2.actionrequest(text=json.dumps(data)))  # 返回的結果就是proto中定義的類
    print("received: " + response.text)

if __name__ == '__main__':
    run()

客戶端連接的主機號和端口號,必須是服務器建立的主機號和端口號.

先運行服務端,在運行客戶端,結果以下:

client.py

Grpc 跨語言遠程調用  python demo

server.py

Grpc 跨語言遠程調用  python demo

最終目錄結構

Grpc 跨語言遠程調用  python demo

相關文章
相關標籤/搜索