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