What's gRPC?
gRPC is a modern open source high performance RPC framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.(gRPC是能夠在任何環境中運行的現代的開源高性能RPC框架。它能夠經過可插拔的支持來有效地鏈接數據中心內和跨數據中心的服務,以實現負載平衡,跟蹤,運行情況檢查和身份驗證。它也適用於分佈式計算的最後一英里,以將設備,移動應用程序和瀏覽器鏈接到後端服務。)
咱們能夠用一句話來歸納:A high-performance, open-source universal RPC framework
RPC(remote procedure call 遠程過程調用)框架實際是提供了一套機制,使得應用程序之間能夠進行通訊,並且也聽從server/client模型。使用的時候客戶端調用server端提供的接口就像是調用本地的函數同樣。java
so
在什麼狀況下須要使用gRPC呢?
須要對接口進行嚴格約束的狀況,好比咱們提供了一個公共的服務,不少人,甚至公司外部的人也能夠訪問這個服務,這時對於接口咱們但願有更加嚴格的約束,咱們不但願客戶端給咱們傳遞任意的數據,尤爲是考慮到安全性的因素,咱們一般須要對接口進行更加嚴格的約束。這時gRPC就能夠經過protobuf來提供嚴格的接口約束。
對於性能有更高的要求時。有時咱們的服務須要傳遞大量的數據,而又但願不影響咱們的性能,這個時候也能夠考慮gRPC服務,由於經過protobuf咱們能夠將數據壓縮編碼轉化爲二進制格式,一般傳遞的數據量要小得多,並且經過http2咱們能夠實現異步的請求,從而大大提升了通訊效率。
可是,一般咱們不會去單獨使用gRPC,而是將gRPC做爲一個部件進行使用,這是由於在生產環境,咱們面對大併發的狀況下,須要使用分佈式系統來去處理,而gRPC並無提供分佈式系統相關的一些必要組件。並且,真正的線上服務還須要提供包括負載均衡,限流熔斷,監控報jing,服務註冊和發現等等必要的組件。python
接下來開始gRPC的Hello World測試
gRPC的使用一般包括以下幾個步驟:
一、經過protobuf來定義接口和數據類型
二、編寫gRPC server端代碼
三、編寫gRPC client端代碼macos
我實在mac中使用的python,mac中自帶python2,由於須要,本身安裝了python3。
首先pip3 安裝grpc和protobufc#
(lxc) liuxuchong:untitled liuxuchong$ pip3 install grpcio Collecting grpcio Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out. (read timeout=15)")': /packages/0d/27/0413a5dffd7ddca4ea43cffd22f46ec2b26a5ed18c974e4448763e758a9b/grpcio-1.25.0-cp37-cp37m-macosx_10_9_x86_64.whl Downloading https://files.pythonhosted.org/packages/0d/27/0413a5dffd7ddca4ea43cffd22f46ec2b26a5ed18c974e4448763e758a9b/grpcio-1.25.0-cp37-cp37m-macosx_10_9_x86_64.whl (2.3MB) 100% |████████████████████████████████| 2.3MB 8.1kB/s Collecting six>=1.5.2 (from grpcio) Using cached https://files.pythonhosted.org/packages/65/26/32b8464df2a97e6dd1b656ed26b2c194606c16fe163c695a992b36c11cdf/six-1.13.0-py2.py3-none-any.whl Installing collected packages: six, grpcio Successfully installed grpcio-1.25.0 six-1.13.0 (lxc) liuxuchong:untitled liuxuchong$ pip3 install protobuf Collecting protobuf Downloading https://files.pythonhosted.org/packages/a5/c6/a8b6a74ab1e165f0aaa673a46f5c895af8780976880c98934ae82060356d/protobuf-3.10.0-cp37-cp37m-macosx_10_9_intel.whl (1.4MB) 100% |████████████████████████████████| 1.4MB 83kB/s Requirement already satisfied: setuptools in ./venv/lxc/lib/python3.7/site-packages/setuptools-40.8.0-py3.7.egg (from protobuf) (40.8.0) Requirement already satisfied: six>=1.9 in ./venv/lxc/lib/python3.7/site-packages (from protobuf) (1.13.0) Installing collected packages: protobuf Successfully installed protobuf-3.10.0
定義protobuf後端
下面定義一個簡單的protobuf文件,在其中聲明一個grpc服務。
建立一個proto目錄,並在其中建立grpchello.proto文件,以下內容。瀏覽器
syntax = "proto3"; package grpcDemo; message HelloRequest { string name = 1; } message HelloReply { string message = 1; } service gRPC { rpc SayHello (HelloRequest) returns (HelloReply) {} }
編譯protobuf安全
使用protobuf的編譯器,爲咱們生成python版本的Message定義和服務的架手腳。網絡
lxc) liuxuchong:untitled liuxuchong$ python -m grpc-tools.protoc -I./proto --python_out=. --grpc_python_out=. grpchello.proto /Users/liuxuchong/PycharmProjects/untitled/venv/lxc/bin/python: Error while finding module specification for 'grpc-tools.protoc' (ModuleNotFoundError: No module named 'grpc-tools')
提示咱們沒有安裝grpc-tools,用pip安裝一下併發
python3 -m pip install --user grpcio-toolsapp
而後在運行上面的命令
在當前目錄下,生成2個文件:
查看第一個文件,消息定義文件:
# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: grpchello.proto import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='grpchello.proto', package='grpcDemo', syntax='proto3', serialized_options=None, serialized_pb=_b('\n\x0fgrpchello.proto\x12\x08grpcDemo\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2B\n\x04gRPC\x12:\n\x08SayHello\x12\x16.grpcDemo.HelloRequest\x1a\x14.grpcDemo.HelloReply\"\x00\x62\x06proto3') ) _HELLOREQUEST = _descriptor.Descriptor( name='HelloRequest', full_name='grpcDemo.HelloRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( name='name', full_name='grpcDemo.HelloRequest.name', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], serialized_start=29, serialized_end=57, )
而後看下grpc服務定義:
from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='grpchello.proto', package='grpcDemo', syntax='proto3', serialized_options=None, serialized_pb=_b('\n\x0fgrpchello.proto\x12\x08grpcDemo\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2B\n\x04gRPC\x12:\n\x08SayHello\x12\x16.grpcDemo.HelloRequest\x1a\x14.grpcDemo.HelloReply\"\x00\x62\x06proto3') ) _HELLOREQUEST = _descriptor.Descriptor( name='HelloRequest', from google.protobuf import symbol_database as _symbol_database # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='grpchello.proto', package='grpcDemo', syntax='proto3', serialized_options=None, serialized_pb=_b('\n\x0fgrpchello.proto\x12\x08grpcDemo\"\x1c\n\x0cHelloRequest\\ x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x011 \x01(\t2B\n\x04gRPC\x12:\n\x08SayHello\x12\x16.grpcDemo.HelloRequest\x1a\x14.grpcc Demo.HelloReply\"\x00\x62\x06proto3') ) _HELLOREQUEST = _descriptor.Descriptor( name='HelloRequest', # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! import grpc import grpchello_pb2 as grpchello__pb2 class gRPCStub(object): # missing associated documentation comment in .proto file pass def __init__(self, channel): """Constructor. Args: channel: A grpc.Channel. """ self.SayHello = channel.unary_unary( '/grpcDemo.gRPC/SayHello', request_serializer=grpchello__pb2.HelloRequest.SerializeToString, response_deserializer=grpchello__pb2.HelloReply.FromString, ) class gRPCServicer(object): # missing associated documentation comment in .proto file pass def SayHello(self, request, context): # missing associated documentation comment in .proto file pass context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def add_gRPCServicer_to_server(servicer, server): rpc_method_handlers = { 'SayHello': grpc.unary_unary_rpc_method_handler( servicer.SayHello, request_deserializer=grpchello__pb2.HelloRequest.FromString, response_serializer=grpchello__pb2.HelloReply.SerializeToString, ), } generic_handler = grpc.method_handlers_generic_handler( 'grpcDemo.gRPC', rpc_method_handlers) server.add_generic_rpc_handlers((generic_handler,))
這裏使用的幾個主要方法(類):
實現服務
在咱們的實現服務的類中,使用服務方法,並在網絡中暴露出來。
# -*- coding: utf-8 -*- import grpc import time from concurrent import futures import grpchello_pb2, grpchello_pb2_grpc _HOST = 'localhost' _PORT = '8188' _ONE_DAY_IN_SECONDS = 60 * 60 * 24 class gRPCServicerImpl(grpchello_pb2_grpc.gRPCServicer): def SayHello(self, request, context): print ("called with " + request.name) return grpchello_pb2.HelloReply(message='Hello, %s!' % request.name) def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) grpchello_pb2_grpc.add_gRPCServicer_to_server(gRPCServicerImpl(), server) server.add_insecure_port('[::]:'+_PORT) server.start() try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0) if __name__ == '__main__': serve()
這裏包括2個實現:
使用客戶端client
在客戶端,調用grpc的服務API。
# -*- coding: utf-8 -*- """The Python implementation of the gRPC client.""" from __future__ import print_function import grpc from grpchello_pb2 import * ## or import grpchello_pb2 from grpchello_pb2_grpc import * ## No grpcDemo! from grpcDemo import grpchello_pb2, grpchello_pb2_grpc #error! _PORT = '8188' def run(): conn = grpc.insecure_channel(_HOST + ':' + _PORT) client = gRPCStub(channel=conn) response = client.SayHello(HelloRequest(name='lxc')) print("received: " + response.message) ## if __name__ == '__main__': if len(sys.argv)== 2: print (sys.argv[1]) _HOST = sys.argv[1] else: _HOST = 'localhost' # run()
說明:
測試
分別啓動服務,而後再啓動客戶端,能夠看到調用結果。
也能夠啓動java、c#版本的grpc服務端、客戶端,都能調用成功。
而後運行
(lxc) liuxuchong:untitled liuxuchong$ python3 grpchello_pb2.py Traceback (most recent call last): File "grpchello_pb2.py", line 7, in <module> from google.protobuf import descriptor as _descriptor ModuleNotFoundError: No module named 'google'
提示沒有google模版
網上查了一下解決方法以下
pip3 install google
pip3 install protobuf
而後運行另外一個py文件
python3 grpchello_pb2_grpc.py Traceback (most recent call last): File "grpchello_pb2_grpc.py", line 2, in <module> import grpc
奇怪,剛纔明明裝了,還提示沒有模版,又裝了一次
pip3 install grpcio Collecting grpcio Using cached https://files.pythonhosted.org/packages/0d/27/0413a5dffd7ddca4ea43cffd22f46ec2b26a5ed18c974e4448763e758a9b/grpcio-1.25.0-cp37-cp37m-macosx_10_9_x86_64.whl Requirement already satisfied: six>=1.5.2 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from grpcio) (1.13.0) Installing collected packages: grpcio Successfully installed grpcio-1.25.0
果真剛纔裝的丟了。。。
而後運行python3 get_service.py
打開一個新的窗口運行
python3 client.py
在原來的窗口能夠看到called with lxc
參考資料:
https://www.jianshu.co×××c947d98e192
http://www.javashuo.com/article/p-gvuhtwdi-ng.html