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

搭建类似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,特别适合做后端。

5、带宽资源

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

二、前端的灵活性

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

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

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

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

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

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