PCR框架实践

最近做的一个项目,希望将前端接口调用与后台的算法分离,当算法进行升级更新的时候,前端无需调整,为此,计划使用pcr框架来实现二者的通信。

1. PCR结构

如图所示,灰色框部分由pcr的框架进行实现。
在这里插入图片描述

2. rpyc示例

python可以通过如下方式实现rpyc框架。安装rpyc:pip3 install rpyc==5.0.1
client.py,客户端:

import rpyc
from threading import Thread
import random


def call_prc(i):
    print(i)
    a = random.randint(0, 1000)
    b = random.randint(0, 1000)
    result = conn.root.sum(i, a, b)
    print('>>>', i, a, b, result)


conn = rpyc.connect('IP', 9999)
# 多线程,同时请求10次
exist_thread_array = []
for i in range(10):
    t1 = Thread(None, call_prc, None, args=(i,))
    t1.start()
    exist_thread_array.append(t1)

for sub_thread in exist_thread_array:
    sub_thread.join()
conn.close()

server.py,服务器端:

from rpyc import Service
from rpyc.utils.server import ThreadedServer
import random
import time


class TestService(Service):
    # 如果名字是以 “exposed_” 开始的, 这个属性将可以被远程访问, 否则只能在本地进行访问
    def exposed_sum(self, num0: int, num1: int, num2: int) -> int:
        '''
        实现num1、num2相加
        :param num1:
        :param num2:
        :return:
        '''
        a = random.randint(0, 5)
        print('request: %s, sleep: %s' % (num0, a))
        time.sleep(a)
        return num1 + num2


if __name__ == '__main__':
    # 如果想要让客户端访问未暴露的方法,需要再ThreadedServer中配置:protocol_config={"allow_public_attrs": True})
    s = ThreadedServer(TestService, port=9999, auto_register=False)
    s.start()

从客户端与服务器端日志可以发现,在同一个进程里向服务器发送请求,rpc一次收到这10个请求后,是以排队的方式执行任务的。当第1个任务执行完毕后,再执行第0、5、7…的任务。
服务器日志
在这里插入图片描述
之后,我开了3个进程,3个进程同时发送10次请求,rpc接收到这30次请求的日志如图,可以发现,rpc会同时处理3个进程的请求,但是进程内部的10次请求是排队的方式执行的。
在这里插入图片描述

3. 问题处理

3.1 响应超时

调用一个计算时间较长的接口时,报错TimeoutError: result expired,即响应超时,因此,配置如下:

# 设置响应时间最长为240s
# 可以设置为None
conn._config['sync_request_timeout'] = 240

3.2 AttributeError: cannot access ‘extend’

调用接口处理,其中涉及list的extend方法调用,报错’extend’找不到,觉得很奇怪,首先检查输入的2个参数确实为list,本地可以执行,百度后提示:rpc的包版本不一致,但是检查之后发现版本均为5.0.1。
考虑到输入输出都是较为复杂的dict,因此采用json进行编码和解码,成功执行

# 客户端输入
result = conn.root.sum(json.dumps(params))

# 服务器端返回
json.dumps(results, ensure_ascii=False)

这是由于rpc会对接收和返回的数据进行包装,将其转换为包装类型:<netref class ‘rpyc.core.netref.type’>
为了避免json的序列化开销,也可以使用下列方法将包装类型转为基本类型:
客户端:

conn = rpyc.connect(
            ip, port, config={"allow_public_attrs": True, "allow_pickle": True})
data = conn.root.process_edi_risk(params)
# 将rpc的包装类:<netref class 'rpyc.core.netref.type'>,转为基本类型:dict
data = rpyc.classic.obtain(data)

服务端:

rpyc.core.protocol.DEFAULT_CONFIG['allow_pickle'] = True
params= rpyc.classic.obtain(params)

s = ThreadedServer(
            ExpressService, port=config_map['rpc_port'], auto_register=False,
            protocol_config=rpyc.core.protocol.DEFAULT_CONFIG)

4. grpc

python还可以通过grpc实现rpc框架

  1. 编写proto文件并编译,生成2个文件
python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. time.proto
syntax = "proto3"; 
package time; 

 
service Time { // Time 服务名
    // GetTime RPC 调用
    // TimeRequest RPC 输入类型
    // TimeReply   RPC 输出类型
    rpc GetTime (TimeRequest) returns (TimeReply) {} 
} 
 
 
// Empty Request Message 
message TimeRequest {
} 
 
 
// The response message containing the time 
message TimeReply {
    string message = 1; // 字符串类型
}
  • _pb2.py:包含生成的 request(HelloRequest) 和 response(HelloReply) 类。
  • _pb2_grpc.py:包含生成的 客户端(GreeterStub)和服务端(GreeterServicer)的类
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值