当注入磁盘填满故障时,如何观察“_dbs_info”返回的“error”字段?

解读

国内生产环境普遍把 CouchDB 跑在容器或云主机里,磁盘满属于高频故障。面试官想知道两点:

  1. 你是否主动制造过磁盘满场景并熟悉 CouchDB 的防御机制;
  2. 你是否能用最小权限、最小影响快速拿到“_dbs_info”里的 error 字段,而不是去翻巨量的日志。
    因此,回答要给出可复现的注入步骤观测命令以及字段解析,并体现你对国内监控体系(如阿里云云监控、夜莺、Prometheus)的对接思路。

知识点

  1. 磁盘满触发条件:CouchDB 在剩余空间低于 disk_failure_threshold(默认 10%)时,对写请求返回 507 Insufficient Storage,并在内部把数据库标记为 “nonsense” 状态。
  2. “_dbs_info” 端点:GET /_dbs_info?keys=[“db1”,”db2”] 会返回数组,每个成员含 {“key”:”db1”,”info”:{…},”error”:null};若库不可访问,error 字段为字符串而非 null
  3. error 字段值空间
    • nonsense” —— 磁盘满导致元数据损坏;
    • internal_error” —— 其他运行时异常;
    • no_db_file” —— 文件被误删。
  4. 注入手段:国内机房常用 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'
  5. 观测工具:curl + jq 是最低依赖;若现场不允许外网,用容器内 busybox 的 awk 也能解析。
  6. 恢复验证:清理 dummy 文件后,需主动 PUT /_node/_local/_config/couchdb/disk_failure_threshold 临时调到 1%,再调回 10%,触发 CouchDB 重新检测,否则“nonsense”标记不会自动解除。

答案

  1. 注入磁盘满
    以非 root 用户登录 CouchDB 宿主机,找到 data 目录挂载点,执行
    df -h /data 确认剩余空间,然后
    dd if=/dev/zero of=/data/fill$(date +%s).tmp bs=1M count=剩余MB-500
    迅速把可用空间压到 5% 以下(低于 10% 阈值即可)。

  2. 触发写请求
    任意写一条 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。

  3. 观察 _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}'

  4. 清理与恢复
    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,表示库已可用。

拓展思考

  1. 自动化观测:把 curl _dbs_info | jq -r '.[].error' 封装成 exporter,配合阿里云云监控自定义脚本,每 60s 上报,error!=null 时直接触发电话告警。
  2. 灰度限流:在磁盘剩余 15% 时,通过 nginx+lua 拦截写请求,提前降级,避免进入 nonsense 状态。
  3. 多租户隔离:国内 SaaS 厂商常把每个租户独立成库,利用 _dbs_info 批量巡检,可在 1s 内扫描上千库,比轮询 /db/_info 节省 90% 开销。
  4. 容器场景:把 emptyDir 大小限制在 70% 宿主机盘,配合 kubelet 的 eviction-hard=imagefs.available<10%,让 Pod 提前被驱逐,防止进入 nonsense 后人工介入困难。