如何用 Turso 吞吐基准测试测量并发写入事务的每秒事务数?
【免费下载链接】tursoA SQL database in Rust: SQLite-compatible, now also speaking Postgres (experimental). The LLVM of databases.项目地址: https://gitcode.com/GitHub_Trending/tu/turso
仓库里的perf/throughput目录提供了txn-throughput基准测试,用来测量 SQLite 和 Turso 在多个连接同时写入时每秒能提交多少小写入事务(transactions per second)。它把连接数当作同时执行的事务数逐步扫过,从 1 个一直扫到远超 CPU 核心数的范围,并把每个吞吐点与进程 CPU 占用、磁盘活动和 checkpoint 耗时放在一起报告。本文按文档给出的路径,从环境准备、快速试跑、完整基准到结果读取和正确性校验,走通一次测量。
这个基准到底在测什么
测量方式是闭环(closed loop):每个连接在上一笔事务提交后立即开始下一笔,因此连接数就等于在途事务数。吞吐量定义为测量窗口内开始的事务数除以窗口时长,所有引擎和配置使用相同的墙钟时间,且包含 checkpoint 阶段。关键设定(来自 perf/throughput/README.md):
- 单表
test_table(id INTEGER PRIMARY KEY, data TEXT),每个事务插入BATCH_SIZE行(默认 100),id 来自所有连接共享的计数器,事务之间不触碰同一行,竞争只发生在引擎自身写入路径上; - 两个引擎都运行
PRAGMA synchronous = FULL,每次 commit 都以 fsync 结束; - SQLite 侧使用 WAL 模式、每连接一个线程(通过
rusqlite)和BEGIN IMMEDIATE;Turso 侧使用 MVCC(PRAGMA journal_mode = mvcc)、每连接一个独立 tokio runtime、BEGIN CONCURRENT,Linux 上使用 io_uring 后端; - 写连接的 auto-checkpoint 关闭,由独立连接每
CHECKPOINTER毫秒(默认 1000)执行一次PRAGMA wal_checkpoint(PASSIVE),与服务器实际行为一致。
每笔事务的 begin、work、commit 耗时都会被记录,重启(restarted)次数计入其服务时间。
准备条件
README 列出的环境要求:
- Rust 工具链(脚本通过
cargo build --release -p txn-throughput构建测试框架); uv,用于绘制结果图;- Linux,供 Turso 的 io_uring 后端使用;
- 可
sudo的账号:每轮运行前脚本会执行sudo fstrim和echo 3 | sudo tee /proc/sys/vm/drop_caches。
最后一条有实际副作用:fstrim会向数据库所在挂载点的磁盘发出 TRIM 命令,drop_caches会丢弃系统 page cache。文档说明这样做的目的是让消费者级 SSD 在空闲期排空写缓存、避免后一轮继承前一轮的写积压;如果你不希望修改磁盘状态或没有 root 权限,这一步无法省略,也就不能直接跑完整的run.sh流程(可改为直接运行单次 harness,见下文"可选:直接运行单次 harness")。
txn-throughput是 cargo workspace 的成员(见根 Cargo.toml 中perf/throughput),所以在仓库根目录下即可完成构建。另外 scripts/bench.sh 通过git rev-parse --show-toplevel定位仓库根目录,需要在 git 检出中运行。
快速试跑:缩短参数验证流程
完整基准耗时很长,先用文档给出的缩短配置跑一遍,确认工具链、sudo 和输出路径都正常:
CONNS="1 8 64" REPEATS=2 DURATION=10 IDLE=5 ./scripts/run.sh命令在perf/throughput目录下执行。含义:只在 1、8、64 三个连接数上各跑 2 次,每次只测量 10 秒(默认 30 秒),fstrim后只空闲 5 秒(默认 30 秒)。环境变量由 scripts/bench.sh 读取,run.sh调用它,因此两个入口都接受这些变量。
完整基准(./scripts/run.sh不带任何变量)会在 1、2、4、8、16、32、64 个连接上各跑 3 次并绘图。README 估计耗时约一小时,其中一半是每轮运行前 30 秒的磁盘空闲等待;而 scripts/run.sh 的注释写的是约两小时。两处口径不一致,按较保守的估计预留时间即可。
可选:直接运行单次 harness
如果想跑单个引擎、单个连接数的配置而不走脚本,先构建再直接调用二进制。scripts/bench.sh 展示的构建和调用方式为:
cargo build --release -p txn-throughput二进制默认位于 cargo target 的release目录(脚本通过仓库自带的scripts/cargo-target-dir查询实际位置,尊重CARGO_TARGET_DIR)。参数与 bench.sh 中一致:
cargo run --release -p txn-throughput -- \ --engine turso --connections 16 \ --batch-size 100 --checkpointer 1000 \ --duration 30 --warmup 3 --run 1 \ --db-dir ./db --out-dir ./plot--engine取sqlite或turso。--db-dir存放数据库文件,--out-dir存放结果文件;每次运行会写入自己的文件,拒绝覆盖已存在的文件,拒绝时提示already exists; remove it or pass another --db-dir/--out-dir。txn-throughput --help列出了全部选项,其中与对比相关的两个:
--mode immediate:让 Turso 以 WAL +BEGIN IMMEDIATE运行,与 SQLite 相同的单写者路径(SQLite 只支持immediate模式);--io syscall:切换 Turso 的 IO 后端(Linux 上默认io_uring,非 Linux 默认syscall,见 main.rs 中的DEFAULT_IO)。
如何读到"每秒事务数"
一次完整运行结束后,TPS 出现在三处:
- 终端与
plot/bench.log:每轮运行打印摘要,形如{引擎} transactions, {行数} rows in {秒} s: {transactions/s}, {rows/s},随后是服务时间分位数(p50/p99/p99.9/max)、CPU(user、sys、占一个核心的百分比、占全部硬件线程的百分比、每事务微秒数)、磁盘写入统计和 checkpoint 的 p50/max 耗时。bench.log开头还记录机器型号、硬件线程数、内核版本和磁盘信息,方便复现时对照环境; plot/<engine>-c<connections>-r<run>-result.csv:每轮一行,包含transactions_per_s、rows_per_s、cpu_us_per_transaction、restarts、各分位数、磁盘写入量与 checkpoint 统计;plot/throughput.png(及.pdf、.tikz):左轴是 TPS 随连接数的变化,右轴(0–100%)是进程 CPU 占全部硬件线程的份额,每个点是各次运行的均值并带一个标准差的误差棒。run.sh在跑完全部配置后用uv run plot/plot-throughput.py自动生成这三份图。
另外每轮还会写三个明细 CSV:...-r<run>.csv记录每个事务的开始时刻、是否预热、重启次数和 begin/work/commit 耗时;...-timeline.csv按秒记录每秒提交的事务数和 CPU 占用;...-checkpoints.csv记录每次 checkpoint 的开始时刻与耗时。所有数据库文件保留在db/<timestamp>/下,脚本不会删除任何历史文件。
结果可信度如何判断
harness 自带一次正确性校验:运行结束后通过一条全新连接对表做SELECT count(*),行数必须等于已提交事务数乘以BATCH_SIZE,不一致时打印the table holds N rows but M transactions of B rows committed并以退出码 1 结束(见 main.rs)。所以一次运行"跑完且退出码为 0"本身就包含了落盘数据完整性的检查;bench.sh也把每一轮 harness 的退出状态单独取出,非 0 即整体终止。
解读结果时的两个文档提示:
- 每轮都从一个全新的空数据库文件开始,测量 30 秒前有 3 秒预热(预热期的事务会被记录但标记为 warmup,不参与汇总和绘图);
- 奇数次重复按连接数从小到大扫描,偶数次从大到小,顺序效应会体现为两者的差异——对比结果时应成对看,而不是只取某一次。
限制与不适用情况
- 该流程要求能执行
sudo fstrim与清空 page cache,缺少相应权限时不能按文档路径复现完整基准; - 磁盘统计来自
/proc/diskstats,仅在 Linux 上可用; - 输出目录中若已有同名结果文件,运行会拒绝覆盖而不是静默替换;重跑时换
OUT/DB_DIR或先移走旧文件(仓库本身只读约束下,在自有检出中操作)。
如果只需要单次配置的 TPS 而非完整对比曲线,直接用上文"单次 harness"的路径;需要 SQLite 与 Turso 全连接数扫描加绘图时,主路径就是./scripts/run.sh。
【免费下载链接】tursoA SQL database in Rust: SQLite-compatible, now also speaking Postgres (experimental). The LLVM of databases.项目地址: https://gitcode.com/GitHub_Trending/tu/turso
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考