Skip to content

项目结构规范

概述

良好的项目结构是构建可维护、可扩展微服务的基础。本章将介绍 CloudWeGo 推荐的项目目录结构,帮助你组织代码、提高开发效率。

核心内容

单体项目结构

适用于小型项目或初期开发:

myapp/
├── cmd/                    # 应用入口
│   └── server/
│       └── main.go
├── internal/               # 内部代码(不可导入)
│   ├── handler/            # 处理器
│   ├── service/            # 业务逻辑
│   ├── repository/         # 数据访问
│   └── model/              # 数据模型
├── pkg/                    # 公共代码(可导入)
│   ├── config/             # 配置
│   ├── middleware/         # 中间件
│   └── utils/              # 工具函数
├── idl/                    # IDL 定义
│   └── api.thrift
├── kitex_gen/              # 生成的代码
├── config/                 # 配置文件
│   ├── config.yaml
│   └── config.test.yaml
├── scripts/                # 脚本
│   ├── build.sh
│   └── gen.sh
├── go.mod
├── go.sum
├── Makefile
└── README.md

微服务项目结构

适用于中大型项目,每个服务独立仓库:

user-service/
├── cmd/
│   ├── server/             # 服务入口
│   │   └── main.go
│   └── client/             # 客户端示例
│       └── main.go
├── internal/
│   ├── handler/            # RPC 处理器
│   │   └── user_handler.go
│   ├── service/            # 业务逻辑
│   │   └── user_service.go
│   ├── repository/         # 数据访问
│   │   └── user_repo.go
│   ├── model/              # 领域模型
│   │   └── user.go
│   └── infra/              # 基础设施
│       ├── db/             # 数据库
│       ├── cache/          # 缓存
│       └── mq/             # 消息队列
├── pkg/
│   ├── config/             # 配置管理
│   │   └── config.go
│   ├── middleware/         # 中间件
│   │   ├── auth.go
│   │   └── logging.go
│   └── utils/              # 工具函数
├── idl/
│   └── user.thrift         # IDL 定义
├── kitex_gen/              # 生成的代码
├── api/                    # HTTP API(可选)
│   ├── handler/
│   └── router/
├── config/
│   ├── config.yaml
│   ├── config.dev.yaml
│   └── config.prod.yaml
├── scripts/
│   ├── build.sh
│   ├── gen.sh
│   └── docker.sh
├── deployments/
│   ├── docker/
│   │   └── Dockerfile
│   └── k8s/
│       └── deployment.yaml
├── docs/                   # 文档
├── go.mod
├── go.sum
├── Makefile
└── README.md

Monorepo 项目结构

适用于多服务统一管理的场景:

monorepo/
├── services/               # 微服务
│   ├── user-service/
│   │   ├── cmd/
│   │   ├── internal/
│   │   └── idl/
│   ├── order-service/
│   │   ├── cmd/
│   │   ├── internal/
│   │   └── idl/
│   └── payment-service/
│       ├── cmd/
│       ├── internal/
│       └── idl/
├── api/                    # 共享 IDL
│   ├── user/
│   │   └── user.thrift
│   ├── order/
│   │   └── order.thrift
│   └── common/
│       └── common.thrift
├── pkg/                    # 共享代码
│   ├── middleware/
│   ├── config/
│   └── utils/
├── tools/                  # 工具
│   └── gen-code.sh
├── docs/                   # 文档
├── go.mod
├── go.sum
├── Makefile
└── README.md

目录职责说明

cmd/

应用入口,只负责初始化和启动:

go
// cmd/server/main.go
package main

import (
    "log"
    
    "example/internal/handler"
    "example/internal/service"
    "example/internal/repository"
    "example/pkg/config"
    
    "github.com/cloudwego/kitex/server"
)

func main() {
    // 加载配置
    cfg, err := config.Load("config/config.yaml")
    if err != nil {
        log.Fatal(err)
    }
    
    // 初始化依赖
    db := repository.NewDB(cfg.Database)
    repo := repository.NewUserRepo(db)
    svc := service.NewUserService(repo)
    handler := handler.NewUserHandler(svc)
    
    // 启动服务
    svr := server.NewServer(handler)
    if err := svr.Run(); err != nil {
        log.Fatal(err)
    }
}

internal/

内部代码,不可被外部导入:

go
// internal/service/user_service.go
package service

type UserService struct {
    repo repository.UserRepository
}

func NewUserService(repo repository.UserRepository) *UserService {
    return &UserService{repo: repo}
}

func (s *UserService) GetUser(ctx context.Context, id int64) (*model.User, error) {
    return s.repo.FindByID(ctx, id)
}

pkg/

公共代码,可被外部导入:

go
// pkg/middleware/auth.go
package middleware

import (
    "context"
    
    "github.com/cloudwego/kitex/pkg/klog"
)

func AuthMiddleware(next endpoint.Endpoint) endpoint.Endpoint {
    return func(ctx context.Context, req interface{}) (interface{}, error) {
        // 认证逻辑
        klog.CtxInfof(ctx, "auth middleware")
        return next(ctx, req)
    }
}

idl/

IDL 定义文件:

thrift
// idl/user.thrift
namespace go user

include "common.thrift"

struct User {
    1: i64 id
    2: string name
    3: string email
}

service UserService {
    User GetUser(1: i64 id)
}

配置管理

配置文件结构

yaml
# config/config.yaml
server:
  name: user-service
  port: 8888

database:
  driver: mysql
  dsn: "user:pass@tcp(localhost:3306)/db?charset=utf8mb4"
  max_open: 100
  max_idle: 10

redis:
  addr: "localhost:6379"
  password: ""
  db: 0

log:
  level: info
  output: stdout

registry:
  type: nacos
  address: "localhost:8848"
  namespace: "dev"

配置加载

go
// pkg/config/config.go
package config

import (
    "os"
    
    "gopkg.in/yaml.v3"
)

type Config struct {
    Server   ServerConfig   `yaml:"server"`
    Database DatabaseConfig `yaml:"database"`
    Redis    RedisConfig    `yaml:"redis"`
    Log      LogConfig      `yaml:"log"`
    Registry RegistryConfig `yaml:"registry"`
}

func Load(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, err
    }
    
    var cfg Config
    if err := yaml.Unmarshal(data, &cfg); err != nil {
        return nil, err
    }
    
    return &cfg, nil
}

Makefile 示例

makefile
.PHONY: all build run gen clean

APP_NAME := user-service
MAIN_FILE := cmd/server/main.go

all: gen build

build:
	go build -o bin/$(APP_NAME) $(MAIN_FILE)

run:
	go run $(MAIN_FILE)

gen:
	kitex -module example -service user idl/user.thrift

clean:
	rm -rf kitex_gen bin

test:
	go test -v ./...

docker:
	docker build -t $(APP_NAME) -f deployments/docker/Dockerfile .

Dockerfile 示例

dockerfile
# deployments/docker/Dockerfile
FROM golang:1.21-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o bin/server ./cmd/server

FROM alpine:latest

WORKDIR /app
COPY --from=builder /app/bin/server .
COPY --from=builder /app/config ./config

EXPOSE 8888
CMD ["./server"]

大型项目组织最佳实践

1. 模块化设计

大型项目的模块划分

user-service/
├── cmd/                    # 应用入口
├── internal/               # 内部代码
│   ├── modules/            # 业务模块
│   │   ├── user/           # 用户模块
│   │   │   ├── handler/    # 处理器
│   │   │   ├── service/    # 业务逻辑
│   │   │   ├── repository/ # 数据访问
│   │   │   └── model/      # 数据模型
│   │   └── auth/           # 认证模块
│   └── infra/              # 基础设施
├── pkg/                    # 公共代码
├── idl/                    # IDL 定义
└── config/                 # 配置文件

模块设计原则

  • 高内聚:每个模块职责单一
  • 低耦合:模块间依赖最小化
  • 可测试:模块可独立测试
  • 可扩展:支持功能扩展

2. 依赖管理

Go 模块依赖管理

go
// go.mod
module example.com/user-service

go 1.21

require (
    github.com/cloudwego/kitex v0.10.0
    github.com/cloudwego/hertz v0.7.0
    gopkg.in/yaml.v3 v3.0.1
)

require (
    // 间接依赖
)

依赖管理最佳实践

  • 使用 Go 1.18+ 的模块系统
  • 锁定依赖版本(使用 go.sum)
  • 定期更新依赖
  • 使用依赖分析工具(如 go mod why)
  • 避免循环依赖

3. 代码组织

分层架构

层级职责示例目录
接口层处理请求和响应internal/handler
业务逻辑层核心业务逻辑internal/service
领域模型层业务实体internal/model
数据访问层数据库操作internal/repository
基础设施层外部依赖internal/infra

代码组织原则

  • 按功能模块组织代码
  • 遵循单一职责原则
  • 使用依赖注入
  • 接口与实现分离

4. 配置管理

大型项目的配置管理

config/
├── default.yaml        # 默认配置
├── development.yaml    # 开发环境
├── staging.yaml        # 测试环境
├── production.yaml     # 生产环境
└── secrets/            # 敏感配置

