Ads Service
一个高性能、可扩展的广告管理微服务,基于 gRPC 和 HTTP Gateway 架构,提供广告位管理、广告内容分发等核心功能。
🚀 特性
- 📢 广告管理: 多类型广告内容管理(文本、图片、视频、音频、链接、附件)
- 📍 广告位管理: 灵活的广告位配置和分类管理
- ⚡ 高性能: Redis缓存 + 数据库优化,支持高并发访问
- 🔄 智能缓存: 10分钟缓存策略,提升响应速度
- 🐳 容器化: 完整的Docker支持
- 📊 监控: 健康检查和APM集成
- 🔒 安全: 完善的错误处理和输入验证
- 🌐 多协议: 支持gRPC和HTTP Gateway双重访问方式
📋 目录
🚀 快速开始
环境要求
- Go: 1.25.1+
- PostgreSQL: 12+
- Redis: 6+
- Docker: 20.10+ (可选)
- Protocol Buffers: 3.15+ (开发需要)
快速安装
# 克隆项目
git clone git.apinb.com/bsm-apps/ads.git
cd ads
# 安装依赖
go mod tidy
# 生成代码
make proto
# 构建应用
go build -o bin/ads cmd/main/main.go
# 运行服务
./bin/ads
Docker 快速启动
# 构建镜像
docker build -t ads-service .
# 运行容器
docker run -d --name ads-service \
-p 12216:12216 \
-p 12102:12102 \
-e SERVICE_ENV=development \
ads-service
📁 项目结构
ads/
├── 📁 cmd/ # 应用程序入口
│ ├── 📁 main/ # 主服务入口
│ └── 📁 cli/ # 命令行工具
├── 📁 internal/ # 内部包
│ ├── 📁 config/ # 配置管理
│ ├── 📁 impl/ # 实现层
│ ├── 📁 logic/ # 业务逻辑
│ │ └── 📁 fetch/ # 广告获取逻辑
│ ├── 📁 models/ # 数据模型
│ └── 📁 server/ # 服务器实现
├── 📁 pb/ # Protocol Buffers 生成代码
├── 📁 proto/ # Protocol Buffers 定义文件
├── 📁 swagger/ # API 文档
├── 📁 scripts/ # 脚本文件
├── 📁 etc/ # 配置文件
├── 🐳 Dockerfile # Docker 镜像构建
├── 🔧 Makefile # 构建脚本
└── 📖 README.md # 项目文档
🔧 核心功能
1. 广告获取服务 (Fetch Service)
📍 按广告位获取广告 (ByPos)
rpc ByPos(ByPosRequest) returns (ByPosReply)
- 功能: 根据广告位标识获取对应的广告内容
- 特性:
- 支持多种广告类型(文本、图片、视频、音频、链接、附件)
- Redis缓存加速,缓存时间10分钟
- 只返回启用状态的广告
- 完整的错误处理和日志记录
- 用途: 前端页面广告展示、移动端广告投放
2. 广告类型支持
| 类型 | 值 | 描述 | 用途 |
|---|---|---|---|
| 文本 | 1 | 纯文本广告 | 文字推广、通知公告 |
| 图片 | 2 | 图片广告 | 横幅广告、图片推广 |
| 视频 | 3 | 视频广告 | 视频推广、宣传片 |
| 音频 | 4 | 音频广告 | 音频推广、语音广告 |
| 链接 | 5 | 链接广告 | 跳转链接、外部推广 |
| 附件 | 6 | 附件广告 | 文件下载、文档推广 |
📚 API文档
gRPC 服务
| 服务 | 方法 | 描述 | 端口 |
|---|---|---|---|
| Fetch | ByPos | 按广告位获取广告 | 12216 |
HTTP Gateway
| 端点 | 方法 | 描述 |
|---|---|---|
/ads.Fetch/ByPos |
POST | 按广告位获取广告 |
Swagger 文档
- 本地: http://localhost:12102/ads.swagger.json
- 在线: 通过 HTTP Gateway 访问完整的 API 文档
请求示例
gRPC 请求
// 请求
{
"key": "homepage_banner"
}
// 响应
{
"data": [
{
"id": 1,
"title": "首页横幅广告",
"content": "欢迎使用我们的服务",
"type": 2,
"toUrl": "https://example.com",
"created": "2024-01-01 12:00:00"
}
]
}
HTTP 请求
curl -X POST http://localhost:12102/ads.Fetch/ByPos \
-H "Content-Type: application/json" \
-d '{"key": "homepage_banner"}'
🛠️ 开发指南
开发环境设置
# 安装开发工具
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
# 启动开发模式
go run cmd/main/main.go
代码生成
# 生成 protobuf 代码
protoc --go_out=. --go-grpc_out=. proto/ads.proto
# 生成 Swagger 文档
protoc --grpc-gateway_out=. --openapiv2_out=swagger proto/ads.proto
测试
# 运行所有测试
go test ./...
# 测试覆盖率
go test -cover ./...
# 代码检查
go vet ./...
gofmt -s -w .
数据库管理
# 初始化数据库表
go run cmd/main/main.go --init-db
# 数据库迁移
gorm migrate
🚀 部署说明
Docker 部署
# 构建镜像
docker build -t ads-service:latest .
# 启动服务栈
docker run -d --name ads-service \
-p 12216:12216 \
-p 12102:12102 \
-e SERVICE_ENV=production \
-e CONFIG_FILE=etc/ads_prod.yaml \
ads-service:latest
生产环境部署
-
环境准备
# 创建生产配置 cp etc/ads_dev.yaml etc/ads_prod.yaml # 编辑生产配置... -
数据库初始化
# 创建数据库表 psql -h your-db-host -U postgres -d ads_db -c " CREATE TABLE IF NOT EXISTS ads_pos ( id SERIAL PRIMARY KEY, key VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS ads_item ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, pos_key VARCHAR(255) NOT NULL, content VARCHAR(255) DEFAULT '', type INTEGER DEFAULT 0, to_url VARCHAR(255) DEFAULT '', status INTEGER DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); " -
服务启动
# 构建生产版本 CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/ads-linux cmd/main/main.go # 启动服务 ./bin/ads-linux
Kubernetes 部署
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ads-service
spec:
replicas: 3
selector:
matchLabels:
app: ads-service
template:
metadata:
labels:
app: ads-service
spec:
containers:
- name: ads-service
image: ads-service:latest
ports:
- containerPort: 12216
- containerPort: 12102
env:
- name: SERVICE_ENV
value: "production"
- name: CONFIG_FILE
value: "etc/ads_prod.yaml"
⚡ 性能优化
缓存策略
| 数据类型 | 缓存时间 | 策略 | 说明 |
|---|---|---|---|
| 广告数据 | 10分钟 | 按广告位缓存 | 提升查询性能 |
| 广告位信息 | 30分钟 | 全量缓存 | 减少数据库查询 |
数据库优化
- 索引优化: 在
pos_key和status字段建立复合索引 - 查询优化: 只查询启用状态的广告
- 连接池: 配置合适的连接池大小
- 读写分离: 支持主从数据库配置
监控指标
# 服务健康检查
curl http://localhost:12102/health
# 性能指标
curl http://localhost:12102/metrics
🔧 配置说明
环境配置文件
# etc/ads_prod.yaml
Service: ads
Port: 12216
# 数据库配置
Databases:
Driver: postgres
Source:
- host=db-host user=postgres password=*** dbname=ads_db port=5432 sslmode=require
# 缓存配置
Cache: redis://username:password@redis-host:6379/0
# 网关配置
Gateway:
Enable: true
Port: 12102
# 微服务配置
MicroService:
Enable: true
Registry: etcd://etcd-cluster:2379
# APM监控
APM:
Platform: elasticAPM
Endpoint: http://apm-server:8200
环境变量
| 变量名 | 描述 | 默认值 |
|---|---|---|
SERVICE_ENV |
运行环境 | development |
CONFIG_FILE |
配置文件路径 | etc/ads_dev.yaml |
LOG_LEVEL |
日志级别 | info |
TZ |
时区设置 | Asia/Shanghai |
🐛 故障排除
常见问题
-
服务启动失败
# 检查端口占用 netstat -tlnp | grep :12216 # 检查配置文件 go run cmd/main/main.go --check-config -
数据库连接失败
# 测试数据库连接 psql -h your-db-host -U postgres -d ads_db -c "SELECT 1;" -
Redis连接失败
# 测试Redis连接 redis-cli -h your-redis-host ping
日志分析
# 查看服务日志
tail -f logs/ads.log
# 查看错误日志
grep ERROR logs/ads.log
# 查看性能日志
grep "slow query" logs/ads.log
性能调优
-
内存优化
# 监控内存使用 go tool pprof http://localhost:6060/debug/pprof/heap -
CPU优化
# CPU性能分析 go tool pprof http://localhost:6060/debug/pprof/profile
📊 数据模型
核心表结构
ads_pos - 广告位表
CREATE TABLE ads_pos (
id SERIAL PRIMARY KEY,
key VARCHAR(255) NOT NULL, -- 广告位标识
name VARCHAR(255) NOT NULL, -- 广告位名称
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
ads_item - 广告内容表
CREATE TABLE ads_item (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL, -- 广告标题
pos_key VARCHAR(255) NOT NULL, -- 广告位标识
content VARCHAR(255) DEFAULT '', -- 广告内容
type INTEGER DEFAULT 0, -- 广告类型
to_url VARCHAR(255) DEFAULT '', -- 跳转链接
status INTEGER DEFAULT 1, -- 状态(1:启用 0:禁用)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
🤝 贡献指南
开发流程
- Fork 项目
- 创建特性分支:
git checkout -b feature/amazing-feature - 提交更改:
git commit -m 'Add amazing feature' - 推送分支:
git push origin feature/amazing-feature - 创建 Pull Request
代码规范
- 遵循 Go 官方代码规范
- 使用
gofmt格式化代码 - 添加必要的注释和文档
- 编写单元测试
提交规范
type(scope): description
[optional body]
[optional footer]
类型:
feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式refactor: 重构test: 测试chore: 构建过程或辅助工具的变动
📄 许可证
本项目采用内部许可证,仅供 BSM 内部使用。
👥 团队
- 作者: David Yan (david.yan@qq.com)
- 维护者: BSM 开发团队
- 项目地址: git.apinb.com/bsm-apps/ads
🔗 相关链接
⭐ 如果这个项目对你有帮助,请给它一个星标!
Made with ❤️ by BSM Team