grpc的微服务探索实践
对于微服务的实践,一般都是基于Java和Golang的,博主最近研究了下基于Python的微服务实践,现在通过一个简单的服务来分析Python技术栈的微服务实践
技术栈:Python3 + grpc + Zookeeper
服务API:通过学科获取相应的题型
grpc:由Google公司开源的高性能RPC框架,消息协议使用Google自家开源的Protocol Buffers协议机制,传输使用HTTP2.0标准,支持双向流和连接多路复用
Protocol Buffers部分:
syntax = "proto3";
message Subject {
string name = 1;
}
message QuestionType {
string name = 1;
}
service SimpleRpcServer {
// server streaming rpc
// 客户端发送学科,服务端多次返回该学科包含的题型
rpc GetSubjectQuestionTypes (Subject) returns (stream QuestionType) {
}
}
这里定义grpc的接口类型为服务器流式RPC,即客户端发起一次请求,服务器可以返回多个响应信息,典型的例子有:客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端:
通过protobuf编译器和Protocol Buffers生成代码:
python3 -m grpc_tools.protoc -I. --python_out=.. --grpc_python_out=.. simple_calculate.proto
服务端开启服务器,对外提供rpc调用流程:
客户端rpc调用流程:
Zookeeper服务注册与发现策略:
服务注册:
1 def register_zk(host, port):
2 """
3 注册到zookeeper
4 """
5 zk = KazooClient(hosts='{host}:{port}'.format(
6 host=settings_info["zookeeper"]["host"],
7 port=settings_info["zookeeper"]["port"])
8 )
9 zk.start()
10 zk.ensure_path('/rpc_calc') # 创建根节点
11 value = json.dumps({'host': host, 'port': port})
12
13 # 创建服务子节点
14 zk.create(
15 '/rpc_calc/calculate_server',
16 value.encode(),
17 ephemeral=True,
18 sequence=True
19 )
服务治理发现:
1 def _get_servers(self, event=None):
2 """
3 从zookeeper获取服务器地址信息列表
4 """
5 servers = self._zk.get_children(
6 '/rpc_calc', watch=self._get_servers
7 )
8 print(servers)
9 self._servers = []
10 for server in servers:
11 data = self._zk.get('/rpc_calc/' + server)[0]
12 if data:
13 addr = json.loads(data.decode())
14 self._servers.append(addr)
15
16 def get_server(self):
17 """
18 随机选出一个可用的服务器
19 """
20 return random.choice(self._servers)
服务端实现代码:
1 class SimpleRpcServerServicer(calculate_grpc.SimpleRpcServerServicer):
2 """
3 实现被调用方法的具体代码
4 """
5
6 def __init__(self):
7 self.subject_question_type_db = {
8 'Chinese': ['单选', '多选', '填空', '解答', '问答', '作文'],
9 'Math': ['单选', '填空', '解答'],
10 'English': ['单选', '填空', '作文'],
11 'Physics': ['单选', '多选', '填空', '解答'],
12 'Chemistry': ['单选', '多选', '填空', '解答'],
13 'Biology': ['单选', '多选', '填空', '解答'],
14 'History': ['单选', '多选', '填空', '解答', '问答']
15 }
16
17 def GetSubjectQuestionTypes(self, request, context):
18 """
19 服务器流式RPC调用 根据subject获取question_types
20 :param request:
21 :param context:
22 :return:
23 """
24 subject = request.name
25 question_types = self.subject_question_type_db.get(subject)
26 for question_type in question_types:
27 yield calculate_pb2.QuestionType(name=question_type)
客户端实现代码:
1 def invoke_get_subject_question_types(stub):
2 """
3 根据学科获取题型
4 Server Streaming RPC 服务器流式RPC 客户端发送,服务器响应多个
5 :param stub:
6 :return:
7 """
8 subject = calculate_pb2.Subject(name='Chinese')
9 question_types = stub.GetSubjectQuestionTypes(subject)
10 for question_type in question_types:
11 print(question_type.name)
服务测试:
开启三个服务,地址分别是 host:8003 host:8005 host:8009,客户端开启两个,client1 和 client2 ,测试结果:
已经成功注册了三个server到Zookeeper,客户端1使用的是8003端口的server,客户端2使用的是8005端口的server;grpc框架对于完整的rpc实现来说,实质上是封装了 网络传输、数据协议的打包解包,使得实现rpc更加简单,其本质仍然是遵守rpc的实现原理的
完整的代码详见我的git:simple_calculate_service