Python:关于数据服务中的Web API的设计

125 篇文章 8 订阅
79 篇文章 6 订阅

搭建类似joinquant、tushare类似的私有数据服务应用,有以下一些点需要注意:

需要说明的是,这里讨论的是web api前后端,当然还有其它方案,thrift,grpc等。因为要考虑到一鱼两吃,本文只探讨web api。在web api的基础上,可以提供封装sdk库,供前端函数式调用服务或纯手动写restful api 的方式,自己封装调用函数服务。

一、性能

性能主要取决于后端,前端可以考虑性能更好的语言、多线程和异步。
后端开发上,主要是序列化+压缩。
1、序列化

需要考虑跨语言的问题。比如,如果后端用python开发,用pickle序列化,前端用julia,用rust调用就会存在反序列化的问题。
如果用json序列化,虽然会通用,但效率会差一些。
阿里的Fury据说是一个跨语言的序列化的库,没有试用过。

https://furyio.org

python:

pip install pyfury

在这里插入图片描述比如python:

from typing import Dict
import pyfury

class SomeClass:
    f1: "SomeClass"
    f2: Dict[str, str]
    f3: Dict[str, str]

fury = pyfury.Fury(ref_tracking=True)
fury.register_class(SomeClass, "example.SomeClass")
obj = SomeClass()
obj.f2 = {"k1": "v1", "k2": "v2"}
obj.f1, obj.f3 = obj, obj.f2
data = fury.serialize(obj)
# bytes can be data serialized by other languages.
print(fury.deserialize(data))

这个库,正好缓解不少跨语言的痛点。但是并不一定可以解决所有语言的痛点,比如,对于R,或C#呢,就不知道是否可以。

当然,还是有其它解决办法的。比如,可以在这个基础上进行跨语言ffi封装,不过技术上会复杂一些。

2、压缩
不仅需要考虑性能,选择读写高效的库,而且还要考虑跨语言的问题。
在这里插入图片描述
显然,API是要跨网络的,对压缩比,以及压缩和解压来综合考量比较,需要根据场景来选取。有人喜欢zstd,也有人喜欢别的。

3、数据库还是文件系统

这个具体还是要看场景(并发、性能、硬件条件等),看应用服务的要求,各有优点。

(1)数据库

是选择TDengine,还是Clickhouse,还是DolphinDB? 还是采用其它?当然性能(读/写还是读和写)要求高,一般的数据库就不需要考虑了(如mysql之类)。

(2)文件系统

是选择Hdf5?还是Feather,还是Parquet,还有 Jay?Csv文件格式当源数可以考虑,但是当文件服务的一线服务支持,性能太差了。

Parquet压缩比好,但速度略慢于Feather。hdf5对字符串性能要差,需要进行特别处理。最好还是把最常用的数据格式做个比较,还要看看空间占用情况。

hdf5文件我还碰到过硬盘空间澎胀(空间占用异常暴涨)的事情,这些都需要自已摸索。

4、异步

后端如果采用异步的方式,有利于提升并发的效率。这里异步的框架的深度和广度,也需要进一步探讨。是在网络IO层,还是包括数据库的访问?

就异步而言,异步支持最好的是rust,特别适合做后端。

异步包括但不限于的有关环节:
(1)网络传输和处理环节:流式和非流式
对特定数据类的web api而言,大文件相对多一些,在这种情况下,流式传输的性能可能会更好。
但缺点是前后端对程序的编写要求会高一些。
(2)序列化和反序列化环节
(3)数据库取数环节

5、带宽资源

这个主要看你有多豪了。没什么说的,上预算。

二、前端的灵活性

1、关于前端服务模式的适用性

可以考虑在前端提供不同的选择,比如,是python sdk模式(提供安装包),还是纯restful模式(手写post,get等),以及不同的语言选择,来指定特定后端的序列化和压缩库的选择,便于前端有更好的适用性和体验。

这个可以在前端的headers中,或者post的params参数中,可以带入让后端判断的参数即可以。

这个可以通过写比较详细的示例,让大家更易于上手。

2、关于前端服务对后端的约束

前端如果python用户多,后端用python开发有使用上有一定的优势。前后端数据格式容易对齐(序列化)和Dataframe等。rust也非常适合,可以通过PYO3提供相应的前端适用服务封装。包括polars也是rust封装的,pandas2.x上有很多还赶不上。

三、其它:GRPC

其实,如果不考虑前端的灵活多样性,如果前端可以采用SDK方式,更好的方案是grpc方式。

1、参考数据1

根据 https://juejin.cn/post/6844903577979191309 文章的数据:

{
"id":1,
"name":"jojo",
"email":"123@qq.com",
}

使用 JSON 进行编码,得出byte长度为43的的二进制数据:

7b226964 223a312c 226e616d 65223a22 6a6f6a6f 222c2265 6d61696c 223a2231 32334071 712e636f 6d227d

如果使用 Protobuf 进行编码,得到的二进制数据仅有20个字节:

0a046a6f 6a6f1001 1a0a3132 33407171 2e636f6d

如果在protobuf的基础上,再进行压缩,相关网络传输的性能会更好。

2、参考数据2

有文章对这两者的数据进行了进一步的探讨,具体见:https://blog.csdn.net/qq_65307907/article/details/134041331
数据如下:

100次 [pb序列化]耗时:0.382ms. 序列化后的大小:278
100次 [pb反序列化]耗时:0.442ms.
100次 [json序列化]耗时:2.43ms. 序列化后的大小:567
100次 [json反序列化]耗时:1.091ms.

1000次 [pb序列化]耗时:3.196ms. 序列化后的大小:278
1000次 [pb反序列化]耗时:5.047ms.
1000次 [json序列化]耗时:20.22ms. 序列化后的大小:567
1000次 [json反序列化]耗时:13.037ms.

10000次 [pb序列化]耗时:29.206ms. 序列化后的大小:278
10000次 [pb反序列化]耗时:48.03ms.
10000次 [json序列化]耗时:206.259ms. 序列化后的大小:567
10000次 [json反序列化]耗时:114.738ms.

关于thrift和grpc:感觉grpc比thrift略优一点
数据来源:https://blog.csdn.net/dazheng/article/details/48830511
在这里插入图片描述

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值