EulerMaker存储设计揭秘:etcd与Elasticsearch双引擎协同方案
【免费下载链接】EulerMakerA software package build system that completes the build from source code to binary packages and supports developers in customizing OS scenarios.项目地址: https://gitcode.com/openeuler/EulerMaker
前往项目官网免费下载:https://ar.openeuler.org/ar/
EulerMaker作为openEuler社区的开源软件包构建系统,其存储架构采用了创新的etcd与Elasticsearch双引擎协同方案,为开发者提供了高效、可靠的数据管理能力。这种独特的存储设计不仅确保了系统的高可用性,还实现了实时数据同步与快速检索的完美结合,成为构建系统领域的存储设计典范。
🚀 为什么需要双引擎存储架构?
在传统的构建系统中,存储方案往往面临一个两难选择:要么选择强一致性的KV存储(如etcd)来保证数据可靠性,要么选择全文搜索引擎(如Elasticsearch)来支持复杂的查询需求。EulerMaker巧妙地将两者结合,充分发挥了各自的优势:
- etcd:提供强一致性、高性能的键值存储,支持watch机制实现实时变更通知
- Elasticsearch:提供强大的全文搜索和索引能力,支持复杂的查询和分析
🏗️ 双引擎协同工作原理
数据流架构
EulerMaker的存储架构遵循清晰的数据流向:
用户请求 → ebs-gateway → ebs-apiserver → [etcd + Elasticsearch]所有组件都通过统一的API访问存储层,这种设计确保了系统的可维护性和扩展性。
核心存储组件
1. etcd主存储路径
etcd作为主存储,负责持久化所有资源对象并维护resourceVersion。在EulerMaker中,etcd采用以下路径结构:
/registry/ebs/projects/{name} /registry/ebs/snapshots/{project}/{name} /registry/ebs/builds/{project}/{name} /registry/ebs/jobs/{project}/{name} /registry/ebs/runners/{name}这种层级结构设计使得:
- 全局list/watch可以监听资源前缀(如
/registry/ebs/builds) - 项目内list/watch可以监听项目子前缀(如
/registry/ebs/builds/{project})
2. Elasticsearch索引设计
Elasticsearch作为增强存储,为每个资源类型创建独立的索引:
ebs-projects ebs-snapshots ebs-builds ebs-jobs ebs-runners每个索引都包含标准化的映射结构,确保数据的一致性和查询效率。
🔄 双引擎协同机制详解
读写操作协同策略
EulerMaker通过EnricherStore实现了etcd与Elasticsearch的智能协同:
创建操作(Create)
func (e *EnricherStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { if err := e.indexES(ctx, obj); err != nil { return nil, fmt.Errorf("ES index failed: %w", err) } return e.etcdStore.Create(ctx, obj, createValidation, options) }关键点:先写Elasticsearch,再写etcd。ES写入失败会导致整个创建操作失败,确保数据一致性。
读取操作(Get)
func (e *EnricherStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { var ( obj runtime.Object esData json.RawMessage etcdErr error esErr error wg sync.WaitGroup ) wg.Add(2) go func() { obj, etcdErr = e.etcdStore.Get(ctx, name, options) }() go func() { esData, esErr = e.esClient.Get(ctx, e.resource, esDocID) }() wg.Wait() if etcdErr != nil { return nil, etcdErr } if esErr == nil && esData != nil { json.Unmarshal(esData, obj) // 用ES数据增强返回对象 } return obj, nil }创新点:并发读取etcd和Elasticsearch,用ES中的增强数据覆盖返回对象,实现数据融合。
更新操作(Update)
func (e *EnricherStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { result, wasCreated, err := e.etcdStore.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) if err != nil { return nil, false, err } if err := e.indexES(ctx, result); err != nil { return result, wasCreated, nil // ES失败不影响etcd更新 } return result, wasCreated, nil }设计哲学:先更新etcd,再尝试更新Elasticsearch。ES写入失败不会阻断etcd更新,保证系统可用性。
删除操作(Delete)
func (e *EnricherStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { obj, wasImmediate, err := e.etcdStore.Delete(ctx, name, deleteValidation, options) if err != nil { return nil, false, err } e.esClient.Delete(ctx, e.resource, esDocID) // 异步删除ES数据 return obj, wasImmediate, nil }容错设计:先删etcd,再删除ES文档,即使ES删除失败也不影响主要业务流程。
文档ID命名策略
对于命名空间化的对象,EulerMaker采用{project}/{name}作为文档ID:
esDocID := name if ns, ok := genericapirequest.NamespaceFrom(ctx); ok && ns != "" { esDocID = ns + "/" + name }这种命名策略确保了文档的唯一性和可读性,同时兼容URL编码要求。
🛠️ 实际应用场景
场景一:构建状态实时监控
当用户创建新的构建任务时:
- 构建请求通过ebs-gateway到达ebs-apiserver
- apiserver将构建对象写入Elasticsearch(索引:ebs-builds)
- apiserver将构建对象写入etcd(路径:/registry/ebs/builds/{project}/{name})
- 控制器通过watch机制监听到新构建,开始调度执行
- 执行过程中状态更新会同时同步到两个存储引擎
场景二:复杂查询与统计
项目经理需要查询特定时间段内所有失败的构建任务:
{ "query": { "bool": { "must": [ { "term": { "status.phase": "Failed" } }, { "range": { "metadata.creationTimestamp": { "gte": "2024-01-01" } } } ] } } }这种复杂查询直接在Elasticsearch中执行,无需遍历etcd中的所有数据,大大提升了查询效率。
场景三:项目资源管理
系统管理员需要查看某个项目的所有资源:
# 通过etcd watch机制实时获取项目资源变化 watch /registry/ebs/builds/project-alpha watch /registry/ebs/jobs/project-alpha同时,可以通过Elasticsearch进行跨项目统计和分析。
⚡ 性能优化策略
1. 并发读取优化
通过并发读取etcd和Elasticsearch,EulerMaker将读取延迟降低到两个存储系统中较慢的那个:
wg.Add(2) go func() { /* 读取etcd */ }() go func() { /* 读取ES */ }() wg.Wait()2. 异步写入容错
对于更新操作,ES写入失败不会影响etcd更新,确保系统的高可用性:
if err := e.indexES(ctx, result); err != nil { return result, wasCreated, nil // 静默处理ES错误 }3. 智能索引管理
Elasticsearch客户端在启动时自动创建并配置索引:
func (c *Client) ensureIndices() error { for _, index := range indices { // 检查索引是否存在,不存在则创建 mapping := `{ "settings": { "number_of_shards": 1, "number_of_replicas": 0 }, "mappings": { /* 优化字段映射 */ } }` } }🔧 部署与配置
Docker Compose部署
测试环境可以通过hacks/docker-compose.yml快速启动所有组件:
etcd: image: quay.io/coreos/etcd:v3.5.0 ports: - "2379:2379" elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0 ports: - "9200:9200" ebs-apiserver: build: ./components/ebs-apiserver ports: - "8443:8443" environment: - ETCD_SERVERS=http://etcd:2379 - ES_SERVERS=http://elasticsearch:9200关键配置参数
| 参数 | 默认值 | 说明 |
|---|---|---|
--etcd-servers | http://etcd:2379 | etcd服务地址 |
--es-servers | http://elasticsearch:9200 | Elasticsearch服务地址 |
--secure-port | 8443 | HTTPS监听端口 |
🎯 设计优势总结
1. 数据一致性保证
- etcd提供强一致性保证
- 关键操作(Create)采用两阶段提交模式
- 更新操作以etcd为准,ES作为增强存储
2. 查询性能提升
- 简单查询走etcd,复杂查询走Elasticsearch
- 并发读取减少总体延迟
- 索引优化提升搜索效率
3. 系统可扩展性
- 存储层与业务逻辑解耦
- 支持水平扩展的存储集群
- 灵活的索引策略支持不同查询需求
4. 开发体验优化
- 统一的API接口简化客户端开发
- 实时watch机制支持响应式应用
- 丰富的查询能力满足复杂业务场景
💡 最佳实践建议
1. 生产环境部署
- 为etcd和Elasticsearch配置高可用集群
- 根据数据量调整Elasticsearch的分片和副本数
- 定期备份关键数据
2. 监控与告警
- 监控etcd集群健康状态
- 监控Elasticsearch索引性能
- 设置存储空间使用率告警
3. 性能调优
- 根据查询模式优化Elasticsearch索引映射
- 调整etcd的watch缓冲区大小
- 合理设置连接池参数
🚀 未来发展方向
EulerMaker的双引擎存储架构为构建系统提供了坚实的基础,未来可以在以下方向继续演进:
- 多级缓存优化:引入Redis等内存缓存,进一步提升热点数据访问性能
- 数据湖集成:对接大数据分析平台,支持构建数据的深度分析
- 存储插件化:支持更多存储后端,如TiKV、MongoDB等
- 智能索引管理:基于查询模式自动优化索引策略
📚 学习资源
想要深入了解EulerMaker存储设计的开发者可以查看以下源码:
- 存储协同核心:components/ebs-apiserver/pkg/storage/hybrid/store.go - 双引擎存储协同实现
- Elasticsearch客户端:components/ebs-apiserver/pkg/storage/es/client.go - ES客户端封装
- 架构设计文档:docs/zh/design/architecture.md - 系统架构详细说明
- 数据模型定义:docs/zh/design/data-models.md - 资源对象模型定义
EulerMaker的etcd与Elasticsearch双引擎协同方案展示了现代构建系统存储设计的先进理念,通过巧妙的架构设计,在保证数据一致性的同时,提供了强大的查询和分析能力。这种设计模式值得其他分布式系统借鉴和学习。
无论你是正在构建新的软件包构建系统,还是优化现有系统的存储架构,EulerMaker的实践经验都能为你提供宝贵的参考。🚀
【免费下载链接】EulerMakerA software package build system that completes the build from source code to binary packages and supports developers in customizing OS scenarios.项目地址: https://gitcode.com/openeuler/EulerMaker
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考