六边形、洋葱、策略、适配器架构设计

六边形、洋葱、策略、适配器架构设计

场景说明

一家提供“行业级数据/行为分析与算法服务”的平台,多个公司(Company A, B, C)接入。各公司数据采集、字段、格式与接入协议可能不同(HTTP webhook、SFTP、消息队列、第三方API等),但核心算法引擎(例如:行为得分、异常检测、ROI 计算、聚合指标计算)是公用的。平台需要:

  • 对不同公司做接入适配(Adapter)
  • 算法策略选择不同分析方法(Strategy)
  • 使用六边形架构把核心业务逻辑(Domain)与外部接口(DB、消息、API)解耦
  • 使用洋葱架构分层组织依赖反转(Domain 最内层,不依赖外层)
  • 提供后台长期运行任务(worker、调度、重试、任务状态持久化)

概念详解

六边形架构(Ports & Adapters / Hexagonal)

image-20251022094622139

image-20251022094724736

  • 核心理念:系统应围绕域逻辑(Domain / Application)构建,通过“端口(ports)”定义对外接口(入站/出站),外部系统通过“适配器(adapters)”实现这些端口。
  • 优点:实现了依赖方向从外向内,方便替换外部实现(数据库、消息、第三方),利于测试(可以注入 mock 适配器)。
  • 在本系统的映射
    • Ports:RepositoryMessageBrokerDataIngestorAlgorithmRunner 的接口。
    • Adapters:MySQL 实现/Redis 实现/HTTP webhook 适配器/文件处理适配器等。

洋葱架构(Onion)

image-20251022094655332

  • 核心理念:应用被分成多层,内层包含 Domain(实体、聚合、业务规则),外层依赖内层,内层不依赖外层。应用服务、接口层、持久层按圈层组织。
  • 与六边形的关系:这两者高度兼容 — 洋葱强调层次、六边形强调端口/适配器。我们可以把 Domain 放在洋葱最内层,Ports/Interfaces 作为内外层交互契约,Adapters 在最外层实现契约。

六边形 vs 洋葱 —— 是否重复?

  • 结论:二者互补,不是互斥。六边形强调“端口/适配器”的概念,洋葱强调“层次/依赖方向”。在实际工程中,常把 Domain 放在洋葱内层,同时用六边形的 ports 作为内外契约 —— 所以可以同时使用,且常常是最佳实践组合。

策略模式(Strategy)

  • 核心理念:定义一系列可替换的算法(策略),将它们封装起来,使得它们可以互换。客户端通过统一接口选择并使用某个策略。
  • 在本系统:不同公司或场景需要不同分析算法(例如:轻量得分/深度模型/历史加权),实现为多个 Strategy,并运行时根据租户配置、数据特性或 A/B 测试动态选择。

适配器模式(Adapter)

  • 核心理念:把一个类的接口转换成客户端所期望的另一个接口,解决接口不兼容问题。
  • 在本系统:各公司数据格式与接入方式不同,编写适配器把公司专有的数据映射为平台内部统一的 IngestEventNormalizedRecord,使核心算法不必处理各种原始格式。

项目架构

analysis-platform/                 # 项目根
├── cmd/
│   └── api/                       # main for HTTP API
│       └── main.go
├── internal/
│   ├── domain/                    # 洋葱最内层:实体、值对象、领域服务接口
│   │   ├── model.go
│   │   └── algorithm.go           # Algorithm (Domain-level interface)
│   ├── application/               # 应用服务层(use cases)
│   │   ├── service.go
│   │   └── workflow.go
│   ├── ports/                     # 六边形的 ports(接口定义)
│   │   ├── repository.go
│   │   ├── messagebroker.go
│   │   └── ingestor.go
│   ├── adapters/                  # 外围适配器(外层)
│   │   ├── db/
│   │   │   └── mysql_repo.go
│   │   ├── mq/
│   │   │   └── kafka_adapter.go
│   │   └── ingesters/
│   │       ├── http_webhook.go
│   │       └── sftp_ingest.go
│   └── strategies/                # 策略实现(具体算法)
│       ├── strategy_light.go
│       └── strategy_advanced.go
├── scripts/
├── configs/
└── docs/

设计理念(要点)

  1. Domain 最小依赖:Domain 层只包含纯业务概念和接口(接口抽象在 ports),不导入外部库。
  2. 接口优先 / 依赖注入:应用层通过接口(ports)与外部交互,启动时由 main 注入具体 adapters 实现。
  3. 策略解耦算法:算法以策略(Strategy)实现并注入,便于扩展/AB 测试/运行时切换。
  4. 适配器隔离接入复杂性:各公司接入变化只影响 adapters,不影响核心逻辑。
  5. 可测试性:所有关键点(仓库、消息、算法)都可替换为 mock。
  6. 可观测性与重试:工作流与后台任务应支持任务追踪、重试、幂等、持久化任务状态。
  7. 多租户支持:每个请求/任务携带 tenant_id,算法/策略可以基于 tenant 配置做变更。

后台工作流设计

  • 任务种类:实时分析(同步/近实时)、批量重算(离线)、模型训练(长期)、聚合任务(定期)。
  • 队列:使用 Redis Streams / Kafka / RabbitMQ 进行异步解耦。任务入队后由 worker 池消费。
  • Worker 特性
    • 并发控制、幂等检查(唯一 task_id)、重试(指数退避)、死信队列/告警。
    • 任务元数据表(task_id、tenant、type、payload、status、attempts、last_error、created_at)。
  • 调度:cron 或基于事件触发入队。
  • 监控:队列长度、失败率、处理延时(Prometheus + Grafana)。
  • 持久化:每次任务成功/失败更新数据库(便于审计与重试)。
posted @ 2025-10-22 09:52  AJun816  阅读(13)  评论(0)    收藏  举报