首页
/ Milvus 集合级自动 Compaction 开关:collection.autocompaction.enabled 设计与实现全解析

Milvus 集合级自动 Compaction 开关:collection.autocompaction.enabled 设计与实现全解析

2026-09-08 12:14:16作者:段琳惟

本技术指南围绕 Milvus 中"集合级(Collection Level)自动 Compaction 开关"这一能力展开,其源头是设计提案 20230511-collection_level_autocompaction_switch.md(对应 Enhancement Issue #23993)。阅读本文后,你将掌握:全局自动 compaction 与集合级属性的优先级解析规则、该特性在 DataCoord 中的底层实现链路、如何通过 AlterCollection API 与各语言 SDK 动态开启/关闭单个集合的自动 compaction,以及仓库中对应的单元测试与端到端验证方式。文章以该 MEP 为骨架,结合仓库源码、配置与测试逐层印证,帮助你在生产环境中精确控制 compaction 行为。

背景与动机:为什么需要集合级别的自动 Compaction 开关

全局开关的粒度局限

Milvus 的 DataCoord 负责发现并调度 compaction。历史上,是否启用"自动 compaction"只由一个全局配置控制,即 configs/milvus.yaml 中位于 DataCoord 段下的两个开关(见 configs/milvus.yaml):

dataCoord:
  enableCompaction: true
  compaction:
    # Switch value to control if to enable automatic segment compaction during which
    # data coord locates and merges compactable segments in the background.
    # This configuration takes effect only when dataCoord.enableCompaction is set as true.
    enableAutoCompaction: true

从配置注释可知两者语义不同:dataCoord.enableCompaction 是 compaction 功能的总开关(Compaction 可将小 segment 合并成大 segment,并清理超出 Time Travel 保留期的删除实体);而 dataCoord.compaction.enableAutoCompaction 控制 DataCoord 是否在后台自动定位并合并可压缩的 segment,且前者必须为 true 后者才生效。

该全局开关作用于系统中所有集合,无法区分不同集合的业务诉求。这正是设计文档 Summary 中描述的痛点。

典型业务场景

设计文档给出了两个需要"按集合细粒度控制"的典型场景:

  • 数据导入期间禁止自动 compaction:批量导入(bulk insert / import)时若后台自动 compaction 持续触发,会导致 segment 反复重建、索引频繁重构建,拖慢导入吞吐并产生不必要的写放大;
  • 测试期间保证行为稳定:某些自动化测试或基准测试希望系统行为可预期,需要临时关闭个别集合的自动 compaction,而不是改动全局配置去影响整个集群中的其他集合。

一句话概括:把"自动 compaction 是否开启"从系统级全局变量下沉为可逐集合覆盖的元数据属性

设计方案:一条集合属性与三级取值规则

MEP 的 Design 一节给出了简洁的落地方案:

新增集合级属性,属性键为 collection.autocompaction.enabled(该键在源码 pkg/common/common.go 中定义为常量 CollectionAutoCompactionKey)。

在处理所有 compaction 信号时,按以下规则解析"该集合当前是否允许自动 compaction":

  1. 未设置:使用全局自动 compaction 设置;
  2. 取值合法:使用集合级设置;
  3. 取值非法:按设计文档意图应回退到全局设置(注意下方"实现层面的差异"小节会说明当前仓库代码的实际行为)。

将这条属性与同一代码块中其他集合级属性(如 collection.ttl.secondscollection.on.truncating 以及各类限流与配额键)并列可见,Milvus 的"集合 properties"机制天然支持此类按集合覆盖系统行为的配置模式。

属性定义与 SDK 封装:从常量到客户端构造器

服务端常量定义

集合属性键集中定义在 pkg/common/common.go

const (
	CollectionTTLConfigKey      = "collection.ttl.seconds"
	CollectionAutoCompactionKey = "collection.autocompaction.enabled"
	...
)

CollectionAutoCompactionKey = "collection.autocompaction.enabled" 即为贯穿全文的属性键名,服务端(DataCoord 解析)与客户端(Go/Python SDK 构造属性)共用同一字符串值。

Go SDK 中的集合属性构造器

在 Go SDK 侧,client/entity/collection_attr.go 提供了类型安全的构造器:

// cakAutoCompaction const for collection attribute key autom compaction enabled.
const cakAutoCompaction = `collection.autocompaction.enabled`

// CollectionAutoCompactionEnabled returns collection attribute to set collection auto compaction enabled.
func CollectionAutoCompactionEnabled(enabled bool) autoCompactionCollAttr {
	ca := autoCompactionCollAttr{}
	ca.key = cakAutoCompaction
	ca.value = strconv.FormatBool(enabled)
	return ca
}

CollectionAttribute 接口包含 KeyValue() (string, string)Valid() error 两个方法,其中 Valid() 通过 strconv.ParseBool 校验值必须是合法布尔串(true/false),否则返回 auto compaction setting is not valid boolean 错误,在请求构造阶段即可拦截非法值。SDK 还支持 CollectionTTL 等其它集合属性,体现了同一套属性抽象。

Go Client 的 Alter 链路

Go 客户端将属性写入集合的入口是 AlterCollectionProperties,实现在 client/milvusclient/collection.go

func (c *Client) AlterCollectionProperties(ctx context.Context, option AlterCollectionPropertiesOption, callOptions ...grpc.CallOption) error

配套的 option 构造器在 client/milvusclient/collection_options.go

func NewAlterCollectionPropertiesOption(collection string) *alterCollectionPropertiesOption
func (opt *alterCollectionPropertiesOption) WithProperty(key string, value any) *alterCollectionPropertiesOption

option 内部将属性收集到 map 后,经 entity.MapKvPairs 转换为 commonpb.KeyValuePair,再封装为 milvuspb.AlterCollectionRequest 发送给服务端——这就是设计文档中"所有集合级属性均可通过 AlterCollection API 修改"这一结论的 Go 落地路径。

实现原理:DataCoord 如何消费集合级开关

全局触发循环的启动条件

在 DataCoord 中,自动 compaction 的全局心跳循环位于 internal/datacoord/compaction_trigger.goschedule()

// If AutoCompaction disabled, global loop will not start
if !Params.DataCoordCfg.EnableAutoCompaction.GetAsBool() {
	return
}

即:只有当全局 EnableAutoCompaction 为真时,后台周期性的全局 compaction 信号才会产生。这是第一道"全局闸门"。

compaction 信号的入口校验

TriggerCompactioninternal/datacoord/compaction_trigger.go)在分配信号 ID 前还会做一次快速判断:

// If AutoCompaction disabled, flush request will not trigger compaction
if !paramtable.Get().DataCoordCfg.EnableAutoCompaction.GetAsBool() && !paramtable.Get().DataCoordCfg.EnableCompaction.GetAsBool() {
	return -1, nil
}

只有两个全局配置均为 false 时才会直接放弃(此时 flush 也不再触发自动 compaction);只要 compaction 功能总开关或自动 compaction 任一打开,信号即可进入后续处理。

handleSignal 中的集合级过滤

真正消费集合级开关的位置在 handleSignalinternal/datacoord/compaction_trigger.go):

if !signal.isForce && !isCollectionAutoCompactionEnabled(coll) {
	log.RatedInfo(context.TODO(), rate.Limit(20), "collection auto compaction disabled")
	return nil
}

关键点有两个:

  1. 过滤发生在每个候选集合分组内——全局信号会遍历所有集合,但每个集合都会单独套用自身的属性判断,天然实现"按集合隔离";
  2. isForce(手动/强制 compaction 信号)不受集合级开关约束。强制信号走独立的 manualSignals 通道(更高优先级),因此运维需要立即压缩时仍可绕过该开关。

属性解析函数与三级规则

集合级开关的核心解析函数在 internal/datacoord/util.go

// getCollectionAutoCompactionEnabled returns whether auto compaction for collection is enabled.
// if not set, returns global auto compaction config.
func getCollectionAutoCompactionEnabled(properties map[string]string) (bool, error) {
	// when collection is on truncating, disable auto compaction.
	if _, ok := properties[common.CollectionOnTruncatingKey]; ok {
		return false, nil
	}
	v, ok := properties[common.CollectionAutoCompactionKey]
	if ok {
		enabled, err := strconv.ParseBool(v)
		if err != nil {
			return false, err
		}
		return enabled, nil
	}
	return Params.DataCoordCfg.EnableAutoCompaction.GetAsBool(), nil
}

