Files
trading_assistant/README.md
2026-02-06 15:23:41 +08:00

406 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Go Monorepo 目录结构设计
适配小团队开发,满足**业务独立部署、发布互不影响**,基于`docker compose`实现一键发布,遵循**轻量设计、无过度封装**原则,整体结构兼顾可维护性和开发效率,各业务模块解耦且资源可复用。
## 核心设计思路
1. **单仓库多业务**所有代码归拢在一个monorepo团队协作更便捷
2. **业务模块独立**:每个业务单独放在`services/`拥有独立的Go代码、配置、Dockerfile、docker-compose子配置做到独立构建/部署/发布;
3. **公共资源复用**:抽离公共库、工具、中间件配置,避免重复开发,公共代码变更需做兼容性保证(不影响各业务);
4. **根目录一键部署**:通过根目录`docker-compose.yml`聚合所有业务,支持**全局启动**或**单独启动某一个业务**,满足团队开发/生产不同场景。
---
# 最终目录结构
```
go-monorepo/
├── Makefile # 全局快捷命令(构建、启动、停止、日志等,简化团队操作)
├── docker-compose.yml # 根级compose聚合所有业务支持独立启动单个服务
├── .env # 全局环境变量数据库、Redis等公共中间件地址团队统一配置
├── .gitignore # git忽略规则go编译产物、docker日志、.env等
├── go.work # Go 1.18+ 工作区文件管理多模块实现monorepo依赖管理
├── go.work.sum # 工作区依赖校验文件
├── common/ # 公共复用模块(所有业务均可依赖,团队统一维护,保证通用性)
│ ├── go.mod # 公共模块的mod文件模块名go-monorepo/common
│ ├── go.sum
│ ├── db/ # 公共数据库封装PostgresSQL连接、基础CRUD轻量无过度封装
│ │ ├── postgres.go
│ │ └── options.go
│ ├── redis/ # 公共Redis封装连接池、基础操作
│ │ └── redis.go
│ ├── logger/ # 公共日志zap轻量封装统一日志格式
│ │ └── logger.go
│ ├── utils/ # 公共工具函数(加密、时间、字符串等)
│ │ └── common.go
│ └── middleware/ # 公共中间件HTTP跨域、限流、日志Gin适配
│ └── cors.go
├── services/ # 业务服务根目录(每个子目录是一个独立业务,可单独部署)
│ ├── user/ # 业务1用户服务示例团队可按业务拆分如order/pay/user
│ │ ├── go.mod # 独立mod文件依赖根目录common模块名go-monorepo/services/user
│ │ ├── go.sum
│ │ ├── main.go # 服务入口Gin/GRPC均可示例用Gin
│ │ ├── conf/ # 业务独立配置(可覆盖全局.env支持多环境
│ │ │ └── config.go
│ │ ├── api/ # 接口层HTTP路由、请求响应体
│ │ │ └── user_api.go
│ │ ├── service/ # 业务逻辑层
│ │ │ └── user_service.go
│ │ ├── dao/ # 数据访问层操作PostgresSQL依赖common/db
│ │ │ └── user_dao.go
│ │ ├── model/ # 数据模型(数据库表结构、结构体)
│ │ │ └── user_model.go
│ │ ├── Dockerfile # 业务独立Dockerfile单独构建镜像不影响其他业务
│ │ └── docker-compose.yml # 业务独立compose单独部署时使用仅包含自身+依赖的中间件)
│ ├── order/ # 业务2订单服务和user服务结构完全一致独立部署
│ │ ├── [结构同user服务]
│ └── pay/ # 业务3支付服务团队可一人负责一个核心业务完美适配
│ ├── [结构同user服务]
├── deploy/ # 部署相关资源(非必须,可放公共配置、初始化脚本)
│ ├── postgres/ # PostgresSQL初始化建库、建表、初始化数据脚本
│ │ └── init.sql
│ └── redis/ # Redis初始化可选配置文件、持久化脚本
│ └── redis.conf
└── logs/ # 全局日志目录docker挂载所有服务日志统一存放便于排查
└── .gitkeep
```
---
# 关键文件说明(核心实现,保证独立部署+复用)
## 1. Go工作区文件 `go.work`monorepo核心
Go 1.18+ 引入的**工作区模式**是实现monorepo的关键无需将common发布到私服本地即可实现多模块依赖且每个业务模块独立管理自身依赖。
**go.work 内容**
```go
go 1.21 // 建议使用稳定版Go团队统一版本
// 加入公共模块
use ./common
// 加入所有业务服务模块(新增业务时只需追加一行)
use ./services/user
use ./services/order
use ./services/pay
```
**作用**:所有模块在同一个工作区,业务服务可直接通过`import "go-monorepo/common/xxx"`依赖公共库,本地开发无需手动`go mod replace`,团队协作无依赖问题。
## 2. 公共模块 `common/go.mod`(轻量封装,无过度设计)
仅声明公共依赖,暴露简单接口,不做复杂业务封装,示例:
```go
module go-monorepo/common
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
github.com/jmoiron/sqlx v1.3.5
github.com/redis/go-redis/v9 v9.3.0
go.uber.org/zap v1.26.0
github.com/lib/pq v1.10.9 // PostgresSQL驱动
)
require (
// 间接依赖go mod tidy 自动生成)
)
```
## 3. 业务模块 `services/user/go.mod`(独立依赖,发布不影响其他业务)
业务模块仅依赖自身需要的包+公共模块,**每个业务的mod独立管理**,升级依赖/修改代码不会影响其他业务,示例:
```go
module go-monorepo/services/user
go 1.21
// 依赖本地公共模块(工作区模式下,无需指定版本)
require go-monorepo/common v0.0.0-00010101000000-000000000000
// 业务自身的依赖(仅引入当前业务需要的,按需添加)
require (
github.com/gin-gonic/gin v1.9.1
github.com/joho/godotenv v1.5.1 // 环境变量解析
)
// 工作区模式下的本地依赖映射go work sync 自动生成,无需手动修改)
replace go-monorepo/common => ../../common
```
**关键**:新增/升级业务依赖仅修改当前业务的`go.mod`,其他业务不受影响,实现**发布隔离**。
## 4. 业务独立Dockerfile`services/user/Dockerfile`
轻量多阶段构建,仅构建当前业务,镜像体积小,独立构建不影响其他业务,**所有业务的Dockerfile格式统一**(团队规范),示例:
```dockerfile
# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /app
# 复制当前业务的代码仅复制user目录不涉及其他业务
COPY . .
# 设置Go代理加速构建
ENV GOPROXY=https://goproxy.cn,direct
# 编译(静态编译,无系统依赖)
RUN go build -ldflags="-s -w" -o user-server main.go
# 运行阶段使用alpine基础镜体积仅数MB
FROM alpine:3.19
WORKDIR /app
# 从构建阶段复制编译产物
COPY --from=builder /app/user-server .
# 复制业务配置(可选)
COPY --from=builder /app/conf ./conf
# 暴露业务端口user服务示例用8080order可8081pay可8082互不冲突
EXPOSE 8080
# 启动命令
CMD ["./user-server"]
```
**特点**:每个业务单独构建镜像,镜像名区分(如`go-monorepo-user:latest`),发布时仅推送当前业务的镜像即可。
## 5. 根目录`docker-compose.yml`(聚合所有业务,支持独立启动)
核心满足**全局启动所有服务**/**单独启动某一个业务**所有中间件PostgresSQL/Redis全局共享团队无需为每个业务单独部署中间件通过`depends_on`控制依赖关系,**业务服务之间通过服务名访问**如user服务访问order服务`http://order:8081`)。
**核心内容**
```yaml
version: '3.8' # 兼容主流Docker版本
services:
# 公共中间件PostgresSQL所有业务共享团队统一管理
postgres:
image: postgres:16-alpine
container_name: monorepo-postgres
environment:
POSTGRES_USER: ${PG_USER:-root}
POSTGRES_PASSWORD: ${PG_PWD:-123456}
POSTGRES_DB: ${PG_DB:-monorepo}
ports:
- "${PG_PORT:-5432}:5432"
volumes:
- ./deploy/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化脚本
- pg_data:/var/lib/postgresql/data # 数据持久化
networks:
- monorepo-net
restart: always
# 公共中间件Redis所有业务共享
redis:
image: redis:7-alpine
container_name: monorepo-redis
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- ./deploy/redis/redis.conf:/etc/redis/redis.conf
- redis_data:/data
command: redis-server /etc/redis/redis.conf
networks:
- monorepo-net
restart: always
# 业务服务1用户服务
user:
build:
context: ./services/user # 仅构建user目录独立构建
dockerfile: Dockerfile
container_name: monorepo-user
environment:
- GIN_MODE=release
- PG_ADDR=postgres:5432 # 访问公共PG通过服务名
- REDIS_ADDR=redis:6379 # 访问公共Redis
ports:
- "8080:8080"
volumes:
- ./logs/user:/app/logs # 日志挂载到本地
networks:
- monorepo-net
restart: always
depends_on:
- postgres
- redis
# 可选:限制资源(团队开发/测试环境,避免单个服务占满资源)
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
# 业务服务2订单服务和user服务结构一致独立部署
order:
build:
context: ./services/order
dockerfile: Dockerfile
container_name: monorepo-order
environment:
- GIN_MODE=release
- PG_ADDR=postgres:5432
- REDIS_ADDR=redis:6379
ports:
- "8081:8081"
volumes:
- ./logs/order:/app/logs
networks:
- monorepo-net
restart: always
depends_on:
- postgres
- redis
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
# 业务服务3支付服务独立部署
pay:
build:
context: ./services/pay
dockerfile: Dockerfile
container_name: monorepo-pay
environment:
- GIN_MODE=release
- PG_ADDR=postgres:5432
- REDIS_ADDR=redis:6379
ports:
- "8082:8082"
volumes:
- ./logs/pay:/app/logs
networks:
- monorepo-net
restart: always
depends_on:
- postgres
- redis
deploy:
resources:
limits:
cpus: "0.5"
memory: "512M"
# 全局网络:所有服务在同一个网络,通过服务名互通
networks:
monorepo-net:
driver: bridge
# 全局数据卷:中间件数据持久化,不会随容器删除
volumes:
pg_data:
redis_data:
```
## 6. 业务独立`docker-compose.yml``services/user/docker-compose.yml`
满足**单独部署某一个业务**的场景如仅修改了user服务只需发布user无需启动其他业务仅包含当前业务+必要的中间件(也可连接外部已有的中间件),示例:
```yaml
version: '3.8'
services:
user:
build:
context: .
dockerfile: Dockerfile
container_name: standalone-user
environment:
- GIN_MODE=release
- PG_ADDR=192.168.1.100:5432 # 可连接外部PG/Redis无需启动本地中间件
- REDIS_ADDR=192.168.1.100:6379
ports:
- "8080:8080"
volumes:
- ../../logs/user:/app/logs
restart: always
networks:
default:
driver: bridge
```
## 7. 全局Makefile简化团队操作避免记复杂命令
团队统一使用Makefile命令降低操作成本**所有命令支持全局/单独业务执行**,示例:
```makefile
# 全局启动所有服务(中间件+所有业务)
up:
docker compose up -d
# 单独启动某一个业务如usermake up-svc svc=user
up-svc:
docker compose up -d $(svc)
# 全局停止所有服务
down:
docker compose down
# 单独停止某一个业务
down-svc:
docker compose stop $(svc)
# 构建所有业务镜像
build:
docker compose build
# 单独构建某一个业务镜像(核心:发布时仅构建当前业务)
build-svc:
docker compose build $(svc)
# 查看所有服务日志
logs:
docker compose logs -f
# 查看某一个业务日志
logs-svc:
docker compose logs -f $(svc)
# 重新启动某一个业务(修改代码后,一键重启)
restart-svc:
docker compose restart $(svc)
# 清理无用镜像/容器(团队开发环境,定期清理)
clean:
docker system prune -f
# 初始化Go工作区新成员拉取代码后一键执行
go-init:
go work init
go work use ./common
go work use ./services/user
go work use ./services/order
go work use ./services/pay
go mod tidy
```
**团队使用示例**
- 新成员拉取代码:`make go-init`初始化Go工作区解决依赖
- 开发用户服务:`make build-svc svc=user && make up-svc svc=user`(仅构建+启动user服务
- 发布订单服务:`make build-svc svc=order && make restart-svc svc=order`(仅构建+重启order服务不影响user/pay
- 全局启动所有服务(测试环境):`make up`
---
# 团队开发&发布流程(适配团队)
## 开发流程(一人负责一个核心业务,互不干扰)
1. 拉取monorepo代码`git clone <仓库地址> && cd go-monorepo && make go-init`
2. 开发各自业务如A开发userB开发orderC开发pay仅修改`services/[自己的业务]`目录下的代码;
3. 公共代码修改如common/logger需团队沟通保证兼容性不修改现有接口仅新增避免影响其他业务
4. 本地测试:使用`make build-svc svc=xxx && make up-svc svc=xxx`仅启动自己的业务,快速验证。
## 发布流程(业务独立发布,不影响其他服务)
### 生产/测试环境发布单个业务(核心需求)
```bash
# 1. 拉取最新代码(仅拉取,不影响运行中的服务)
git pull origin main
# 2. 仅构建当前业务的镜像如发布pay服务
make build-svc svc=pay
# 3. 仅重启当前业务容器(秒级重启,不影响其他服务)
make restart-svc svc=pay
```
### 首次部署/全局发布(如测试环境初始化)
```bash
make go-init && make build && make up
```
---
# 关键满足点验证
1.**无需过度封装**common仅做轻量基础封装无业务逻辑业务模块结构简单api/service/dao/model四层团队易理解
2.**业务独立部署**每个业务有独立Dockerfile、compose支持`make up-svc svc=xxx`单独启动也可通过业务目录下的compose单独部署
3.**发布互不影响**:发布时仅构建/重启当前业务镜像,其他业务容器正常运行,公共代码变更做兼容性保证;
4.**docker compose发布**根目录compose聚合所有服务支持全局/单独发布Makefile封装所有命令团队使用便捷
5.**团队适配**:一人一个核心业务,目录结构清晰,公共代码统一维护,开发/发布命令简化,无复杂配置。
---
# 扩展建议(团队可按需添加,不影响现有结构)
1. **新增业务**:在`services/`下新建业务目录复制user服务的基础结构go.mod、Dockerfile、目录分层`go.work`和根`docker-compose.yml`中追加一行,即可实现独立部署;
2. **多环境配置**:在各业务`conf/`下添加`dev/ prod/ test`目录,通过环境变量`ENV=prod`指定配置文件,根`.env`区分不同环境的变量;
3. **接口文档**:在各业务`api/`下添加`swagger/`目录,使用`swag init`生成接口文档独立访问如user服务`http://localhost:8080/swagger/index.html`
4. **监控告警**:根`docker-compose.yml`中新增Prometheus+Grafana服务所有业务暴露metrics接口统一监控轻量配置团队易维护
5. **代码规范**:添加`golangci-lint`配置文件(.golangci.yml团队提交代码前执行`golangci-lint run`,保证代码风格统一。
### 总结
本次设计的Go Monorepo核心围绕**小团队高效开发**和**业务独立部署发布**通过Go工作区实现monorepo依赖管理`services/`为业务隔离边界结合Docker和docker compose实现**独立构建、独立发布、全局聚合**同时通过Makefile封装所有操作降低团队协作成本。整体结构轻量、可扩展无需过度设计完全匹配任务要求。