尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

阶段七 · Capstone 综合大作业:端到端串联 Linux + Flask + pytest + 性能压测(华为云 ECS 真机)

阶段七 · Capstone 综合大作业:端到端串联 Linux + Flask + pytest + 性能压测(华为云 ECS 真机) 阶段七 · Capstone 综合大作业端到端串联 Linux Flask pytest 性能压测华为云 ECS 真机系列AI 全能测试工程师 · 全链路真机实操阶段阶段七 · 综合大作业Capstone真机华为云 ECSHuawei Cloud EulerOS 2.08vCPU/16GBPython 3.9.9时长约 6 小时含设计、踩坑、压测前置阶段一Linux/MySQL、阶段三Python/Flask、阶段四pytest、阶段六性能压测学完前六个阶段你掌握了单点能力Linux 运维、接口开发、自动化、性能压测。但真实项目里这些能力是串成一条流水线的——服务要作为进程跑在 Linux 上、接口要被测、变更要被自动化守护、上线前要做压测。本篇用一个智能订单履约系统把它们全部串起来并在华为云 ECS 真机上一次性跑通。⚠️ 本文所有命令与数据均来自ecs-24f5-2db6-0004120.46.93.25EulerOS 2.0真实执行输出未经篡改可复现。目录1. 为什么需要综合大作业2. 项目架构与目录结构3. 环境准备真机4. 阶段一视角服务即进程Linux5. 阶段二视角Flask REST API6. 阶段三视角pytest 接口自动化7. 阶段四视角性能压测8. 踩坑实录3 个真实坑9. 性能解读与延伸10. 小结附完整源码1. 为什么需要综合大作业单点练习容易陷入我会了某个工具但面试和工作中问的是你能把一套系统从启动、测试到压测完整地交付吗本 Capstone 用最小但完整的系统回答这个问题Linux 进程/日志 ──► Flask REST API ──► pytest 自动化 ──► 性能压测 (阶段一) (阶段二/三) (阶段四) (阶段六) └────────────── 一条 E2E 流水线 ──────────────┘我们用一个订单履约系统管理商品、下单校验库存、统计营收。它够小能在一台 8C16G 的 ECS 上跑通也够真覆盖数据库、并发、接口契约、自动化与性能。2. 项目架构与目录结构/opt/capstone/ ├── capstone_app.py # Flask 应用SQLite 存储REST 接口 ├── test_capstone.py # pytest 接口自动化用例 ├── capstone_loadgen.py # 纯 requests 压测脚本等价 Locust 混合场景 ├── capstone_runner.py # 端到端运行器前台单进程 harness └── capstone.db # 运行时生成的 SQLite 库数据流capstone_runner 启动线程拉起 Flask :5001pytest 调真实接口 8 用例loadgen 50并发/60s终态统计 /api/stats说明用 Mermaid 画架构图是技术博客的加分项——读者一眼看懂数据流。下面所有代码块都标注了语言便于阅读与复制。3. 环境准备真机在 ECS-0004 上确认环境真实输出[rootecs-24f5-2db6-0004 ~]# python3 --versionPython3.9.9[rootecs-24f5-2db6-0004 ~]# python3 -c import sqlite3; print(sqlite3.sqlite_version)3.37.2[rootecs-24f5-2db6-0004 ~]# pip show flask requests | grep -E Name|VersionName: Flask Version:3.1.3 Name: requests Version:2.32.5仅缺 pytest安装即可EulerOS 用系统 pip注意它提示用 root 安装实验环境可接受pipinstallpytest-qpython3-mpytest--version# pytest 8.4.2⚠️为什么用 SQLite 而不是 MySQL为了单机端到端可复现SQLite 零部署、文件即库。但它也是后文性能瓶颈的源头——这恰好是教学价值所在。生产环境应换 MySQL/PostgreSQL 连接池。4. 阶段一视角服务即进程Linux在 Linux 眼里这个系统就是一个进程。运行器用线程在进程内拉起 Flask等价于python3 capstone_app.py后台常驻# 启动前台 harness 模式避免 EulerOS SSH 后台进程挂死cd/opt/capstonepython3 capstone_runner.pycap_out.txt21真机启动日志节选* Serving Flask app capstone_app * Debug mode: off * Running on http://127.0.0.1:5001 服务已就绪: http://127.0.0.1:5001运维要点对应阶段一进程管理用pgrep -af [c]apstone查进程pkill -f [c]apstone回收正则加[]避免误杀自身。日志Flask 开发服务器把每个请求打到 stdout生产应落gunicorn 日志文件。端口本例用5001避免与既有服务冲突。5. 阶段二视角Flask REST API核心应用capstone_app.py关键接口如下真实代码app.route(/api/products,methods[POST])defcreate_product():datarequest.get_json(silentTrue)or{}name(data.get(name)or).strip()try:pricefloat(data.get(price))stockint(data.get(stock,0))except(TypeError,ValueError):returnjsonify({error:price/stock 必须为数字}),400ifnotname:returnjsonify({error:商品名称不能为空}),400ifprice0:returnjsonify({error:价格不能为负}),400ifstock0:returnjsonify({error:库存不能为负}),400with_db_lock,get_db()asdb:curdb.execute(INSERT INTO products (name, price, stock) VALUES (?, ?, ?),(name,price,stock),)db.commit()pidcur.lastrowidreturnjsonify({id:pid,name:name,price:price,stock:stock}),201下单接口做库存校验这是业务正确性核心也是自动化重点app.route(/api/orders,methods[POST])defcreate_order():datarequest.get_json(silentTrue)or{}try:pidint(data.get(product_id))qtyint(data.get(qty))except(TypeError,ValueError):returnjsonify({error:product_id/qty 必须为整数}),400ifqty0:returnjsonify({error:购买数量必须大于 0}),400with_db_lock:withget_db()asdb:rowdb.execute(SELECT id, price, stock FROM products WHERE id ?,(pid,)).fetchone()ifrowisNone:returnjsonify({error:商品不存在}),404ifrow[stock]qty:returnjsonify({error:库存不足,available:row[stock]}),409totalround(row[price]*qty,2)curdb.execute(INSERT INTO orders (product_id, qty, total) VALUES (?, ?, ?),(pid,qty,total),)db.execute(UPDATE products SET stock stock - ? WHERE id ?,(qty,pid))db.commit()oidcur.lastrowidreturnjsonify({id:oid,product_id:pid,qty:qty,total:total}),201接口契约总结这正是接口测试要覆盖的边界接口成功关键异常POST /api/products201400空名/负价/负库存/类型错POST /api/orders201400qty≤0/ 404商品不存在/ 409库存不足GET /api/orders/id200404订单不存在GET /api/stats200聚合 product/order 数 营收6. 阶段三视角pytest 接口自动化test_capstone.py直接打真实运行中的服务不是 mock覆盖健康、增查、下单成功/失败、统计deftest_order_success():prequests.post(f{BASE}/api/products,json{name:显示器,price:1299.0,stock:10},timeout5).json()pidp[id]rrequests.post(f{BASE}/api/orders,json{product_id:pid,qty:2},timeout5)assertr.status_code201assertr.json()[total]2598.0# 1299 * 2# 库存应被扣减stockrequests.get(f{BASE}/api/products,timeout5).json()prodnext(xforxinstockifx[id]pid)assertprod[stock]8deftest_order_insufficient_stock():prequests.post(f{BASE}/api/products,json{name:显卡,price:5999.0,stock:1},timeout5).json()rrequests.post(f{BASE}/api/orders,json{product_id:p[id],qty:5},timeout5)assertr.status_code409# 库存不足真机执行结果8 个用例全部通过 test session starts collecting ... collected 8 items test_health PASSED [ 12%] test_create_product_and_list PASSED [ 25%] test_create_product_validation PASSED [ 37%] test_order_success PASSED [ 50%] test_order_product_not_found PASSED [ 62%] test_order_insufficient_stock PASSED [ 75%] test_order_bad_qty PASSED [ 87%] test_stats_aggregation PASSED [100%] 8 passed in 0.12s 接口自动化不是能跑就行而是把业务契约钉死。今天total算错、明天库存没扣pytest 立刻红灯——这就是自动化的价值。7. 阶段四视角性能压测压测脚本capstone_loadgen.py用纯requests 多线程模拟70% 读health/products/stats 30% 写建商品的混合场景口径与 Locust/JMeter 一致。真机 50 并发压 60 秒 启动压测: 并发50 时长60s 目标http://127.0.0.1:5001 Capstone 压测报告 总请求数: 7751 失败数: 0 (错误率 0.00%) 持续时长: 61.7s 吞吐量: 125.7 RPS 平均RT: 393.6 ms 最小RT: 1.6 ms 最大RT: 3228.8 ms P50: 10.8 ms P90: 1880.6 ms P95: 2517.1 ms P99: 3063.9 ms END 压测后终态业务统计真实 阶段C最终业务统计 stats: {order_count: 1, product_count: 2253, product_stock: 112609, revenue: 2598.0}解读错误率 0%说明接口在并发下功能稳定但 RPS 仅 125、P95 高达 2.5s——这背后是一个教科书级的并发问题见下一节。8. 踩坑实录3 个真实坑这些不是编的是本次真机运行当场遇到的。坑 1高并发下sqlite3.OperationalError: database is locked压测一开始疯狂报错[2026-08-17 11:52:08,477] ERROR in app: Exception on /api/products [GET] sqlite3.OperationalError: database is locked原因SQLite 默认串行写、单连接无等待超时。50 线程同时建连接读被写阻塞就直接抛错。修复WAL 模式 忙等待超时defget_db():connsqlite3.connect(DB_PATH,timeout30,check_same_threadFalse)conn.row_factorysqlite3.Row conn.execute(PRAGMA busy_timeout30000)# 抢不到锁就等而非报错returnconndefinit_db():with_db_lock,get_db()asdb:...db.commit()db.execute(PRAGMA journal_modeWAL)# 读不阻塞写修复后错误率从 ~25% 降到0.00%——这就是不改业务、只改存储配置的典型优化。坑 2python3 test_xxx.py根本没跑测试第一版运行器写的是python3 test_capstone.py -v结果pytest exit0却一个 PASSED 都没有。原因python3 test_xxx.py只是 import 模块就退出了pytest 根本没被调用。正确姿势是python3-mpytest test_capstone.py-v# 用 -m pytest 入口坑 3EulerOS SSH 后台进程挂死EXIT CODE: -1最初用nohup python3 capstone_runner.py 想后台跑SSH 通道直接返回-1且拿不到输出。解决前台单进程 harness——在 Python 内线程拉起 Flask再用子进程跑 pytest/loadgen全部输出落盘到文件再拉回详见capstone_runner.py。9. 性能解读与延伸为什么 8C16G 的机器RPS 只有 125、P95 2.5s写被串行化下单/建商品都走_db_lock全局锁50 线程的写请求只能排队。SQLite 的并发天花板即便开了 WALSQLite 仍是单写者模型不适合高并发写入。开发服务器Flask 自带的 WSGI 是单进程开发服务器生产该用gunicorn -w 4多 worker。延伸路线图把 Capstone 升级成生产级维度现状教学生产建议存储SQLite 文件MySQL/PostgreSQL 连接池SQLAlchemy并发写全局锁串行数据库自身事务 乐观锁服务Flask dev servergunicorn/uvicorn 多 worker自动化本地 pytestCI 流水线GitHub Actions质量门禁压测纯 requests 脚本Locust/JMeter 分布式 监控Prometheus这正是全能测试工程师的成长路径从能跑通到懂瓶颈再到能治理。10. 小结通过这一个 Capstone你完成了一条 E2E 流水线服务启动 → pytest 8 用例全过 → 50 并发 60s 压测 0 错误 → 业务统计落库全部在华为云 ECS 真机一次跑通。三个真实踩坑database is lockedWAL 修复、pytest 调用方式、EulerOS SSH 后台挂死前台 harness每一个都是面试和工作中会撞上的。性能直觉看到 RPS 125 / P95 2.5s能立刻定位到SQLite 写串行化并给出生产级演进方案。⚠️ 实验环境机器为按时计费体验机运行窗口有限本文数据已落盘于cap_out.txt源码见仓库code/capstone/可自取复现。至此AI 全能测试工程师 全链路真机实操系列阶段一 ~ 七全部交付。附完整源码完整可运行源码取自真机见仓库code/capstone/capstone_app.py—— Flask 应用含 WAL/busy_timeout 修复test_capstone.py—— pytest 8 用例capstone_loadgen.py—— 50 并发压测脚本capstone_runner.py—— 端到端前台运行器复现命令cd/opt/capstone python3-mpipinstallflask requests pytest-qrm-fcapstone.db capstone.db-wal capstone.db-shm python3 capstone_runner.pycap_out.txt21catcap_out.txt
返回列表