7

Python Flask + Tornado 请求很慢的接口导致全站无法访问,有什么解决方法么?

 3 years ago
source link: https://www.v2ex.com/t/795550
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  Python

Python Flask + Tornado 请求很慢的接口导致全站无法访问,有什么解决方法么?

  theklf4 · 1 天前 · 923 次点击

第一次写 Flask,一个网页返回前需要请求一个要 5s 左右才能返回结果的接口,对方要求不能用 ajax,但一旦发起请求到请求完成前全站就无法打开了。按 Google 上找的教程做了多线程,但请求量大还是会导致全站无法打开,CPU 占用只有不到 1%,请问有什么解决方法么?

第 1 条附言  ·  23 小时 19 分钟前

问题是一个需要较长时间返回的网页返回结果前网站的其它请求都无法处理,服务器上调也是这样。看起来像只有一个线程, 于是去抄了一份 Tornado 异步的代码,但情况没有改善 paste.ubuntu.com/p/w2XNbbjDgh/
17 条回复    2021-08-13 19:51:00 +08:00

learningman

learningman   1 天前

协程,asyncio

Icarooooos

Icarooooos   1 天前 via Android

gunicorn

wzwwzw

wzwwzw   1 天前

看你的描述应该是直接用了 app.run 需要在外层套一层 web 服务器 gunicorn 了解下。

wellsc

wellsc   1 天前

profile 看下到底慢在哪个环节

theklf4

theklf4   1 天前

@Icarooooos #2
@wzwwzw #3 感谢回复,已经用了 Tornado,按 Google 上的说法 Tornado 已经包含了一个异步 WSGI server,请问还有必要用 gunicorn 么?

rationa1cuzz

rationa1cuzz   23 小时 54 分钟前

先找问题啊,你这问题都没找到瞎猜什么?先看是接口问题还是什么服务器问题,用个抓包工具像 4 楼的 profile 或者直接用 postman,本地调一下服务器调一下

Kinnice

Kinnice   23 小时 47 分钟前

5s 左右才能返回结果的接口 是实时数据还是弱实时的,如果是弱实时的,可以起个定时器定时去请求然后把结果缓存到本地,然后接口直接取本地的那个缓存结果

theklf4

theklf4   23 小时 44 分钟前

@rationa1cuzz #6 问题是一个需要较长时间返回的网页返回结果前网站的其它请求都无法处理,服务器上调也是这样。看起来是像只有一个线程, 于是去抄了一份 Tornado 异步的代码,但情况没有改善 paste.ubuntu.com/p/w2XNbbjDgh/

theklf4

theklf4   23 小时 44 分钟前

@Kinnice #7 是实时数据。

Kinnice

Kinnice   23 小时 40 分钟前

看这个问题,你好像需要改的是前端的问题,让前端先加载其他资源,最后再加载这个,
另外就是你的这个接口怎么会这么慢是做了什么操作

vicalloy

vicalloy   23 小时 34 分钟前

server = tornado.httpserver.HTTPServer(app)
server.bind(8888)
server.start(0) # forks one process per cpu
IOLoop.current().start()
把 server.start(0)改成 99
你的 web 服务器是单进程&单线程模式,一次只能有一个实例,你得想办法把线程 /进程数改打。
前面说到 asyncio 是行不通的,asyncio 有传播性,除非你的应用本身就是 asyncio 写的,不然不会有任何改善。

stach

stach   23 小时 12 分钟前   ❤️ 3

- 1. 不要用 tornado, 你显然搞不定
- 2. 百度一下怎么用 gevent monkey patch flask
- 3. 最好用 gunicorn 部署 flask

tisswb

tisswb   23 小时 10 分钟前

tonghuashuai

tonghuashuai   23 小时 5 分钟前   ❤️ 1

wsgi 应用是同步的,如用 wsgi server 再是单线程单进程的,就相当于你这个 web 服务是一个单线程 /进程同步服务,同时只能处理一个任务。Tornado 框架可以解决,看来是姿势不对了。所以解决办法可以是下面的几种:

1. 保持单线程,但 fork 多个进程,类似于启动多个你这个服务,#11 楼的办法可以参考下,或者 gunicorn 替换 tornado,gunicorn --workers=4 main:app (启动 4 个 worker 进程,也就是能支持 4 个请求同时访问你的耗时接口)
2. 改进,多进程多线程,gunicorn 替换 tornado (考虑加 gevent ),gunicorn --workers=4 --threads=4 main:app,并发请求数就是 worker * 线程

no1xsyzy

no1xsyzy   22 小时 25 分钟前

考虑到通常来说计算不会超过 100ms,你的线程池 size 至少是 50
拿 tornado 作框架你需要手动新建线程池或者 ThreadPoolExecutor

Trim21

Trim21   20 小时 26 分钟前 via Android   ❤️ 1

要么直说用 gunicorn 来运行 flask,要么直接用 tornado+async 来写后端,建议前者

qiuhang

qiuhang   17 小时 37 分钟前

你这似乎是以单进程但线程提供服务,某个请求卡住后就没有其它 responder 了,可以尝试开多进程,或者开协程。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK