过去的一段时间,我们连载了一系列和可观测数据采集、加工工具 Vector 相关的文章,包括各种数据源、数据目的地和数据处理能力的基本介绍,在生产环境/Kubernetes 中的最佳实践,以及流控、缓冲等各种内部机制的详细解释。
这个系列发布后,经过和很多的朋友交流,我们获得了一些他们使用 Vector 的反馈,包括使用经验、实践技巧和遇到的问题等等,算是达到抛砖引玉的效果😄。待合适的时候,我们计划再进行一波关于 Vector 使用的连载,和读者一起更深入地认识这个工具。
在第一季连载完成的时候,我想再补充一个彩蛋——番外篇,简单聊聊 Vector 如何作为一个开源项目管理和持续集成的机制。我们从 2023 年开始为 Vector 逐步添加了针对 GreptimeDB 的 Metrics 和 Logs 的 Sink。恰好这期间,Vector 本身的 CI 也经历了一次升级。
模块化机制
Vector 使用 Rust 编写,在运行时非常高效,但开发过程中的编译速度却让人一言难尽。尤其是 Vector 作为一个集成各种外部应用的综合体,依赖众多,其编译速度和编译时的资源消耗是我见过的 Rust 项目中唯一一个能比肩 GreptimeDB 的(🐶 保命)。
受限于 Rust 语言本身的机制,实现一个有意义的、能保留 Rust 安全性保证的插件机制是比较难的。Rust 的构建工具 cargo 采用类似 git 一样的——从 PATH 加载子命令的方式实现插件,不过这种机制仅限于插件模块和核心模块只有少量数据交互的场景,且没有性能上的要求,不适合 Vector 这类模块间大量数据交互的应用。
尽管如此,Vector 还是在 Rust 的模块机制下严格实现了编译时的功能开关,项目中约定每一个数据源和数据目的地都定义自己的 Feature gate ,即功能开关。这个功能可以在编译时打开,官方打包的版本则保持全部打开的状态。这个机制可以根据用户自己的需求,挑选 Vector 里的模块打包自己的版本。我们曾经的 Demo 演示项目中,就自己打包了一个只包含 GreptimeDB 和 Prometheus 数据源的轻量版本:
cargo build --release --no-default-features --features=default-greptimedb-custom,sinks-console,sources-prometheus-scrape
以目前的软件分发生态来看,真正支持编译时自定义的管理工具并不多,类似 Nginx、Curl 这类有很多编译选项的应用,自定义的潜力还没有发挥出来,Vector 也是一样的。
集成测试
Vector 的模块主要用于与外部工具通信,仅仅依靠单元测试则需要大量 Mock ,编写复杂且不能保证正确性。因此在 Vector 的开发框架下定义了一套集成测试的机制,主要通过 docker-compose 把外部依赖运行起来,再执行相应模块的集成测试。
以我们维护的 GreptimeDB 模块为例,需要在 scripts/integration 的 greptimedb 目录下编写 compose.yml 描述启动开源版的 GreptimeDB 。在另一个 test.yml 文件中可以定义要被测试的 greptimedb 版本(支持多个版本),以及当代码库中执行当前的集成测试时要修改的文件。这种选择性测试的机制,对 Vector 这样的大型项目尤其重要。
在本地开发时,也可以通过 make test-integration-greptimedb
命令执行集成测试。
在提交 Pull request 时,Vector 有一套比较复杂的机制来识别变更文件中涉及的模块,并且选择性地执行相应模块的集成测试来缩短 CI 时间。

这套机制使用起来还是比较顺畅的,但受限于 GitHub action 的能力,CI 定义里存在不少的重复信息,维护起来令人头大。
文档和 Changelog
管好这么多外部贡献者维护的模块,且文档上达到统一的质量要求是有难度的,在我看来最关键的是:
- 让外部贡献者需要写的内容越少越好;
- 把需要写的内容尽可能汇集在一起。
这就形成了 Vector 的文档管理机制,其模块文档由两部分构成。
一部分位于代码库 website/cue/reference/components/
下,这里主要介绍模块的背景信息和功能特点等。相应的字段已经高度抽象,与网站自身的模板结合就可以生成完整的内容;另一部分存在于代码的配置信息中,为了保持一致性,配置信息是直接从 Rust 代码利用宏生成文档的。例如:
/// Configuration items for GreptimeDB
#[configurable_component(sink("greptimedb_metrics", "Ingest metrics data into GreptimeDB."))]
#[derive(Clone, Debug, Derivative)]
#[derivative(Default)]
#[serde(deny_unknown_fields)]
pub struct GreptimeDBMetricsConfig {
/// The [GreptimeDB database][database] name to connect.
///
/// Default to `public`, the default database of GreptimeDB.
///
/// Database can be created via `create database` statement on
/// GreptimeDB. If you are using GreptimeCloud, use `dbname` from the
/// connection information of your instance.
///
/// [database]: https://docs.greptime.com/user-guide/concepts/key-concepts#database
#[configurable(metadata(docs::examples = "public"))]
#[derivative(Default(value = "default_dbname()"))]
#[serde(default = "default_dbname")]
pub dbname: String,
}
这里的文档将直接出现在 Vector 的网站上,在“关于 GreptimeDB 模块”的内容中可以找到:

值得一提的是,尽管 Vector 有上百个各种模块,但每一个模块都利用继承的层级和模板机制渲染出全量的信息。这意味着,作为 Vector 的新用户直接来到 GreptimeDB 的 sink 页面可以全量地了解到 Vector 所有支持的配置选项和工作原理,不用跳转到其他页面学习背景知识。这是 Vector 在文档层面为用户特意做的设计。
此外,PR review 时偶尔也有文档工程师的身影来保障变更文档的质量。
在 Changelog 方面,2024 年 Vector 项目又引入一个新的机制要求开发者编写变更描述,该机制来自工具 towncrier
。具体方法是在代码库 changelog.d
下按照 PR 的编号和名称编写用户可读的变更内容,在发布时由 towncrier
统一汇总成变更记录。
在 PR 中也能看到对变更记录的检查。

总结
维护一个多人参与的开源项目,并保持可靠的质量底线,需要用到一些工程和管理技巧。简单总结起来就是降低重复性,提高可达性。
这一季的 Vector 系列连载就到此结束了,感谢读者的陪伴。在可观测领域还有什么你觉得值得挖掘的高质量项目,可以通过评论和我们交流。
关于 Greptime
Greptime 格睿科技专注于为可观测、物联网及车联网等领域提供实时、高效的数据存储和分析服务,帮助客户挖掘数据的深层价值。目前基于云原生的时序数据库 GreptimeDB 已经衍生出多款适合不同用户的解决方案,更多信息或 demo 展示请联系下方小助手(微信号:greptime)。
欢迎对开源感兴趣的朋友们参与贡献和讨论,从带有 good first issue 标签的 issue 开始你的开源之旅吧~期待在开源社群里遇见你!添加小助手微信即可加入“技术交流群”与志同道合的朋友们面对面交流哦~
Star us on GitHub Now: https://github.com/GreptimeTeam/greptimedb
Twitter: https://twitter.com/Greptime
Slack: https://greptime.com/slack