gRPC詳解


gRPC詳解

 
pip install grpcio

pip install grpcio-tools
https://grpc.io/docs/languages/python/quickstart/

gRPC是什么?

gRPC是什么可以用官網的一句話來概括

A high-performance, open-source universal RPC framework

所謂RPC(remote procedure call 遠程過程調用)框架實際是提供了一套機制,使得應用程序之間可以進行通信,而且也遵從server/client模型。使用的時候客戶端調用server端提供的接口就像是調用本地的函數一樣。如下圖所示就是一個典型的RPC結構圖。

 
RPC通信

gRPC有什么好處以及在什么場景下需要用gRPC

既然是server/client模型,那么我們直接用restful api不是也可以滿足嗎,為什么還需要RPC呢?下面我們就來看看RPC到底有哪些優勢

gRPC vs. Restful API

gRPC和restful API都提供了一套通信機制,用於server/client模型通信,而且它們都使用http作為底層的傳輸協議(嚴格地說, gRPC使用的http2.0,而restful api則不一定)。不過gRPC還是有些特有的優勢,如下:

  • gRPC可以通過protobuf來定義接口,從而可以有更加嚴格的接口約束條件
  • 另外,通過protobuf可以將數據序列化為二進制編碼,這會大幅減少需要傳輸的數據量,從而大幅提高性能。
  • gRPC可以方便地支持流式通信(理論上通過http2.0就可以使用streaming模式, 但是通常web服務的restful api似乎很少這么用,通常的流式數據應用如視頻流,一般都會使用專門的協議如HLS,RTMP等,這些就不是我們通常web服務了,而是有專門的服務器應用。)

使用場景

  • 需要對接口進行嚴格約束的情況,比如我們提供了一個公共的服務,很多人,甚至公司外部的人也可以訪問這個服務,這時對於接口我們希望有更加嚴格的約束,我們不希望客戶端給我們傳遞任意的數據,尤其是考慮到安全性的因素,我們通常需要對接口進行更加嚴格的約束。這時gRPC就可以通過protobuf來提供嚴格的接口約束。
  • 對於性能有更高的要求時。有時我們的服務需要傳遞大量的數據,而又希望不影響我們的性能,這個時候也可以考慮gRPC服務,因為通過protobuf我們可以將數據壓縮編碼轉化為二進制格式,通常傳遞的數據量要小得多,而且通過http2我們可以實現異步的請求,從而大大提高了通信效率。

但是,通常我們不會去單獨使用gRPC,而是將gRPC作為一個部件進行使用,這是因為在生產環境,我們面對大並發的情況下,需要使用分布式系統來去處理,而gRPC並沒有提供分布式系統相關的一些必要組件。而且,真正的線上服務還需要提供包括負載均衡,限流熔斷,監控報警,服務注冊和發現等等必要的組件。不過,這就不屬於本篇文章討論的主題了,我們還是先繼續看下如何使用gRPC。

gRPC HelloWorld實例詳解

gRPC的使用通常包括如下幾個步驟:

  1. 通過protobuf來定義接口和數據類型
  2. 編寫gRPC server端代碼
  3. 編寫gRPC client端代碼
    下面來通過一個實例來詳細講解上述的三步。
    下邊的hello world實例完成之后,其目錄結果如下:

     
     
    project helloworld

定義接口和數據類型

  • 通過protobuf定義接口和數據類型
syntax = "proto3";

package rpc_package;

// define a service
service HelloWorldService {
    // define the interface and data type
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// define the data type of request
message HelloRequest {
    string name = 1;
}

// define the data type of response
message HelloReply {
    string message = 1;
}
  • 使用gRPC protobuf生成工具生成對應語言的庫函數
python -m grpc_tools.protoc -I=./protos --python_out=./rpc_package --grpc_python_out=./rpc_package ./protos/helloworld.proto

這個指令會自動生成rpc_package文件夾中的helloworld_pb2.pyhelloworld_pb2_grpc.py,但是不會自動生成__init__.py文件,需要我們手動添加

關於protobuf的詳細解釋請參考Google Protobuf簡明教程

gRPC server端代碼

# -*- coding: utf-8 -*-
# @Time : 2021/7/8 14:15
# @Author : ward
# @File : hello_server.py


from concurrent import futures
import grpc
import logging
import time

from rpc_package.helloworld_pb2_grpc import add_HelloWorldServiceServicer_to_server, \
HelloWorldServiceServicer
from rpc_package.helloworld_pb2 import HelloRequest, HelloReply


class Hello(HelloWorldServiceServicer):

# 這里實現我們定義的接口
def SayHello(self, request, context):
print(request.name)
return HelloReply(message='Hello, %s!' % request.name)


def serve():
# 這里通過thread pool來並發處理server的任務
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
# 將對應的任務處理函數添加到rpc server中
add_HelloWorldServiceServicer_to_server(Hello(), server)

# 這里使用的非安全接口,世界gRPC支持TLS/SSL安全連接,以及各種鑒權機制
server.add_insecure_port('[::]:50000')
server.start()
try:
while True:
time.sleep(60 * 60 * 24)
except KeyboardInterrupt:
server.stop(0)


if __name__ == "__main__":
logging.basicConfig()
serve()

gRPC client端代碼

# -*- coding: utf-8 -*-
# @Time : 2021/7/8 14:16
# @Author : ward
# @File : hello_client.py


from __future__ import print_function
import logging

import grpc
from rpc_package.helloworld_pb2 import HelloRequest, HelloReply
from rpc_package.helloworld_pb2_grpc import HelloWorldServiceStub


def run():
# 使用with語法保證channel自動close
with grpc.insecure_channel('localhost:50000') as channel:
# 客戶端通過stub來實現rpc通信
stub = HelloWorldServiceStub(channel)

# 客戶端必須使用定義好的類型,這里是HelloRequest類型
response = stub.SayHello(HelloRequest(name='eric'))
print("hello client received: " + response.message)


if __name__ == "__main__":
logging.basicConfig()
run()

演示

先執行server端代碼

python hello_server.py

接着執行client端代碼如下:

➜  grpc_test python hello_client.py
hello client received: Hello, eric!

References

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM