当附件为重复文件时,如何启用“att_compression_level=9”并验证 SHA-1 去重?
解读
国内生产环境普遍把 CouchDB 当作“离线优先”数据总线,手机端、IoT 端频繁上传图片、日志等附件,导致同名不同内容或同内容不同名的冗余。面试官抛出本题,核心想验证三点:
- 你是否知道 CouchDB 的附件是独立二进制 blob、与文档 JSON 分离存储;
- 能否把“压缩级别”与“去重”这两个看似无关的配置同时生效;
- 能否用SHA-1 摘要在应用层或 Fauxton 层做二次校验,证明去重真实发生。
知识点
- att_compression_level 只在节点级配置文件 etc/local.ini 的
[attachments]段生效,范围 0–9,9 为最高压缩。 - 该参数仅对新建附件生效,已存附件不会回溯压缩;若需历史数据压缩,必须重写附件。
- CouchDB 内部以附件长度 + 摘要作为去重键,摘要算法默认 MD5,但可通过配置改为 SHA-1。
- 摘要算法由
[attachments] hash_algorithm = sha控制,sha 即 SHA-1(不是 SHA-256)。 - 验证去重时,可借助
GET /db/doc/att?name&att_encoding_info=true返回的encoded_length、digest字段,比较两次上传的digest是否一致。
答案
步骤一:修改配置
在 每个节点 的 etc/local.ini 追加:
[attachments]
compression_level = 9
hash_algorithm = sha
保存后 依次重启 所有节点,使配置生效。
步骤二:上传重复文件
- 准备一份测试文件
test.bin,记录本地 SHA-1:
sha1sum test.bin→ 假设得到aabbcc... - 第一次上传:
curl -X PUT http://user:pass@127.0.0.1:5984/mydb/doc1/att?rev=1-xxx \ -H "Content-Type: application/octet-stream" --data-binary @test.bin
返回"rev": "2-..."并记下digest字段,应为sha1-aabbcc...。 - 第二次上传不同名文档但同一文件:
curl -X PUT http://user:pass@127.0.0.1:5984/mydb/doc2/att?rev=1-yyy \ -H "Content-Type: application/octet-stream" --data-binary @test.bin
步骤三:验证去重
查询附件元数据:
curl http://user:pass@127.0.0.1:5984/mydb/doc2/att?att_encoding_info=true
返回示例:
{
"content_type": "application/octet-stream",
"revpos": 2,
"digest": "sha1-aabbcc...",
"length": 102400,
"encoded_length": 78888,
"encoding": "gzip"
}
若 doc1 与 doc2 的 digest 完全一致,且 encoded_length < length,则证明同内容附件只存一份,且以最高级别压缩存储,SHA-1 去重生效。
拓展思考
- 如果业务需要SHA-256 而非 SHA-1,CouchDB 3.x 目前尚未内置,需在应用层先计算 sha256 作为附件名或写入文档字段,再上传,实现“应用层去重”。
- 压缩级别 9 会显著增加 CPU,高并发写入场景建议先压测;国内云主机 2 vCPU 环境下,单节点 500 QPS 时 CPU 可飙至 70 %,可考虑折中设为 6。
- 若附件大于 4 MB,CouchDB 默认会分块存储,此时
encoded_length是各块压缩后之和,验证去重时仍需比较顶级digest,无需关心分块细节。