这段代码精确实现了设计文档的三级解析,还额外叠加了两条规则:

情形 解析结果
集合处于 truncating(存在 collection.on.truncating 属性) 一律返回 false(关闭自动 compaction),且不报错
设置了 collection.autocompaction.enabled 且可被 ParseBool 解析 返回集合级布尔值(最高优先级)
设置了该属性但值非法(如 "bad_value" 返回解析错误
未设置该属性 回退到全局 Params.DataCoordCfg.EnableAutoCompaction

调用方对错误与外部集合的处理

解析错误的最终兜底在 internal/datacoord/compaction_trigger.goisCollectionAutoCompactionEnabled

func isCollectionAutoCompactionEnabled(coll *collectionInfo) bool {
	if coll == nil {
		return false
	}
	if coll.IsExternal() {
		mlog.Debug(context.TODO(), "collection auto compaction disabled for external collection", mlog.FieldCollectionID(coll.ID))
		return false
	}
	enabled, err := getCollectionAutoCompactionEnabled(coll.Properties)
	if err != nil {
		mlog.Warn(context.TODO(), "collection properties auto compaction not valid, returning false", mlog.Err(err))
		return false
	}
	return enabled
}

这里补充了两条约束:nil 集合外部集合(external collection,如基于文件系统挂载的数据源)一律不做自动 compaction

实现层面与 MEP 文案的差异说明

设计文档在"取值非法"情形下写的意图是"回退到全局设置",而当前仓库实际实现中,当值无法被 ParseBool 解析时,isCollectionAutoCompactionEnabled记录 WARN 日志并返回 false,即对该集合按"自动 compaction 关闭"处理,而非回退到全局值。从行为安全角度看,非法值按关闭处理属于 fail-closed 倾向,但若你依赖设计文档的"回退"语义,需要留意当前代码的实际表现——建议始终通过 SDK 传入 "true"/"false" 这类合法布尔值。

实操:如何修改集合级自动 Compaction 开关

方式一:Go SDK(官方 Go Client)

先构造集合属性,再调用 AlterCollectionProperties

package main

import (
	"context"

	"github.com/milvus-io/milvus/client/v2/entity"
	"github.com/milvus-io/milvus/client/v2/milvusclient"
)

func main() {
	ctx := context.Background()
	c, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
		Address: "localhost:19530",
	})
	if err != nil {
		panic(err)
	}
	defer c.Close(ctx)

	// 关闭名为 "docs" 的集合的自动 compaction
	err = c.AlterCollectionProperties(ctx,
		milvusclient.NewAlterCollectionPropertiesOption("docs").
			WithProperty(entity.CollectionAutoCompactionEnabled(false).KeyValue()))
	if err != nil {
		panic(err)
	}

	// 需要恢复时再次置为 true
	err = c.AlterCollectionProperties(ctx,
		milvusclient.NewAlterCollectionPropertiesOption("docs").
			WithProperty(entity.CollectionAutoCompactionEnabled(true).KeyValue()))
	if err != nil {
		panic(err)
	}
}

说明:entity.CollectionAutoCompactionEnabled(b) 返回的属性对象满足 CollectionAttribute 接口,其 KeyValue() 返回 ("collection.autocompaction.enabled", "true"/"false");也可直接 WithProperty("collection.autocompaction.enabled", false)。若希望移除该属性让其重新跟随全局配置,可使用 milvusclient.NewDropCollectionPropertiesOption(collectionName, "collection.autocompaction.enabled")

方式二:Python SDK

仓库中的测试代码给出了 Python 侧的用法范式,例如 tests/python_client/cdc/testcases/test_collection_properties.py 通过 properties={"collection.autocompaction.enabled": "true"} 修改属性,并轮询 describe_collection 返回的 properties 直到其同步为期望值。核心形态如下:

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

# 关闭集合的自动 compaction
client.alter_collection_properties(
    collection_name="docs",
    properties={"collection.autocompaction.enabled": "false"},
)

