当注入磁盘填满故障时,如何观察“_dbs_info”返回的“error”字段?
解读
国内生产环境普遍把 CouchDB 跑在容器或云主机里,磁盘满属于高频故障。面试官想知道两点:
- 你是否主动制造过磁盘满场景并熟悉 CouchDB 的防御机制;
- 你是否能用最小权限、最小影响快速拿到“_dbs_info”里的 error 字段,而不是去翻巨量的日志。
因此,回答要给出可复现的注入步骤、观测命令以及字段解析,并体现你对国内监控体系(如阿里云云监控、夜莺、Prometheus)的对接思路。
知识点
- 磁盘满触发条件:CouchDB 在剩余空间低于
disk_failure_threshold(默认 10%)时,对写请求返回 507 Insufficient Storage,并在内部把数据库标记为 “nonsense” 状态。 - “_dbs_info” 端点:GET /_dbs_info?keys=[“db1”,”db2”] 会返回数组,每个成员含
{“key”:”db1”,”info”:{…},”error”:null};若库不可访问,error 字段为字符串而非 null。 - error 字段值空间:
- “nonsense” —— 磁盘满导致元数据损坏;
- “internal_error” —— 其他运行时异常;
- “no_db_file” —— 文件被误删。
- 注入手段:国内机房常用
dd if=/dev/zero of=/data/dummy bs=1M count=$[(90%*总空间)]快速打满磁盘;容器场景则kubectl exec -it couchdb-0 -- sh -c 'dd if=/dev/zero of=/opt/couchdb/data/dummy'。 - 观测工具:curl + jq 是最低依赖;若现场不允许外网,用容器内 busybox 的 awk 也能解析。
- 恢复验证:清理 dummy 文件后,需主动 PUT /_node/_local/_config/couchdb/disk_failure_threshold 临时调到 1%,再调回 10%,触发 CouchDB 重新检测,否则“nonsense”标记不会自动解除。
答案
-
注入磁盘满
以非 root 用户登录 CouchDB 宿主机,找到 data 目录挂载点,执行
df -h /data确认剩余空间,然后
dd if=/dev/zero of=/data/fill$(date +%s).tmp bs=1M count=剩余MB-500
迅速把可用空间压到 5% 以下(低于 10% 阈值即可)。 -
触发写请求
任意写一条 doc:
curl -X POST http://<user>:<pwd>@127.0.0.1:5984/proddb -H Content-Type:application/json -d '{"_id":"test"}'
此时 CouchDB 返回 507,内部把 proddb 标记为 nonsense。 -
观察 _dbs_info 的 error 字段
curl -s http://<user>:<pwd>@127.0.0.1:5984/_dbs_info?keys='["proddb"]' | jq '.[].error'
若磁盘满导致元数据损坏,会输出 "nonsense";若只是临时 IO 错误,可能输出 "internal_error"。
无 jq 时:
curl -s ... | awk -F'"error":' '{print $2}' | awk -F'"' '{print $2}' -
清理与恢复
rm /data/fill*.tmp
等待 30s 后再次调用 _dbs_info,若 error 仍为 “nonsense”,需手动刷新阈值:
curl -X PUT http://<user>:<pwd>@127.0.0.1:5984/_node/_local/_config/couchdb/disk_failure_threshold -d '"1%"'
curl -X PUT ... -d '"10%"'
再次查询,error 字段应返回 null,表示库已可用。
拓展思考
- 自动化观测:把
curl _dbs_info | jq -r '.[].error'封装成 exporter,配合阿里云云监控自定义脚本,每 60s 上报,error!=null 时直接触发电话告警。 - 灰度限流:在磁盘剩余 15% 时,通过 nginx+lua 拦截写请求,提前降级,避免进入 nonsense 状态。
- 多租户隔离:国内 SaaS 厂商常把每个租户独立成库,利用 _dbs_info 批量巡检,可在 1s 内扫描上千库,比轮询 /db/_info 节省 90% 开销。
- 容器场景:把 emptyDir 大小限制在 70% 宿主机盘,配合 kubelet 的 eviction-hard=imagefs.available<10%,让 Pod 提前被驱逐,防止进入 nonsense 后人工介入困难。