溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Grpc 跨語(yǔ)言遠(yuǎn)程調(diào)用 python demo

發(fā)布時(shí)間:2020-07-18 07:30:34 來(lái)源:網(wǎng)絡(luò) 閱讀:1885 作者:聽砜 欄目:編程語(yǔ)言

grpc介紹

gRPC 一開始由 google 開發(fā),是一款語(yǔ)言中立、平臺(tái)中立、開源的遠(yuǎn)程過(guò)程調(diào)用(RPC)系統(tǒng)。

在 gRPC 里客戶端應(yīng)用可以像調(diào)用本地對(duì)象一樣直接調(diào)用另一臺(tái)不同的機(jī)器上服務(wù)端應(yīng)用的方法,使得您能夠更容易地創(chuàng)建分布式應(yīng)用和服務(wù)。與許多 RPC 系統(tǒng)類似,gRPC 也是基于以下理念:定義一個(gè)服務(wù),指定其能夠被遠(yuǎn)程調(diào)用的方法(包含參數(shù)和返回類型)。在服務(wù)端實(shí)現(xiàn)這個(gè)接口,并運(yùn)行一個(gè) gRPC 服務(wù)器來(lái)處理客戶端調(diào)用。在客戶端擁有一個(gè)存根能夠像服務(wù)端一樣的方法。因?yàn)?gRPC 對(duì) HTTP/2 協(xié)議的支持使其在 Android、IOS 等客戶端后端服務(wù)的開發(fā)領(lǐng)域具有良好的前景。gRPC 提供了一種簡(jiǎn)單的方法來(lái)定義服務(wù),同時(shí)客戶端可以充分利用 HTTP2 stream 的特性,從而有助于節(jié)省帶寬、降低 TCP 的連接次數(shù)、節(jié)省CPU的使用等。

Grpc 跨語(yǔ)言遠(yuǎn)程調(diào)用  python demo

特性

  • 基于HTTP/2

    • HTTP/2 提供了連接多路復(fù)用、雙向流、服務(wù)器推送、請(qǐng)求優(yōu)先級(jí)、首部壓縮等機(jī)制??梢怨?jié)省帶寬、降低TCP鏈接次數(shù)、節(jié)省CPU,幫助移動(dòng)設(shè)備延長(zhǎng)電池壽命等。gRPC 的協(xié)議設(shè)計(jì)上使用了HTTP2 現(xiàn)有的語(yǔ)義,請(qǐng)求和響應(yīng)的數(shù)據(jù)使用HTTP Body 發(fā)送,其他的控制信息則用Header 表示。
  • IDL使用ProtoBuf

    • gRPC使用ProtoBuf來(lái)定義服務(wù),ProtoBuf是由Google開發(fā)的一種數(shù)據(jù)序列化協(xié)議(類似于XML、JSON、hessian)。ProtoBuf能夠?qū)?shù)據(jù)進(jìn)行序列化,并廣泛應(yīng)用在數(shù)據(jù)存儲(chǔ)、通信協(xié)議等方面。壓縮和傳輸效率高,語(yǔ)法簡(jiǎn)單,表達(dá)力強(qiáng)。
  • 多語(yǔ)言支持 ( C, C++, Python, PHP, Nodejs, C#, Objective-C、Golang、Java)

    • gRPC支持多種語(yǔ)言,并能夠基于語(yǔ)言自動(dòng)生成客戶端和服務(wù)端功能庫(kù)。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它語(yǔ)言的版本正在積極開發(fā)中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等語(yǔ)言,grpc-java已經(jīng)支持Android開發(fā)。

gRPC已經(jīng)應(yīng)用在Google的云服務(wù)和對(duì)外提供的API中,其主要應(yīng)用場(chǎng)景如下:

  • 低延遲、高擴(kuò)展性、分布式的系統(tǒng)
  • 云服務(wù)器進(jìn)行通信的移動(dòng)應(yīng)用客戶端
  • 設(shè)計(jì)語(yǔ)言獨(dú)立、高效、精確的新協(xié)議
  • 便于各方面擴(kuò)展的分層設(shè)計(jì),如認(rèn)證、負(fù)載均衡、日志記錄、監(jiān)控等
gRPC優(yōu)缺點(diǎn):
優(yōu)點(diǎn):

protobuf二進(jìn)制消息,性能好/效率高(空間和時(shí)間效率都很不錯(cuò))
proto文件生成目標(biāo)代碼,簡(jiǎn)單易用
序列化反序列化直接對(duì)應(yīng)程序中的數(shù)據(jù)類,不需要解析后在進(jìn)行映射(XML,JSON都是這種方式)
支持向前兼容(新加字段采用默認(rèn)值)和向后兼容(忽略新加字段),簡(jiǎn)化升級(jí)
支持多種語(yǔ)言(可以把proto文件看做IDL文件)

Netty等一些框架集成

缺點(diǎn):
  • GRPC尚未提供連接池,需要自行實(shí)現(xiàn)

  • 尚未提供“服務(wù)發(fā)現(xiàn)”、“負(fù)載均衡”機(jī)制

  • 因?yàn)榛贖TTP2,絕大部多數(shù)HTTP Server、Nginx都尚不支持,即Nginx不能將GRPC請(qǐng)求作為HTTP請(qǐng)求來(lái)負(fù)載均衡,而是作為普通的TCP請(qǐng)求。(nginx1.9版本已支持)

  • Protobuf二進(jìn)制可讀性差(貌似提供了Text_Fromat功能)
  • 默認(rèn)不具備動(dòng)態(tài)特性(可以通過(guò)動(dòng)態(tài)定義生成消息類型或者動(dòng)態(tài)編譯支持)
grpc坑:

http2只允許單個(gè)鏈接傳輸10億流數(shù)據(jù)。原因在于:? htt2使用31位×××標(biāo)示流,服務(wù)端使用奇數(shù),客戶端使用偶數(shù),所以總共10億可用

解決思路:超過(guò)一定數(shù)量的流,需要重啟鏈接。

gRPC通信方式

gRPC有四種通信方式:

1、 Simple RPC

簡(jiǎn)單rpc? 這就是一般的rpc調(diào)用,一個(gè)請(qǐng)求對(duì)象對(duì)應(yīng)一個(gè)返回對(duì)象?

proto語(yǔ)法:

rpc simpleHello(Person) returns (Result) {}
2、 Server-side streaming RPC

服務(wù)端流式rpc? 一個(gè)請(qǐng)求對(duì)象,服務(wù)端可以傳回多個(gè)結(jié)果對(duì)象?

proto語(yǔ)法 :

rpc serverStreamHello(Person) returns (stream Result) {}
3、 Client-side streaming RPC

客戶端流式rpc? 客戶端傳入多個(gè)請(qǐng)求對(duì)象,服務(wù)端返回一個(gè)響應(yīng)結(jié)果?

proto語(yǔ)法 :

rpc clientStreamHello(stream Person) returns (Result) {}
4、 Bidirectional streaming RPC

雙向流式rpc? 結(jié)合客戶端流式rpc和服務(wù)端流式rpc,可以傳入多個(gè)對(duì)象,返回多個(gè)響應(yīng)對(duì)象?

proto語(yǔ)法 :

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

服務(wù)定義及ProtoBuf

gRPC使用ProtoBuf定義服務(wù), 我們可以一次性的在一個(gè) .proto 文件中定義服務(wù)并使用任何支持它的語(yǔ)言去實(shí)現(xiàn)客戶端和服務(wù)器,反過(guò)來(lái),它們可以在各種環(huán)境中,從云服務(wù)器到你自己的平板電腦—— gRPC 幫你解決了不同語(yǔ)言及環(huán)境間通信的復(fù)雜性。使用 protocol buffers 還能獲得其他好處,包括高效的序列號(hào),簡(jiǎn)單的 IDL 以及容易進(jìn)行接口更新。

