实测怎样测试 Flask 的 session:session_transaction 预置与读取、with client 保留上下文读 session、flash 消息存在 _flashes 里读一次就消费、直接预置 _user_id 来模拟 Flask-Login 登录、断言登录后的 Set-Cookie 属性、拨快时钟测试 permanent session 的过期。
用真实的 pytest 运行 10 个 Flask 文件上传测试:(BytesIO, 文件名) 元组即文件字段、tmp_path 保存上传文件、自动 multipart 与按文件名猜 mimetype、缺文件与空文件名返回 400、同名多文件用列表与 getlist、200 KB 超过 100 KB 限制返回 413、读指针不在开头只会读到剩下的字节。
用真实的 pytest 运行 8 个 Flask 异常处理器测试:自定义异常与 404 处理器返回 JSON、没注册的 abort 返回默认 HTML、TESTING 下未处理的异常抛进测试而 PROPAGATE_EXCEPTIONS=False 或 TESTING=False 时走 500 处理器、蓝图处理器只管蓝图自己的视图、用测试固定错误响应的字段。
用真实的 pytest 运行 9 个 Flask Blueprint 测试:最小应用只注册一个蓝图、端点名带蓝图前缀与 url_for 的点写法、蓝图钩子只作用于自己的请求、注册时覆盖 url_prefix、同一蓝图注册两次要 name、隔离的应用里路由表只含该蓝图。
实测请求耗时统计:after_request 钩子记不到流式响应的真实耗时(0.02 ms 对中间件 325 ms)、500 响应也会走 after_request、计时开销约 9 µs/请求、5% 慢请求时平均 21.1 ms 而 p99 是 210 ms。
在真实的 PostgreSQL 上做慢 SQL 统计:应用侧用 SQLAlchemy 游标事件按去参数的语句聚合并标出端点、按总耗时找出全表扫描的 count(*) LIKE、按次数找出 600 次的 N+1 语句,再对照 pg_stat_statements 的服务端统计(同一条 N+1 语句数据库里共 1.0 ms 而应用侧是 49.6 ms)。
实测 Flask 的性能剖析:Werkzeug 的 ProfilerMiddleware(cProfile)对一个混合视图给出 tottime 表、空视图被拖慢 5.4 倍、profile_dir 写 .prof 文件事后用 pstats 分析、采样式 pyinstrument 输出调用树且开销更小(41.0 ms 对 cProfile 的 47.4 ms)。
实测 Jinja2 模板渲染耗时:第一次渲染含编译 2.51 ms 而之后 1.36 ms、render_template_string 比文件模板慢约 31 倍、循环里 include 比直接写慢约 2.6 倍、|safe 并不更快、TEMPLATES_AUTO_RELOAD 的开销很小、用模板信号统计渲染耗时。
实测 Flask 的 JSON 序列化性能:1 万行标准库 json 7.1 ms 对 orjson 0.92 ms、sort_keys 的额外开销、含 datetime 与 Decimal 时 default 钩子让标准库慢到 16.7 ms、Flask 默认 provider 对自写 orjson provider(30.0 对 2.3 ms)、dataclasses.asdict 比 json.dumps 还慢。
在 10 核机器上实测 gunicorn worker 数量:纯 CPU 请求吞吐到 worker=核数(10 个 663 请求/秒)就到顶,再加到 32 个 p99 反而变差;带 20 ms 等待的请求超过核数仍在涨(10 个 304 到 32 个 625 请求/秒);每多一个 worker 约多 34 MB 内存。
实测 gunicorn 的 worker timeout:2 个 worker 时一个被杀的 worker 不影响服务(/fast 失败 0、p99 6 ms);只有 1 个 worker 时,不加 --preload 的排队请求最多等 4149 ms,--preload 降到 2623 ms;--timeout 0 时慢请求永不被杀。
在真实的 PostgreSQL 上实测连接池大小:每个 20 ms 的数据库请求,pool_size 从 1 到 20 吞吐从 41 增长到 829 请求/秒;池 2 加 0.5 秒超时时 300 个请求只成功 16 个;4 个 worker × pool 10 超过数据库 max_connections=20 时 270 个请求失败且监控连接也被拒。