配置管理最佳实践

  • 使用分层配置(默认 + 环境)
  • 敏感配置使用环境变量或密钥管理服务
  • 配置变更记录和审计
  • 配置验证和类型安全
  • 配置热加载

配置加载示例

go
// pkg/config/config.go
package config

import (
    "os"
    "path/filepath"
    
    "gopkg.in/yaml.v3"
)

type Config struct {
    Server   ServerConfig   `yaml:"server"`
    Database DatabaseConfig `yaml:"database"`
    Redis    RedisConfig    `yaml:"redis"`
}

func Load() (*Config, error) {
    // 加载默认配置
    defaultPath := "config/default.yaml"
    
    // 加载环境配置
    env := os.Getenv("APP_ENV")
    if env == "" {
        env = "development"
    }
    envPath := filepath.Join("config", env+".yaml")
    
    // 合并配置
    cfg, err := loadFile(defaultPath)
    if err != nil {
        return nil, err
    }
    
    envCfg, err := loadFile(envPath)
    if err != nil {
        return nil, err
    }
    
    // 合并环境配置到默认配置
    mergeConfig(cfg, envCfg)
    
    return cfg, nil
}

5. 构建和部署

大型项目的构建策略

makefile
# Makefile
.PHONY: all build test deploy

APP_NAME := user-service

all: build

build:
    @echo "Building $(APP_NAME)..."
    @mkdir -p bin
    @go build -o bin/$(APP_NAME) ./cmd/server

test:
    @echo "Running tests..."
    @go test -v ./...

docker:
    @echo "Building Docker image..."
    @docker build -t $(APP_NAME) -f deployments/docker/Dockerfile .

deploy:
    @echo "Deploying to Kubernetes..."
    @kubectl apply -f deployments/k8s/deployment.yaml
    @kubectl apply -f deployments/k8s/service.yaml

helm:
    @echo "Deploying with Helm..."
    @helm install $(APP_NAME) deployments/helm

部署策略

  • 容器化:使用 Docker 容器
  • 编排:使用 Kubernetes
  • 包管理:使用 Helm
  • 滚动更新:无 downtime 部署
  • 健康检查:配置就绪和存活探针

6. 测试策略

大型项目的测试分层

测试类型目的位置执行频率
单元测试测试单个函数*test.go 文件每次代码变更
集成测试测试模块间交互internal/integration每日构建
端到端测试测试完整流程test/e2e发布前
性能测试测试性能指标test/performance版本发布

测试最佳实践

  • 使用表驱动测试
  • 模拟外部依赖
  • 测试覆盖率目标(如 80%+)
  • 测试自动化
  • 测试环境隔离

7. CI/CD 流程

大型项目的 CI/CD 流程

yaml
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-go@v3
        with:
          go-version: '1.21'
      - name: Test
        run: go test -v ./...

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build
        run: make build

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to staging
        run: make deploy

CI/CD 最佳实践

  • 自动化测试
  • 代码质量检查
  • 安全扫描
  • 环境隔离
  • 部署自动化
  • 回滚机制

8. 监控和可观测性

大型项目的监控

monitoring/
├── prometheus/      # Prometheus 配置
├── grafana/         # Grafana 仪表板
└── alertmanager/    # 告警配置

可观测性最佳实践

  • 指标:使用 Prometheus 收集指标
  • 追踪:使用 OpenTelemetry 进行分布式追踪
  • 日志:结构化日志和集中式日志管理
  • 告警:基于阈值的告警
  • 仪表板:实时监控系统状态

小结

本章介绍了 CloudWeGo 推荐的项目结构和大型项目组织最佳实践:

  1. 项目结构

    • 单体项目:适用于小型项目
    • 微服务项目:适用于中大型项目
    • Monorepo 项目:适用于多服务统一管理
  2. 目录职责

    • cmd:应用入口
    • internal:内部代码
    • pkg:公共代码
    • idl:IDL 定义
    • config:配置文件
  3. 大型项目最佳实践

    • 模块化设计:高内聚、低耦合
    • 依赖管理:版本锁定、定期更新
    • 代码组织:分层架构、单一职责
    • 配置管理:分层配置、敏感信息处理
    • 构建部署:容器化、编排、滚动更新
    • 测试策略:分层测试、自动化测试
    • CI/CD 流程:自动化、质量检查、安全扫描
    • 监控可观测性:指标、追踪、日志、告警
  4. 工具支持

    • Makefile:构建和管理
    • Dockerfile:容器化
    • Kubernetes:编排和部署
    • Helm:包管理

通过本章的学习,你应该掌握了如何组织和管理 CloudWeGo 项目,从小型项目到大型微服务架构,都能找到合适的项目结构和组织方式。在下一章中,我们将深入学习 Kitex RPC 框架的使用。