快速暴露 Python 函数作为 HTTP 服务

2021-02-18 08:48:16 +08:00
 abersheeran

给算法岗擦屁股的人应该明白那种痛苦的感觉。为了解耦不同服务之间的程序,但又能像调用原生函数一样调用远程函数,我在过去写下了 rpc.py。用了一段时间之后,过年守岁的时候闲着没事花了一夜把 coverage 提高到了 100%,修了几个隐藏的小 bug,现在基本稳定。

当然在造轮子之前我了解和使用过 grpc,怎么说呢……用起来挺蛋疼的。注册很麻烦,调用很麻烦,和其它服务配合起来也很麻烦。于是研究了一下 grpc 的原理,自己写了一个。

由于是基于 ASGI/WSGI 这两个通用网关协议的,所以 HTTP 部分我就可以偷懒不处理了,用社区发展十几年的成果就行。你想用 HTTP/1.0 、1.1 还是 2.0,或者更激进点直接 3.0,都可以。Python 社区都有现成方案。

基于这两通用网关协议,还有一个好处就是可以方便的和现有的 Django 、Bottle 、Flask 、Starlette 、FastAPI 、Sanic 、CherryPy 、Responder 、IndexPy……总之你能想到的支持这两个协议中至少一种的任何 Web 框架集成。也就是说,鉴权之类的工作,都可以用现成的。自己独立弄一个是不存在的,如果可以,这辈子我都不想自己造轮子了。

序列化协议上是天然解耦的,目前只内置了 JSON 、pickle 和 msgpack,如果大家还有什么高性能序列化协议,可以提 PR 或者发个 Discussion 。当然,也可以只在自己代码里用,自己注册一个还是很方便的。

基于 Type hint,可以自动转换类型,客户端在调用的时候还会主动检查类型。当然你不用 Type hint 也是可以正常用的。基于 Type hint 生成文档,似乎新框架都自带这个了哈哈哈

https://github.com/abersheeran/rpc.py

最后,造这个轮子的主要原因就是之前某项目大概有上千个函数需要批量转成可远程调用的接口。历史包袱、历史包袱。

4719 次点击
所在节点    Python
37 条回复
skies457
2021-02-18 13:38:42 +08:00
直接白嫖阿里云的 serverless 函数计算不香吗(狗头
HashV2
2021-02-18 13:49:21 +08:00
楼主 github 头像本人?
cornetCat
2021-02-18 14:05:40 +08:00
楼主不是妹子吧
看腾讯离职那篇提到有女朋友的
XingWu
2021-02-18 14:34:11 +08:00
为啥不用 serverless 呢
abersheeran
2021-02-18 15:21:09 +08:00
@no1xsyzy ?如果你客户端代码和服务端代码写在一起了,直接调用不就好了吗
abersheeran
2021-02-18 15:22:26 +08:00
@silymore 这不是我所在公司需要用到的。也不是工作期间开发的。
abersheeran
2021-02-18 15:29:37 +08:00
@skies457
@XingWu

虽然我感觉你们完全不知道 rpc.py 和 serverless 的关系,但是恰好说对了它的用途。阿里云的函数计算原生支持 WSGI 接口,所以部署起来简直不要太简单。再配合另一个库 a2wsgi,可以把 ASGI 模式转成 WSGI,异步函数也可以一样一键注册。
abersheeran
2021-02-18 15:37:45 +08:00
@silymore 想了想,所在的公司或许后续要上微服务,所以可能会被用到。但是直到目前为止,它仍然和我目前所在的公司没什么关系。我上班期间为这家公司造的轮子,是仅内部使用的,而且因为特殊的原因,就算开源了也没有通用价值。轮子造了快三个月,所以我才说不想再造轮子了。

公司正在用的我的开源项目,唯一一个就是 Index\.py 。我入职前基本完工的,公司现在在用。

详细解释一下免得让大家以为我把公司项目给开源了。
no1xsyzy
2021-02-18 16:01:23 +08:00
@abersheeran 我的服务端会有一些缓存,而且是再请求上游服务器的,上游服务器效率非常差( ping 超 300ms,更不用说每组有意义的请求通常包含三个来回),但有更新推送,所以可以拿一个中间服务器作为缓存,根据推送重新获取信息。
abersheeran
2021-02-18 16:20:54 +08:00
@no1xsyzy 原来如此。
seth19960929
2021-02-18 16:22:28 +08:00
楼上怎么关注点不同呀. 老是关注楼主身份. 搞得点进来的人都无法专心看问题啦.
----

话说这样, 和直接暴露一个 path 接口, 然后反射调用然后返回函数返回值有什么区别吗?
abersheeran
2021-02-18 16:32:18 +08:00
@seth19960929 你的意思是直接用某个 web 框架创建接口?其实没有本质上的差别。只不过需要自己约定一个规则和序列化工具。对于生成器函数需要自己手写一下 SSE (目前为止好像没有几个 Py 框架支持这个)。

我在写出 rpcpy 之前,都是用的 bottlepy 作为代替。但 web 框架的大部分功能其实是用不上的,所以效率上可能稍差一点。

用 web 框架手写更自由,也更可控。不过代码量就……
seth19960929
2021-02-18 17:02:52 +08:00
是否支持其他语言客户端? 如果支持, 怎么保证序列化每一种语言的实现. 去用 ProtoBuf ?
如果只支持 Python 有专门的库把任意 Python 数据类型序列化成字符串. 然后客户端反序列化用就好了.
todd7zhang
2021-02-18 17:03:06 +08:00
2.7 老古董看到 typing 脑壳昏, 是不是应该学一学这个 typing 了
abersheeran
2021-02-18 17:09:37 +08:00
@seth19960929 现在内置的三个序列化器,JSON 、Msgpack 都是跨语言的。JSON 自然不必多说,Msgpack 也有很多语言可以支持。ProtoBuf 考虑过,不过没有好用的库,就作罢了。

@todd7zhang 没事,不用 typing 也可以正常工作的。只不过有 type hint 的信息,功能更丰富一点罢了。
NeilWang
2021-02-19 10:58:07 +08:00
"可以方便的和现有的 Web 框架集成。也就是说,鉴权之类的工作,都可以用现成的"
楼主,你的意思是说 注册到 rpc.py 的函数,可以转换成 Flask 等 Web 框架的视图函数? Web 框架转 ASGI/WSGI 应用倒是很简单,不过没见过 ASGI/WSGI 应用转 Web 框架视图函数的。不知道我的理解对不对,有相关的例子可以提供吗
abersheeran
2021-02-19 11:32:32 +08:00
@NeilWang 不能转视图函数。这里我说的是 WSGI/ASGI Application 组合。Flask 我不记得能不能 mount wsgi app,但是 Bottle.mount 可以,所以我猜 Flask 应该也实现了这个功能。具体的你可以去 Flask 社区问问。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/753783

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX