V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
abersheeran
V2EX  ›  Python

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

  •  
  •   abersheeran ·
    abersheeran · 2021-02-18 08:48:16 +08:00 · 4662 次点击
    这是一个创建于 1134 天前的主题,其中的信息可能已经有所发展或是发生改变。

    给算法岗擦屁股的人应该明白那种痛苦的感觉。为了解耦不同服务之间的程序,但又能像调用原生函数一样调用远程函数,我在过去写下了 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

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

    37 条回复    2021-02-19 11:32:32 +08:00
    lipcao
        1
    lipcao  
       2021-02-18 09:34:59 +08:00
    过年守岁的时候闲着没事花了一夜把 coverage 提高到了 100% 重点,要考
    yazoox
        2
    yazoox  
       2021-02-18 10:05:28 +08:00
    不明觉厉!
    abersheeran
        3
    abersheeran  
    OP
       2021-02-18 10:11:34 +08:00
    @lipcao 这算啥重点……

    @yazoox 用用就明白了。用法还是很简单的。
    jenlors
        4
    jenlors  
       2021-02-18 10:13:55 +08:00
    楼主 github 头像本人?
    fy1993
        5
    fy1993  
       2021-02-18 10:16:22 +08:00
    楼主 github 头像本人?
    musi
        6
    musi  
       2021-02-18 10:18:56 +08:00
    看了下楼主的博客,这文采做程序员真的屈才了。多写写小说没准已经拍成电视剧了
    LengthMin
        7
    LengthMin  
       2021-02-18 10:22:55 +08:00
    楼主也是 `index.py` 的作者
    madpecker009
        8
    madpecker009  
       2021-02-18 10:29:07 +08:00
    这妹子好看啊
    abersheeran
        9
    abersheeran  
    OP
       2021-02-18 10:32:44 +08:00
    @madpecker009 谢谢。

    @musi 哈哈哈,谢谢你看我的小说。

    @LengthMin 我是个取名废柴,要不是 web.py 被人用了,Index.py 估计会被我改成这个。
    jenlors
        10
    jenlors  
       2021-02-18 10:34:01 +08:00
    看了楼主 blog,不去写小说可惜了。
    abersheeran
        11
    abersheeran  
    OP
       2021-02-18 10:48:29 +08:00
    @long2ice 😀
    z740713651
        12
    z740713651  
       2021-02-18 10:51:06 +08:00
    大佬太牛了 公司业务正好要用到 rpc.py 感谢大佬
    lewinlan
        13
    lewinlan  
       2021-02-18 10:53:12 +08:00 via Android
    grpc 蛋疼是 python 的问题。换其他语言写 grpc 快乐的很
    abersheeran
        14
    abersheeran  
    OP
       2021-02-18 11:03:39 +08:00
    @z740713651 用呗。我们也在用。

    @lewinlan 那就没办法了。
    no1xsyzy
        15
    no1xsyzy  
       2021-02-18 11:30:01 +08:00
    所以说 Client.remote_call 和 RPC.register 有什么形式上的差别吗?
    完全可以用同一个函数去注册不是吗?
    Client 没必要分离吧(
    johnsona
        16
    johnsona  
       2021-02-18 12:03:44 +08:00 via iPhone
    是不是要有负载均衡(乱说的 bushi
    silymore
        17
    silymore  
       2021-02-18 12:36:58 +08:00 via iPhone
    开源工作相关的框架需要公司同意吗
    gscsnm
        18
    gscsnm  
       2021-02-18 12:37:53 +08:00
    喜欢你的博客,请问下博客是自己开发的吗?还是用的什么?
    poplar50
        19
    poplar50  
       2021-02-18 13:15:51 +08:00 via iPhone
    楼主 github 头像本人?
    jaswer
        20
    jaswer  
       2021-02-18 13:34:52 +08:00
    楼主 github 头像本人?
    skies457
        21
    skies457  
       2021-02-18 13:38:42 +08:00
    直接白嫖阿里云的 serverless 函数计算不香吗(狗头
    HashV2
        22
    HashV2  
       2021-02-18 13:49:21 +08:00
    楼主 github 头像本人?
    cornetCat
        23
    cornetCat  
       2021-02-18 14:05:40 +08:00
    楼主不是妹子吧
    看腾讯离职那篇提到有女朋友的
    XingWu
        24
    XingWu  
       2021-02-18 14:34:11 +08:00
    为啥不用 serverless 呢
    abersheeran
        25
    abersheeran  
    OP
       2021-02-18 15:21:09 +08:00
    @no1xsyzy ?如果你客户端代码和服务端代码写在一起了,直接调用不就好了吗
    abersheeran
        26
    abersheeran  
    OP
       2021-02-18 15:22:26 +08:00
    @silymore 这不是我所在公司需要用到的。也不是工作期间开发的。
    abersheeran
        27
    abersheeran  
    OP
       2021-02-18 15:29:37 +08:00
    @skies457
    @XingWu

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

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

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

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

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

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

    @todd7zhang 没事,不用 typing 也可以正常工作的。只不过有 type hint 的信息,功能更丰富一点罢了。
    NeilWang
        36
    NeilWang  
       2021-02-19 10:58:07 +08:00
    "可以方便的和现有的 Web 框架集成。也就是说,鉴权之类的工作,都可以用现成的"
    楼主,你的意思是说 注册到 rpc.py 的函数,可以转换成 Flask 等 Web 框架的视图函数? Web 框架转 ASGI/WSGI 应用倒是很简单,不过没见过 ASGI/WSGI 应用转 Web 框架视图函数的。不知道我的理解对不对,有相关的例子可以提供吗
    abersheeran
        37
    abersheeran  
    OP
       2021-02-19 11:32:32 +08:00   ❤️ 1
    @NeilWang 不能转视图函数。这里我说的是 WSGI/ASGI Application 组合。Flask 我不记得能不能 mount wsgi app,但是 Bottle.mount 可以,所以我猜 Flask 应该也实现了这个功能。具体的你可以去 Flask 社区问问。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   980 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 20:25 · PVG 04:25 · LAX 13:25 · JFK 16:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.