问题描述
我通过 wfastcgi
配置将 Flask 站点部署到 IIS。
当我使用chrome或firefox开发者工具分析首页的加载时间时,我发现等待接收第一个字节的时间有很多秒(平均6到10秒)。
甚至是 30 秒之前,但随后我“优化”了我的 python 代码以避免在加载时进行任何 db sql 操作。然后我遵循了这个 blog of nspointers 的提示,现在从服务器的任务栏中我看到了 w3wp.exe
为我的应用程序池标识
w3wp.exe – 它是应用程序池的 IIS 工作进程
即使在空闲时间也能保持正常运行。但其他人就不是这样了
python.exe – Django 或 Flask 的主要 FastCGI 进程 应用程序。
而且我不确定这是否是一个问题,以防万一,除了上述帖子中描述的第 4 步之外,我应该做什么。
现在在“Process Model”下的“Edit FastCGI Application”对话框中 编辑“空闲超时”并将其设置为最大值 2592000 以秒为单位的该字段
我还查看了 Flask 应用程序编写的日志,并将其与 IIS 编写的日志进行了比较,这是让我相信问题出在 wfastcgi
部分的最重要的一点,在执行python代码之前。
因为我看到IIS日志的time-taken
与chrome或firefox报告的客户端时间匹配为TTFB
,并且python在执行开始时写入的日志几乎记录在与 IIS 编写的时间相同,即
对应请求完成的时间
(正如我认为的那样,而且我发现它已被 this answer 确认)
总而言之,根据我的尝试和理解,我怀疑 IIS 正在“浪费”许多秒来“准备”python {{1 }} 命令,在实际开始执行我的应用程序代码以生成对 Web 请求的响应之前。在我看来这真的太多了,因为我在 IIS 下开发的其他应用程序(例如在 F# WebSharper 中)没有这种wfascgi
机制在浏览器中立即加载以及它们之间的响应时间与python Flask 应用程序非常引人注目。我还能做些什么来缩短响应时间?
解决方法
好的,现在我有了我正在搜索的证据,并且我知道服务器实际上在哪里花费了时间。
所以我对 wfastcgi
进行了一些研究,最后在 venv\Lib\site-packages
下打开了脚本本身。
浏览 900 行,您可以找到相关的日志部分:
def log(txt):
"""Logs messages to a log file if WSGI_LOG env var is defined."""
if APPINSIGHT_CLIENT:
try:
APPINSIGHT_CLIENT.track_event(txt)
except:
pass
log_file = os.environ.get('WSGI_LOG')
if log_file:
with open(log_file,'a+',encoding='utf-8') as f:
txt = txt.replace('\r\n','\n')
f.write('%s: %s%s' % (datetime.datetime.now(),txt,'' if txt.endswith('\n') else '\n'))
现在,知道 how to set the environment variables,我定义了一个特定的 WSGI_LOG
路径,我们开始吧,现在我看到了来自 chrome 的 5 秒 TTFB(以及来自 IIS 日志的相同 5 秒) time
11:23:26
和 time-taken
5312
) 在 wfastcgi.py
日志中。
2021-02-01 12:23:21.452634: wfastcgi.py 3.0.0 initializing
2021-02-01 12:23:26.624620: wfastcgi.py 3.0.0 started
所以,当然,wfastcgi.py
是人们可能会尝试优化的脚本...
顺便说一句,在深入研究之后,那个时间是由于导入主烧瓶应用程序
handler = __import__(module_name,fromlist=[name_list[0][0]])
还有待验证的是为每个请求重新运行进程的行为(以及主烧瓶模块的导入,这很耗时)。
总而言之,我猜这是一个 BUG,但我已经通过删除“监控文件更改”FastCGI设置解决了它,如下面的屏幕截图所示。
响应时间不到一秒。
,我有一个不同的答案,建议您尝试将 IIS 前端 Flask 应用切换到 HTTP Platform Handler。
这也是微软推荐的选项:
您的应用的 web.config 文件会指示在 Windows 上运行的 IIS (7+) 网络服务器如何通过 HttpPlatform(推荐)或 FastCGI 处理 Python 请求。
https://docs.microsoft.com/en-us/visualstudio/python/configure-web-apps-for-iis-windows?view=vs-2019
示例配置可以是:
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers>
<httpPlatform processPath="c:\inetpub\wwwroot\run.cmd"
arguments="%HTTP_PLATFORM_PORT%"
stdoutLogEnabled="true"
stdoutLogFile="c:\inetput\Logs\logfiles\python_app.log"
processPerApplication="2"
startupTimeLimit="60"
requestTimeout="00:01:05"
forwardWindowsAuthToken="True"
>
<environmentVariables>
<environmentVariable name="FLASK_RUN_PORT" value="%HTTP_PLATFORM_PORT%" />
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
run.cmd 类似于
cd %~dp0
.venv\scripts\waitress-serve.exe --host=127.0.0.1 --port=%1 myapp:wsgifunc
请注意,HTTP 平台处理程序将在端口上动态设置,并通过 FLASK_RUN_PORT 环境变量将其传递到 python 进程中,flask 将自动将其作为端口配置。
安全注意事项:
- 确保您只将您的 Flask 应用程序绑定到本地主机,因此它不会直接从外部可见 - 特别是如果您通过 IIS 使用身份验证
- 在上面的示例中,forwardWindowsAuthToken 被设置,然后可用于依赖由 IIS 完成的 Windows 集成身份验证,然后将令牌传递给 Python,您可以从 Python 获取经过身份验证的用户名。我已经记录了 here。实际上,我将其用于基于 Kerberos 和 AD 组的授权的单点登录,因此效果非常好。
仅侦听本地主机/环回适配器以避免外部请求直接访问 python 应用程序的示例。如果您希望所有请求都通过 IIS。
if __name__ == "__main__":
app.run(host=127.0.0.1)