# 查看属性是否生效
props = client.describe_collection("docs").get("properties", {})
print(props.get("collection.autocompaction.enabled"))  # "false"

方式三:RESTful / 服务端 grpc

对不依赖 SDK 的场景,直接向 /v2/vectordb/collections/alter_properties 发送属性即可,请求载荷中的 properties 同样是 {"collection.autocompaction.enabled": "false"}(详见仓库 tests/restful_client_v2 中对集合属性修改的相关用例)。

与全局开关、强制 Compaction 的组合行为速查

以下矩阵汇总了"全局自动 compaction 开关 × 集合级属性"对一次非强制(自动)信号是否执行的影响:

全局 enableAutoCompaction 集合属性 collection.autocompaction.enabled 集合自动 compaction 是否执行
true 未设置 执行(回退全局=true)
true "true" 执行
true "false" 不执行
true 非法值(如 "bad" 不执行,打 WARN 日志(fail-closed)
false 任意 全局心跳循环不启动,自动信号不会产生
任意 集合处于 truncating / 外部集合 不执行
任意(manual signal) "false" 执行isForce 绕过集合级过滤,但受 TriggerCompaction 的全局总开关约束)

测试计划与仓库验证证据

单元测试:覆盖开关的每个分支

该特性配套的单元测试集中在 internal/datacoord/compaction_trigger_test.go,其子测试与设计文档 Test Plan 一一对应:

  • collectionAutoCompactionConfigErrorcompaction_trigger_test.go):将属性值设为 "bad_value",断言解析失败后不会进入 plan 生成(inspector.enqueueCompaction 不被调用);
  • collectionAutoCompactionDisabledcompaction_trigger_test.go):属性值 "false" 时自动 compaction 信号被跳过;
  • collectionAutoCompactionDisabled_forcecompaction_trigger_test.go):同一 "false" 属性下,isForce=true 的信号仍会执行 compaction(验证强制信号绕过集合级开关);
  • TestIsCollectionAutoCompactionEnabledExternalcompaction_trigger_test.go):验证外部集合恒返回关闭。

另有针对 TestHandleSignal 中的全局开关(EnableAutoCompaction true/false 切换)测试,验证全局与集合两级开关的叠加关系。

E2E / 集成 / 同步测试

这些测试共同构成了设计文档 Test Plan 中 Unit / E2E / Integration 三个层级的落地实现,可作为读者参照复现的"可运行样例"。

最佳实践与注意事项

  1. 导入/灌库窗口关闭,之后恢复:大批量导入前 alter_collection_properties 将该集合置为 false,导入完成并 flush 后手动触发一次 compaction 或恢复 true,即可避免导入期间反复重建索引(对应设计文档的首要动机);
  2. 尽量用合法布尔值:属性值最终经过 strconv.ParseBool(Go)解析,"1"/"t" 等宽松写法在 Go 的 ParseBool 中虽可能通过,但跨语言 SDK 与后续版本行为未必一致,统一使用 "true"/"false" 最稳妥;
  3. 区分强制与自动:集合级开关只拦截自动信号;需要立即回收空间的运维操作应使用手动/强制 compaction,不要依赖"开启属性"来放行;
  4. 作用域意识:该属性只控制 compaction,与 TTL(collection.ttl.seconds)、配额限流等其他集合属性彼此独立;且全局 dataCoord.enableCompaction 总开关仍然拥有最终否决权;
  5. 验证生效:通过 describe_collection / DescribeCollection 查看 properties 以确认修改已落盘生效(同步链路可参考上述 Python CDC 用例的轮询断言模式)。

小结与延伸阅读

collection.autocompaction.enabled 是 Milvus "集合属性(Collection Properties)"体系中一个小而典型的代表:一份 MEP 设计文档,加上服务端常量、SDK 构造器、DataCoord 触发链路上的三级解析,以及覆盖各分支的单测与 E2E,共同把"全局化、一刀切"的 compaction 控制下沉为"逐集合、可动态调整"的元数据开关。理解它的实现路径,也能举一反三地理解 TTL、磁盘配额、复制组等其他集合级属性的设计与接入方式。

相关资源:

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389