使用 /_membership 如何验证所有节点状态为“cluster_nodes”且一致?
解读
在国内实际生产环境中,CouchDB 往往以 3 节点或 5 节点集群部署在阿里云、腾讯云或私有 KVM 上,面试官问这道题,核心想确认两点:
- 你是否知道 /_membership 返回的 JSON 里只有 cluster_nodes 与 all_nodes 两个数组;
- 你是否能写出一行可脚本化的 bash+curl+jq 命令,一次性判断“所有节点既在 cluster_nodes 里,也在 all_nodes 里,并且两个数组元素完全一致”,而不是人工肉眼比对。
如果你能给出 零依赖单命令 并解释容错场景(节点失联、DNS 抖动、证书过期),面试官会立即给你加分。
知识点
- /_membership 是 CouchDB 内置的 ephemeral 接口,无需鉴权 即可返回当前节点视角的集群成员。
- 返回体只有两个字段:cluster_nodes(“期望”成员)与 all_nodes(“实际”成员)。
- 当 cluster_nodes ⊇ all_nodes 且 长度相等 时,集群状态为 Healthy;若出现 “orphan”节点(在 all_nodes 但不在 cluster_nodes),说明该节点已被 remove 但尚未下线;若出现 “missing”节点(在 cluster_nodes 但不在 all_nodes),说明节点 宕机或网络隔离。
- 国内机房常把 5984 映射到 5986 做 SSL 终止,因此脚本里务必使用 HTTPS+6984 或 SSH 隧道,避免 明文 5984 被安全组拦截。
- 判断数组一致性最轻量的工具是 jq,面试官希望你用 jq -e 让 shell 拿到 exit code 0/1,方便 Zabbix/夜莺/阿里云云监控 直接复用。
答案
以下命令在 任意一个节点 上执行即可,无需 ssh 登录其他机器,输出 0 表示一致,非 0 表示不一致,可直接做 告警探针:
#!/usr/bin/env bash
# 用法:./check_membership.sh https://couch0.example.com:6984
ENDPOINT="$1/_membership"
export NODE_COUNT=3 # 根据实际节点数修改
curl -s --max-time 3 -u "${COUCH_USER}:${COUCH_PASS}" "${ENDPOINT}" \
| jq -e --argjson expect "${NODE_COUNT}" '
(.cluster_nodes | length) == $expect and
(.all_nodes | length) == $expect and
(.cluster_nodes - .all_nodes | length) == 0 and
(.all_nodes - .cluster_nodes | length) == 0
' >/dev/null
解释:
- cluster_nodes - all_nodes 为空且 all_nodes - cluster_nodes 为空,说明两个数组 元素完全一致。
- -e 让 jq 在条件为 false 时返回 exit code 1,脚本可直接被 Kubernetes livenessProbe 或 Jenkins 流水线 调用。
- 若集群启用了 自签名证书,给 curl 加 --cacert 参数即可,国内银行私有云环境同理。
拓展思考
- 双活异地场景:北京与深圳各 3 节点,跨城 RTT 40 ms,若出现 “missing”节点,应先 区分“网络抖动”还是“进程 crash”;可结合 /_node/_local/_system 的 uptime 字段做 二次确认,避免 误切流量。
- 灰度扩容:当 加入新节点 后,cluster_nodes 会立即包含新节点,但 all_nodes 可能延迟 5–10 s;此时若监控脚本 直接报警,会造成 误告;建议 sleep 15 s 后重试,或对比 连续 3 次不一致 再报警。
- 权限加固:国内等保 2.0 要求 关闭 5984 公网入口;可把 /_membership 代理到 内网 Nginx,并加 Basic Auth+IP 白名单;脚本里使用 http://127.0.0.1:5984 通过 SSH 隧道 转发,既满足 等保 又兼容 监控脚本。