安裝:

gRPC 的安裝: pip install grpcio

安裝 ProtoBuf 相關(guān)的 python 依賴庫(kù): pip install protobuf

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

demo

新建data.proto文件,定義傳輸?shù)臄?shù)據(jù)格式和grpc服務(wù)要實(shí)現(xiàn)的函數(shù)

syntax = "proto3";
package example;

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

生成proto數(shù)據(jù)的python調(diào)用格式和grpc服務(wù)接口

在proto文件目錄下 調(diào)用下列命令

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

會(huì)生成:data_pb2.py 與 data_pb2_grpc.py, 其中data_pb2.py是數(shù)據(jù)格式調(diào)用的文件,data_pb2_grpc.py是grpc傳輸協(xié)議接口調(diào)用的文件.

創(chuàng)建實(shí)現(xiàn)了grpc傳輸協(xié)議的服務(wù)器端

在服務(wù)器端代碼中需要實(shí)現(xiàn)proto文件中編寫的服務(wù)接口,并重寫處理函數(shù),將重寫后的服務(wù)類實(shí)例化以后添加到grpc服務(wù)器中,這樣創(chuàng)建的grpc服務(wù)器就可以實(shí)現(xiàn)自定義的proto傳輸服務(wù)了

# 實(shí)現(xiàn)了 server 端用于接收客戶端發(fā)送的數(shù)據(jù),并對(duì)數(shù)據(jù)進(jìn)行大寫處理后返回給客戶端

# ! /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

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

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

def serve():
    # 定義服務(wù)器并設(shè)置最大連接數(shù),corcurrent.futures是一個(gè)并發(fā)庫(kù),類似于線程池的概念
    grpcServer = grpc.server(futures.ThreadPoolExecutor(max_workers=4))  # 創(chuàng)建一個(gè)服務(wù)器
    data_pb2_grpc.add_FormatDataServicer_to_server(FormatData(), grpcServer)  # 在服務(wù)器中添加派生的接口服務(wù)(自己實(shí)現(xiàn)了處理函數(shù))
    grpcServer.add_insecure_port(_HOST + ':' + _PORT)  # 添加監(jiān)聽端口
    grpcServer.start()  # 啟動(dòng)服務(wù)器
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        grpcServer.stop(0)  # 關(guān)閉服務(wù)器

if __name__ == '__main__':
    serve()

創(chuàng)建實(shí)現(xiàn)能識(shí)別proto數(shù)據(jù)類和實(shí)現(xiàn)grpc傳輸協(xié)議.

# 實(shí)現(xiàn)了客戶端用于發(fā)送數(shù)據(jù)并打印接收到 server 端處理后的數(shù)據(jù)

# ! /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)  # 監(jiān)聽頻道
    print(conn)
    client = data_pb2_grpc.FormatDataStub(channel=conn)  # 客戶端使用Stub類發(fā)送請(qǐng)求,參數(shù)為頻道,為了綁定鏈接
    print(client)
    data = {'name': 'xjt', 'age': 18}
    response = client.DoFormat(data_pb2.actionrequest(text=json.dumps(data)))  # 返回的結(jié)果就是proto中定義的類
    print("received: " + response.text)

if __name__ == '__main__':
    run()

客戶端鏈接的主機(jī)號(hào)和端口號(hào),必須是服務(wù)器創(chuàng)建的主機(jī)號(hào)和端口號(hào).

先運(yùn)行服務(wù)端,在運(yùn)行客戶端,結(jié)果如下:

client.py

Grpc 跨語(yǔ)言遠(yuǎn)程調(diào)用  python demo

server.py

Grpc 跨語(yǔ)言遠(yuǎn)程調(diào)用  python demo

最終目錄結(jié)構(gòu)

Grpc 跨語(yǔ)言遠(yuǎn)程調(diào)用  python demo

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI