AsmBB 日常运维手册
AsmBB v3.0 运维闭环:五面巡检、SQLite WAL 备份大坑实录与 .backup 正确姿势、恢复流程、监控指标、983.9 req/s 压测基线、二进制换装与 v2.9→v3.0 迁移、八类故障排查实录,全部实测回显。
AsmBB 日常运维手册
目标:给出 AsmBB v3.0 上线后的日常运维闭环——巡检、备份与恢复(含 SQLite WAL 大坑实录)、监控告警、容量评估、升级回滚与七类故障排查,全部命令与回显来自 Ubuntu 22.04 生产形态环境实测。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86-64)
- 论坛引擎:AsmBB v3.0(manifest.uuid
3df85ed0b218e51a59fe3f02650ef7467050cc46),systemd 单元asmbb.service,运行用户www-data - Web 服务器:Nginx 1.18.0 (Ubuntu)(80/443),备用 Lighttpd 1.4.63(8081)
- 站点目录:
/var/www/asmbb;数据库:/var/www/asmbb/board.sqlite(WAL 模式);备份目录:/var/www/asmbb/backup - 引擎套接字:
/var/www/asmbb/engine.sock - 邮件中继:Postfix 3.6.4(127.0.0.1:25)
- 部署过程见 《Ubuntu 22.04 安装 AsmBB v3.0 指南》
二、日常巡检
巡检目标:确认引擎进程、套接字、HTTP 出口、数据库完整性与容量五个面都健康。以下命令构成最小巡检集,建议每日执行。
2.1 服务与进程状态
root@forum:~# systemctl is-active asmbb nginx
active
active
root@forum:~# systemctl status asmbb | head -8
● asmbb.service - AsmBB forum engine FastCGI script.
Loaded: loaded (/etc/systemd/system/asmbb.service; disabled; vendor preset: enabled)
Active: active (running) since Mon 2026-11-02 00:15:31 UTC; 9min ago
Main PID: 3214 (engine)
Tasks: 2 (limit: 2506)
Memory: 3.1M
CPU: 66ms
输出节选(实测首尾)。要点:Active: active (running)、Tasks: 2(主进程+工作线程组)、Memory 应为个位数 MB——若持续涨到数百 MB 属异常,按 7.3 处理。
root@forum:~# ps -eo pid,user,rss,vsz,cmd | grep [e]ngine
3214 www-data 2664 3208 /var/www/asmbb/engine
RSS 2664 KB 即引擎常态内存。若出现多行 engine 进程,说明 Lighttpd spawn 实例也在运行(两方案共存形态,属正常)。
2.2 套接字与 HTTP 出口
root@forum:~# ls -l /var/www/asmbb/engine.sock
srw-rw-rw- 1 www-data www-data 0 Nov 2 00:15 /var/www/asmbb/engine.sock
root@forum:~# curl -s -o /dev/null -w "http %{http_code} %{time_total}s\n" http://127.0.0.1/
http 200 0.002300s
判定标准:套接字存在且为 srw 开头;HTTP 200 且整页耗时毫秒级。页面页脚还自带耗时统计,可直接作为探针指标:
root@forum:~# curl -s http://127.0.0.1/ | grep -oE "Page processing time: [0-9.]+ ms"
Page processing time: 2.533 ms
2.3 数据库完整性与业务量
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "PRAGMA integrity_check;"
ok
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "select (select count(*) from threads),(select count(*) from posts),(select count(*) from users),(select count(*) from eventqueue),(select count(*) from waitingactivation),(select count(*) from userlog);"
1|1|1|2|0|37
六列依次为:主题数、帖子数、用户数、事件队列积压、待激活用户、用户操作日志数。eventqueue 持续增大说明后台任务(如邮件投递)在积压,结合 4.2 看 mail.log。
2.4 引擎日志
引擎自身不写日志文件,异常经 systemd/journald 收集:
root@forum:~# journalctl -u asmbb --no-pager | tail -4
Nov 02 00:58:57 forum.quzuo.local systemd[1]: asmbb.service: Deactivated successfully.
Nov 02 00:58:57 forum.quzuo.local systemd[1]: Stopped AsmBB forum engine FastCGI script..
Nov 02 00:58:57 forum.quzuo.local systemd[1]: asmbb.service: Consumed 3.959s CPU time.
Nov 02 00:58:58 forum.quzuo.local systemd[1]: Started AsmBB forum engine FastCGI script..
三、备份与恢复
AsmBB 全部数据就是 board.sqlite 一个文件,但它是 WAL 日志模式——直接热拷贝主库文件会丢数据,本章先给踩坑实录,再给正确姿势。
3.1 踩坑实录:cp 热拷贝丢 WAL 数据
WAL 模式下最新事务先写 board.sqlite-wal,未合并回主库。实测拷贝走热备份再恢复后,论坛数据全部丢失:
root@forum:~# cp /var/www/asmbb/board.sqlite /var/www/asmbb/backup/board-20261102-004357.sqlite
root@forum:~# ls -la /var/www/asmbb/backup/
total 396
drwxr-xr-x 2 root root 4096 Nov 2 00:43 .
drwxr-xr-x 5 www-data www-data 4096 Nov 2 00:43 ..
-rw-r--r-- 1 root root 397312 Nov 2 00:43 board-20261102-004357.sqlite
用该备份恢复后页面变成:
root@forum:~# curl -s http://127.0.0.1/ | grep -o '<title>[^<]*</title>'
<title>AsmBB: Create the admin account!</title>
root@forum:~# sqlite3 /var/www/asmbb/backup/board-20261102-004357.sqlite "select count(*) from threads;"
0
定位:备份时刻 -wal 里还压着管理员与帖子数据(对照 2.2 节环境:主库 397312 字节时 -wal 一度达 1495592 字节,比主库还大)。结论:严禁对运行中的 AsmBB 用 cp 做热备份。
3.2 正确姿势一:sqlite3 .backup 在线热备份
root@forum:~# TS=$(date +%Y%m%d-%H%M%S); sqlite3 /var/www/asmbb/board.sqlite ".backup /var/www/asmbb/backup/board-live-$TS.sqlite"
root@forum:~# ls -la /var/www/asmbb/backup/
total 784
drwxr-xr-x 2 root root 4096 Nov 2 00:45 .
drwxr-xr-x 5 www-data www-data 4096 Nov 2 00:45 ..
-rw-r--r-- 1 root root 397312 Nov 2 00:43 board-20261102-004357.sqlite
-rw-r--r-- 1 root root 397312 Nov 2 00:45 board-proper-004551.sqlite
-rw-r--r-- 1 root root 32768 Nov 2 00:45 board-proper-004551.sqlite-shm
-rw-r--r-- 1 root root 0 Nov 2 00:45 board-proper-004551.sqlite-wal
-rw-r--r-- 1 root root 397312 Nov 2 00:59 board-live-20261102-005915.sqlite
root@forum:~# sqlite3 /var/www/asmbb/backup/board-live-20261102-005915.sqlite "select count(*) from threads;"
1
.backup 走 SQLite 官方在线备份 API,引擎不停机即可拿到一致快照(实测备份中论坛正常 200)。注意备份库本身也是 WAL 模式,用 sqlite3 打开查询会给备份文件生成 -shm/-wal(上表 board-proper 两行即是),归档前可再执行 sqlite3 备份文件 "PRAGMA journal_mode=delete;" 收拢为单文件。
3.3 正确姿势二:停引擎冷备份
强一致需求(如升级前)用冷备份:systemctl stop asmbb 后直接 cp board.sqlite board.sqlite-wal board.sqlite-shm 三件套,或先停再 .backup。备份完成后 systemctl start asmbb。
3.4 定时备份
root@forum:~# cat /etc/cron.d/asmbb-backup
0 3 * * * root sqlite3 /var/www/asmbb/board.sqlite ".backup /var/www/asmbb/backup/board-$(date +%Y%m%d).sqlite"
每天 03:00 一份,按保留策略轮转旧文件即可。
3.5 恢复流程(含双引擎教训)
恢复必须先停掉所有引擎实例——3.1 那次恢复失败还有一个叠加因素:Lighttpd spawn 实例仍在运行,旧引擎进程继续持有原库句柄,恢复时出现「双引擎写同一目录」的混乱。标准流程:
root@forum:~# systemctl stop asmbb lighttpd nginx
root@forum:~# ps -eo pid,cmd | grep [e]ngine # 确认无残留进程,有则 kill
root@forum:~# rm -f /var/www/asmbb/board.sqlite-wal /var/www/asmbb/board.sqlite-shm
root@forum:~# cp /var/www/asmbb/backup/board-live-20261102-005915.sqlite /var/www/asmbb/board.sqlite
root@forum:~# chown www-data:www-data /var/www/asmbb/board.sqlite
root@forum:~# systemctl start nginx asmbb
root@forum:~# curl -s http://127.0.0.1/ | grep -o '<title>[^<]*</title>'
<title>AsmBB: Threads list /</title>
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "select count(*) from threads;"
1
要点:删除旧 -wal/-shm 是必须的——残留 WAL 会把旧数据"重放"到新库上造成错乱;恢复后页面标题应为 Threads list,若出现 Create the admin account! 说明恢复的库不含用户数据(回到 3.1 检查备份方式)。
四、监控告警
4.1 建议指标集
| 指标 | 采集命令 | 告警阈值建议 |
|---|---|---|
| 引擎存活 | systemctl is-active asmbb | 非 active 即告警 |
| HTTP 出口 | curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1/ | ≠200 告警 |
| 页面耗时 | curl -s http://127.0.0.1/ | grep -oE "Page processing time: [0-9.]+ ms" | >50ms 预警 |
| 常驻内存 | ps -eo rss,cmd | grep [e]ngine | RSS>100MB 预警 |
| 队列积压 | sqlite3 /var/www/asmbb/board.sqlite "select count(*) from eventqueue;" | >100 预警 |
| 邮件投递 | tail /var/log/mail.log | reject/defer 关键字告警 |
| 库体积 | ls -l /var/www/asmbb/board.sqlite* | 结合磁盘水位 |
4.2 邮件链路抽查
激活邮件是否真的在发,看 Postfix 队列日志即可(组合配置背景见 《AsmBB+Nginx+Postfix 组合实战指南》):
root@forum:~# tail -3 /var/log/mail.log
Nov 2 01:08:09 forum postfix/smtpd[8825]: connect from localhost[127.0.0.1]
Nov 2 01:08:09 forum postfix/smtpd[8825]: NOQUEUE: reject: RCPT from localhost[127.0.0.1]: 550 5.1.1 <tester4@forum.quzuo.local>: Recipient address rejected: User unknown in local recipient table; from=<"admin@forum.quzuo.local"@forum.quzuo.local> to=<tester4@forum.quzuo.local> proto=SMTP helo=<forum.quzuo.local>
Nov 2 01:08:09 forum postfix/smtpd[8825]: disconnect from localhost[127.0.0.1] helo=1 mail=1 rcpt=0/1 quit=1 commands=3/4
(此条即 7.5 的现场:引擎在发信,问题出在收件人不存在。)
五、扩容缩容
- 引擎并发上限是编译期常量:源码
source/fcgi.asm定义MAX_THREAD_CNT=20,单进程内最多 20 个工作线程,没有运行时参数可调。 - 压测基线(实测):
ab对首页 2000 请求压测:
root@forum:~# ab -n 2000 -c 20 http://127.0.0.1/
Complete requests: 2000
Requests per second: 983.90 [#/sec] (mean)
Time per request: 50.818 [ms] (mean)
Time per request: 1.016 [ms] (mean, across all concurrent requests)
Transfer rate: 23359.92 [Kbytes/sec] received
压测期间进程内存(两行分别为 systemd 常驻实例与 spawn 实例):
root@forum:~# ps -eo pid,user,rss,vsz,cmd | grep [e]ngine
6033 www-data 1912 2372 /var/www/asmbb/engine
6051 www-data 6356 10816 /var/www/asmbb/engine
复测一轮(n=500 c=20)为 823.15 req/s;Failed requests 454 全部是 Length 差异——动态页每请求长度不同(页脚耗时、会话 token),并非错误,ab 按长度判失败属工具口径:
root@forum:~# ab -n 500 -c 20 http://127.0.0.1/
Complete requests: 500
Failed requests: 454
(Connect: 0, Receive: 0, Length: 454, Exceptions: 0)
Requests per second: 823.15 [#/sec] (mean)
Time per request: 24.297 [ms] (mean)
Transfer rate: 19510.24 [Kbytes/sec] received
- 扩容路径:单节点纵向加 CPU 即可(引擎 RSS 压测峰值也仅 6 MB 量级,瓶颈在 CPU 与 SQLite 写盘)。不支持多写节点水平扩展:
board.sqlite是本地单文件 + WAL,跨机共享文件系统跑多引擎会损坏数据库。若需多实例分摊读压,可用 Lighttpdmax-procs多派生(同机),或前置缓存只读页。 - 缩容:引擎无配置内存上限,天然适合 512MB 级小机器;缩容后主要盯
board.sqlite-wal体积与磁盘水位。
六、升级与回滚
6.1 版本锁定与二进制换装演练
永久链接包永远指向最新构建,升级前先下载新版并比对 sha256 与 manifest.uuid,与现网不同才执行换装。官方升级动作 = 停引擎 → 替换 engine、ld-musl-i386.so、libsqlite3.so 三个文件(v3.0 发布公告原文步骤 4)→ 整目录替换 templates/(步骤 5)→ 起引擎。实测换装流程(本次以同版文件演练全流程):
root@forum:~# systemctl stop asmbb
root@forum:~# cp -a /var/www/asmbb/engine /var/www/asmbb/backup/engine.bak
root@forum:~# cp -f /root/dl/asmbb/engine /var/www/asmbb/engine
root@forum:~# cp -f /root/dl/asmbb/libsqlite3.so /var/www/asmbb/libsqlite3.so
root@forum:~# cp -f /root/dl/asmbb/ld-musl-i386.so /var/www/asmbb/ld-musl-i386.so
root@forum:~# chown www-data:www-data /var/www/asmbb/engine /var/www/asmbb/libsqlite3.so /var/www/asmbb/ld-musl-i386.so
root@forum:~# systemctl start asmbb
root@forum:~# curl -s -o /dev/null -w "换装后 HTTP %{http_code}\n" http://127.0.0.1/
换装后 HTTP 200
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "select count(*) from threads;"
1
6.2 跨大版本(v2.9.1 → v3.0)迁移要点
v3.0 与 v2.x 数据库结构不兼容,官方发布公告给出八步流程:①先解密数据库(SQLeet 与 v3.0 的 SQLite3MultipleCiphers 不兼容,加密库必须先解密)②备份 ③在 SQLite 控制台执行官方迁移 SQL ④停引擎替换三个二进制 ⑤整目录替换 templates/ ⑥启动 ⑦检查 ⑧需要时在设置页重新加密。迁移 SQL 核心节选(官方发布公告原文,完整脚本以公告页为准):
insert into Params values ('nu_post_interval', 0);
insert into Params values ('nu_post_interval_inc', 0);
insert into Params values ('nu_max_post_length', 0);
alter table Users add column LastPostTime integer default 0;
alter table Threads add column Rating integer default 0;
create table ThreadVoters (
threadID integer references Threads(id) on delete cascade on update cascade,
userID integer references Users(id) on delete cascade on update cascade,
Vote integer
);
-- 以及 PostsAI/PostsAD 两个触发器的重建(含发帖间隔统计逻辑)
执行顺序红线:迁移 SQL 必须在引擎停止状态下执行(避免触发器与旧引擎并发写),且第 3.2 节的热备份不能替代步骤②——升级备份请用 3.3 冷备份。
6.3 回滚
回滚 = 反向换装:systemctl stop asmbb → 把 backup/engine.bak 等旧文件放回 → 若做过跨版本迁移,同时按 3.5 恢复迁移前的冷备份库 → systemctl start asmbb → 验证 HTTP 200 与业务计数。因此升级前冷备份 + 旧二进制留存(backup 目录)两个条件必须同时满足。
七、故障排查手册
7.1 502 Bad Gateway
现象:Nginx 502。定位链:systemctl is-active asmbb → 引擎停了;ls -l /var/www/asmbb/engine.sock → 套接字没了。实测:
root@forum:~# systemctl stop asmbb
root@forum:~# curl -s -o /dev/null -w "stop后 HTTP %{http_code}\n" http://127.0.0.1/
stop后 HTTP 502
root@forum:~# systemctl start asmbb
root@forum:~# curl -s -o /dev/null -w "start后 HTTP %{http_code}\n" http://127.0.0.1/
start后 HTTP 200
7.2 引擎报「No such file or directory」但文件存在
root@forum:~# cd / && /var/www/asmbb/engine
bash: line 1: /var/www/asmbb/engine: No such file or directory
exit=127
真凶是相对路径解释器 ./ld-musl-i386.so(file engine 可见 interpreter ./ld-musl-i386.so)。任何启动方式(手工、systemd WorkingDirectory、Lighttpd enter-directory)都必须把工作目录设为站点目录。
7.3 kill -9 后套接字残留与自愈
引擎被 kill -9 后 engine.sock 残留为死文件,但 Restart=on-failure 让 systemd 立即拉起新实例,新实例重建套接字自恢复:
root@forum:~# ls -l /var/www/asmbb/engine.sock
srw-rw-rw- 1 www-data www-data 0 Nov 2 00:43 /var/www/asmbb/engine.sock
root@forum:~# systemctl status asmbb | head -3
Active: active (running) since Mon 2026-11-02 00:43:35 UTC; 742ms ago
Main PID: 5946 (engine)
root@forum:~# curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1/
HTTP 200
若未见自愈,检查单元是否带 Restart=on-failure,或手工 systemctl restart asmbb。
7.4 直改 Params 表不生效
引擎启动时把 Params 缓存进内存,sqlite3 直改库后论坛表现不变,必须重启引擎。实测写入 SMTP 参数后重启生效:
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "select id,val from params where id in ('email_confirm','forum_title','host','smtp_addr','smtp_port');"
email_confirm|1
forum_title|AsmBB Production Demo
host|forum.quzuo.local
smtp_addr|127.0.0.1
smtp_port|25
root@forum:~# systemctl restart asmbb && systemctl is-active asmbb
active
7.5 注册了却收不到激活邮件(smtp_user 为空静默不发)
实录:email_confirm=1、SMTP 地址端口都对,注册返回 302 user_created,但 mail.log 毫无动静——smtp_user 为空时引擎静默跳过发信。补上 smtp_user(如 admin@forum.quzuo.local)并重启引擎后,此前积压的注册事件经 EventQueue 自动重投,三封激活邮件一次性入队:
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "select id,val from params where id in ('smtp_user','smtp_addr','smtp_port','email_confirm');"
email_confirm|1
smtp_addr|127.0.0.1
smtp_port|25
smtp_user|admin@forum.quzuo.local
root@forum:~# tail -3 /var/log/mail.log
Nov 2 00:42:19 forum postfix/qmgr[5785]: 7DED0160F0B8: from=<"admin@forum.quzuo.local"@forum.quzuo.local>, size=857, nrcpt=1 (queue active)
Nov 2 00:42:19 forum postfix/qmgr[5785]: 7F1CE160F0BB: from=<"admin@forum.quzuo.local"@forum.quzuo.local>, size=860, nrcpt=1 (queue active)
Nov 2 00:42:19 forum postfix/qmgr[5785]: 810FE160F0B8: from=<"admin@forum.quzuo.local"@forum.quzuo.local>, size=860, nrcpt=1 (queue active)
注意发件人呈现为 "admin@forum.quzuo.local"@forum.quzuo.local(smtp_user 被当作显示名包了一层),属引擎行为而非配置错误。排查顺序:smtp_user 非空 → 引擎重启过 → mail.log 有无 reject(如 4.2 的 550 收件人不存在)。
7.6 恢复备份后显示「Create the admin account!」
两个原因:备份用了 cp 热拷贝丢了 WAL 数据(见 3.1);或恢复时没停全部引擎/没清 -wal/-shm(见 3.5)。用 .backup 产物按 3.5 流程重做即可。
7.7 Lighttpd 403 Forbidden
lighttpd HTTP 403 size 341 = FastCGI 没接上。依次检查:90-asmbb.conf 是否加载 mod_fastcgi(缺模块时报 unknown config-key fastcgi.server)、fastcgi.server 的 bin-path/enter-directory 是否指向站点目录。完整实录见 《Ubuntu 22.04 安装 AsmBB v3.0 指南》 5.2/5.3。
7.8 Nginx 起不来:cannot load certificate
root@forum:~# nginx -t
nginx: [emerg] cannot load certificate "/etc/nginx/ssl/asmbb.crt": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/nginx/ssl/asmbb.crt, r) error:10000080:BIO routines::no such file)
nginx: configuration file /etc/nginx/nginx.conf test failed
证书目录 /etc/nginx/ssl 不存在导致 openssl 与 nginx 连环失败。mkdir -p /etc/nginx/ssl 后重新签发自签证书即可(完整 TLS 配置实录见 《AsmBB+Nginx+Postfix 组合实战指南》)。
八、常见问题
Q1:AsmBB 有没有自己的日志文件?
没有。引擎无独立日志,进程级事件看 journalctl -u asmbb(见 2.4),业务级操作审计看数据库 UserLog 表(巡检 2.3 实测当前 37 条),邮件看 /var/log/mail.log。
Q2:board.sqlite 能不能收缩体积?
可以。停引擎后执行 VACUUM,实测流程与回显:
root@forum:~# systemctl stop asmbb
root@forum:~# sqlite3 /var/www/asmbb/board.sqlite "VACUUM;"
root@forum:~# ls -l /var/www/asmbb/board.sqlite
-rw-r--r-- 1 www-data www-data 397312 Nov 2 00:44 /var/www/asmbb/board.sqlite
root@forum:~# systemctl start asmbb
root@forum:~# curl -s -o /dev/null -w "vacuum后 HTTP %{http_code}\n" http://127.0.0.1/
vacuum后 HTTP 200
Q3:待激活用户堆着不动怎么办?
查 WaitingActivation 表与 mail.log:多为 7.5(smtp_user 空)或收件域不可达。手动激活可直接把激活链接(用户注册时引擎生成 !activate/<secret>)发给用户,或管理员在用户页处理。
Q4:ARM 服务器能跑吗? 官方二进制是 i386 ELF,不能。需自行用 FASM 从 Fossil 源码重编译(官方有编译安装帖),成本高,选型前先确认架构(见 《AsmBB 介绍与选型指南》 第六章限制)。
九、参考链接
- v3.0 发布公告(升级八步与迁移 SQL 原文):https://board.asm32.info/asmbb-v3-0-has-been-released.401/
- 官方安装文档 install.txt:https://asm32.info/fossil/repo/asmbb/doc/trunk/install.txt
- SQLite WAL 模式官方说明:https://www.sqlite.org/wal.html
- SQLite 在线备份
.backup:https://www.sqlite.org/backup.html - 站内相关:《Ubuntu 22.04 安装 AsmBB v3.0 指南》、《AsmBB 介绍与选型指南》