|
背景
远程过程调用有很多技术选型, 例如FastAPI ,gRPC,XML-RPC,msgpack-RPC等。RPC中很重要的一个部分是序列化与反序列化,主流的序列化方法包括xml,json,protobuf和msgpack。本文将基于Python语言对基于不同序列化方法的RPC实现进行简单对比。(注:这些序列化协议都是跨语言的,每个语言都有自己的实现)
设定
考虑一个简单的“加和”服务:服务提供方接受的参数为一个list,需要将list中的数字都加和后,返回加和的结果。
def sum_nums(nums: list[int]) -> int:
"""
加和传入的nums
"""
return sum(nums)首先计算纯本地调用(无RPC)的耗时,执行10000次。考虑“低数据量”和“高数据量”两个场景:
低数据量:nums=[1,2]: 1.938ms
高数据量:nums=[1,2,3...,1000]: 52.32msjson-FastAPI
json是使用最为广泛的一种序列化方式,广泛应用于前后端之前的通信,并且有非常好的可读性。基于json的RPC调用,这里选择相对性能较好的FastAPI进行测试。
server端
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/rpc", status_code=200)
async def rpc(request: Request):
"""
:param request:
:return:
"""
data = await request.json()
nums = data['nums']
result = sum_nums(nums)
return JSONResponse(content={'result': result})通过uvicorn启动服务
uvicorn fast_api_test:app --port 8000client端
nums = list(range(1, 3))
requests.post('http://127.0.0.1:8000/rpc', json={'nums': nums})执行10000次耗时情况
低数据量:nums=[1,2]: 18590.62ms
高数据量:nums=[1,2,3...,1000]: 20385.60msgRPC
protobuf是一种比json性能更高的序列化方式,但是比json的可读性差很多,序列化之后是二进制不可读的。基于protobuf的RPC调用,选择gRPC 进行测试,这也是是后端服务之间广泛采用的一种RPC方式。
首先需要定义一个proto文件
syntax = "proto3";
service RPCTest {
rpc SumNums(SumNumsRequest) returns (SumNumsResponse) {}
}
message SumNumsRequest {
repeated int32 nums = 1;
}
message SumNumsResponse{
int32 result = 1;
}编译proto文件产生pb2文件和pb2_grpc文件
server端
from concurrent import futures
import test_pb2
import test_pb2_grpc
import grpc
class RPCTest(test_pb2_grpc.RPCTestServicer):
def SumNums(self, request, context):
result = sum(request.nums)
return test_pb2.SumNumsResponse(result=result)
def serve():
port = '50051'
server = grpc.server(futures.ThreadPoolExecutor(max_workers=1))
test_pb2_grpc.add_RPCTestServicer_to_server(RPCTest(), server)
server.add_insecure_port('[::]:' + port)
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()client端
nums = list(range(1, 3))
with grpc.insecure_channel('localhost:50051') as channel:
stub = test_pb2_grpc.RPCTestStub(channel)
response = stub.SumNums(test_pb2.SumNumsRequest(nums=nums))执行10000次耗时情况
低数据量:nums=[1,2]: 8654.08ms
高数据量:nums=[1,2,3...,1000]: 10014.39msmsgpack-RPC
msgpack也是一种二进制的传输协议,比json更小也更快,整体性能比protobuf还要更高。同时不需要预先定义proto文件,所以也没有相应的数据校验,这也会让的项目维护成本高很多。
基于msgpack的RPC调用,选择官方的msgpack-rpc进行实验。
server端
import msgpackrpc
class SumServer(object):
def sum_nums(self, nums: List[int]) -> int:
return sum(nums)
server = msgpackrpc.Server(SumServer())
server.listen(msgpackrpc.Address("localhost", 18800))
server.start()client端
import msgpackrpc
client = msgpackrpc.Client(msgpackrpc.Address("localhost", 18800))
client.call('sum_nums', nums)执行10000次耗时情况
低数据量:nums=[1,2]: 1111.17ms
高数据量:nums=[1,2,3...,1000]: 1610.63ms整体对比
传输数据 | 无PRC | FastAPI (json) | gRPC (protobuf) | msgpack-rpc | 低数据 | 1.938ms | 18590.62ms | 8654.08ms | 1111.17ms | 高数据 | 52.32ms | 20385.60ms | 10014.39ms | 1610.63ms |
速度对比
可以看到protobuf相比json快了1倍,msgpack相比protobuf快了10倍!
不过protobuf相比json少了可读性,msgpack相比protobuf少了数据校验(协作能力),所以前后端之前的通信一般采用json(为了可读性),后端不同服务的相互协作一般采用protobuf(公共的proto)。如果完全自己维护的不同子服务的通信,可以试试msgpack。
<hr/>持续分享AI算法相关的研究和落地工作,欢迎关注!往期文章汇总:
nghuyong:基于FAQ的智能问答(一): Elasticsearch的调教
nghuyong:基于FAQ的智能问答(二): 召回篇
nghuyong:基于FAQ的智能问答(三): 精排篇
2. 统计学习方法forNLP系列
nghuyong:统计机器学习方法 for NLP:基于HMM的词性标注
nghuyong:统计机器学习方法 for NLP:基于CRF的词性标注
nghuyong:统计机器学习方法 for NLP:基于LSA的主题模型
nghuyong:统计机器学习方法 for NLP:基于LDA的主题模型
nghuyong:手算KN-based ngram语言模型
3. NLP论文解读
nghuyong:Flan-T5: One Model for ALL Tasks
nghuyong: 如何评价1700亿参数的GPT-3?
nghuyong: 如何评价OpenAI最新的工作CLIP
4. 其他工程技术
nghuyong:Transformers多机多卡的炼丹实践
nghuyong:文本纠错的论文看这一篇就够了
nghuyong:试试在transformers中调用ERNIE
nghuyong: 如何开始在 github 上学习东西?
nghuyong:Python如何利用多核加速CPU密集型服务 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|