Go技术专家进阶营(一):通知平台需求分析与架构设计
写给每一个在多业务方对接中挣扎的后端开发者:如果你也经历过一个接口被五个业务方各改一遍的痛苦,这篇文章就是你的解药。
我是怕浪猫,一个在Go后端泥潭里摸爬滚打多年的开发者。从今天开始,我会用16周的时间,带你完整走完Go技术专家进阶营的全部内容。这个系列覆盖四大实战项目——通知平台、权限系统、WebSocket网关、分布式任务调度系统,从需求分析到性能优化,全流程闭环。
这是系列的第一篇,我们从通知平台的需求分析与架构设计开始。
平台类服务的核心难点不在于技术多酷,而在于能不能用一套设计兜住N个业务方的N种需求。
1.1 业务需求分析与拆解
通知平台的本质
通知平台是什么?说白了,就是一个消息分发中枢。上游是各种业务系统(订单、营销、风控、客服等),下游是各种通知渠道(短信、邮件、Push、站内信等)。通知平台的核心职责是:接收上游业务方的消息发送请求,根据规则路由到对应渠道,确保消息可靠投递。
听起来简单,但实际做起来,复杂度呈指数级上升。
典型业务场景拆解
假设我们在一个电商公司做通知平台,业务方包括:
- 订单中心:下单成功通知、支付成功通知、发货通知、签收通知
- 营销中心:促销活动Push、优惠券到期提醒、秒杀提醒
- 风控中心:异地登录告警、大额交易告警、风险操作拦截通知
- 客服中心:工单状态变更通知、回复提醒
- 用户中心:注册欢迎、绑定验证码、密码修改通知
每个业务方的需求差异很大:
| 维度 | 订单中心 | 营销中心 | 风控中心 | 客服中心 |
|---|---|---|---|---|
| 时效性 | 秒级 | 分钟级 | 秒级(实时) | 分钟级 |
| 量级 | 高(日均百万) | 中高(活动期间峰值) | 低 | 中 |
| 渠道 | 短信+Push+站内信 | Push+站内信 | 短信+电话 | 站内信+邮件 |
| 个性化 | 中(模板+变量) | 高(用户画像匹配) | 低(固定模板) | 中 |
| 优先级 | 中 | 低 | 最高 | 中 |
| 投递保证 | 至少一次 | 允许丢失 | 必须到达 | 至少一次 |
需求拆解的第一步不是画架构图,而是把每个业务方的需求摊在桌面上,逐维度对比。差异点就是设计点。
需求拆解方法论
怕浪猫在实践中总结了一套"四维拆解法":
第一维:功能需求
把所有业务方的通知需求列成一个清单,标注:
- 通知类型(验证码、营销、告警、状态变更等)
- 通知渠道(单渠道或多渠道组合)
- 模板需求(固定模板还是动态内容)
- 变量替换(哪些字段需要动态填充)
第二维:非功能需求
- 吞吐量:峰值QPS是多少?日均消息量多少?
- 延迟:P99延迟要求?是否需要实时送达?
- 可靠性:允许丢失吗?需要重试吗?
- 一致性:顺序要求?幂等要求?
第三维:业务约束
- 合规性:短信内容需要审核吗?营销推送有时间窗口限制吗?
- 降级策略:渠道不可用时怎么办?降级到哪个备选渠道?
- 限流策略:每个业务方的发送配额是多少?
第四维:演进需求
- 未来可能新增哪些渠道?(企业微信、钉钉、飞书等)
- 是否需要支持国际化?(多语言模板、海外渠道)
- 是否需要A/B测试能力?(同一通知多模板对比)
好的需求分析不是列出所有需求,而是识别出哪些需求会变、哪些不会变。会变的抽象成接口,不会变的固化成实现。
需求清单输出示例
经过四维拆解法,我们得到一份结构化的需求清单:
功能需求清单:
- 支持短信、邮件、Push、站内信四种渠道的消息发送
- 支持多业务方接入,每个业务方独立配置和管理
- 支持消息模板管理,含变量替换和多渠道适配
- 支持定时发送(如营销推送指定时间发送)
- 支持批量发送(如给10万用户群发活动通知)
- 支持渠道降级(如短信渠道不可用时降级到站内信)
- 支持优先级排序(风控告警优先于营销推送)
- 支持幂等去重(同一biz_id不重复发送)
- 支持投递结果回调通知业务方
- 支持发送记录查询和统计报表
非功能需求清单:
- API P99延迟 < 200ms(不含投递时间)
- 消息投递成功率 > 99.5%(短信渠道)
- 系统可用性 > 99.9%
- 峰值QPS 5000,日均消息量1000万
- 消息不丢失(至少一次投递语义)
- 水平可扩展,支持动态扩缩容
业务约束清单:
- 营销类短信发送时间窗口:8:00-22:00
- 验证码类短信有效期:5分钟
- 单业务方日发送量上限可配置
- 短信模板需运营商审核通过后方可使用
- 用户可设置免打扰时段,期间不接收营销类通知
DeepSeek 辅助需求分析
在实际项目中,可以借助 DeepSeek 等 AI 工具来辅助需求分析。具体用法包括:需求文档解析(把PRD丢给DeepSeek,让它提取结构化的需求清单)、场景补充(让AI帮你列举可能遗漏的边界场景)、优先级排序(让AI根据业务影响面帮你排优先级)、用例生成(基于需求自动生成测试用例骨架)。
注意:AI 辅助是加速器,不是决策者。AI 能帮你发现盲点,但最终的架构决策仍然需要你自己来做。
1.2 多业务方接入模型设计
接入模型的核心矛盾
多业务方接入的核心矛盾是:标准化与灵活性的平衡。
- 太标准:业务方觉得不够灵活,总有特殊需求满足不了
- 太灵活:每个业务方一套定制逻辑,平台变成了if-else大杂烩
平台类服务的黄金法则是:80%标准化兜底,20%扩展点留口。标准接口解决共性,扩展点解决个性。
业务方接入流程设计
一个完整的多业务方接入流程分为五个步骤:
步骤一:业务方注册
业务方在平台上注册,获取app_id(业务方唯一标识)、app_secret(接入密钥,用于接口鉴权)、namespace(命名空间,用于数据隔离)。
步骤二:渠道配置
业务方配置自己支持的通知渠道和参数。短信渠道需要配置签名名称、模板编号、服务商选择;邮件渠道需要配置发件人地址、SMTP参数;Push渠道需要配置AppID和设备Token来源;站内信需要配置消息分类和展示模板。
步骤三:模板配置
业务方上传或配置消息模板。模板ID全局唯一,模板内容支持变量占位符(如${user_name}、${order_id})。同一模板可适配多渠道——短信版精简、邮件版丰富。模板需要经过审核流程:待审核、审核通过、上线。
步骤四:配额与限流配置
为业务方设置发送配额:日发送上限防止异常业务方打爆平台,QPS限制保护下游渠道不被冲垮,渠道配额限制单渠道日发送量。
步骤五:接口对接
业务方通过标准API发送通知请求:
type SendRequest struct {
AppID string `json:"app_id"`
TemplateID string `json:"template_id"`
Channel string `json:"channel"`
Receiver string `json:"receiver"`
Variables map[string]string `json:"variables"`
Priority int `json:"priority"`
BizID string `json:"biz_id"`
SendTime *time.Time `json:"send_time"`
}业务方身份验证与鉴权
接入鉴权采用 HMAC-SHA256 签名方案。业务方用自己的 app_secret 对 app_id + timestamp + biz_id 做 HMAC-SHA256,将签名放在 HTTP Header 的 X-Notify-Signature 字段。平台侧用相同算法计算并比对。这种方案的好处是:密钥不在网络上传输,时间戳防止重放攻击,biz_id 防止重复处理。
func (s *AuthService) Auth(req *SendRequest, signature string, timestamp int64) error {
if math.Abs(float64(time.Now().Unix()-timestamp)) > 300 {
return ErrTimestampExpired
}
secret, err := s.store.GetAppSecret(req.AppID)
if err != nil {
return ErrAppNotFound
}
raw := fmt.Sprintf("%s%d%s", req.AppID, timestamp, req.BizID)
expected := hmac256(secret, raw)
if !hmac.Equal([]byte(expected), []byte(signature)) {
return ErrInvalidSignature
}
if !s.CheckPermission(req.AppID, req.Channel, req.TemplateID) {
return ErrNoPermission
}
return nil
}数据隔离设计
多业务方的数据隔离采用"逻辑隔离+物理隔离"混合方案。中小业务方通过 app_id 字段在共享表中做逻辑隔离,大业务方使用独立数据库做物理隔离,每个业务方在配置中心有独立的 namespace。配置隔离确保业务方的渠道配置、模板配置、限流配置互不影响。
数据隔离不是越严格越好,而是要跟业务规模匹配。小业务方物理隔离是浪费资源,大业务方逻辑隔离是埋雷。
业务方接入控制方案总结
| 控制维度 | 实现方案 | 关键参数 |
|---|---|---|
| 身份验证 | HMAC-SHA256签名 | app_id + app_secret + timestamp |
| 权限控制 | RBAC模型 | app_id × channel × template_id |
| 流量控制 | 令牌桶限流 | QPS + 日配额 |
| 数据隔离 | 逻辑隔离 + 物理隔离 | app_id字段 / 独立DB |
| 审计追溯 | 全链路日志 | 日志保留90天 |
1.3 通知平台整体架构设计
架构全景
通知平台的整体架构分为五层,每层职责清晰、边界明确。
第一层:接入层,负责接收业务方请求,完成鉴权、限流、参数校验。API Gateway作为统一入口支持HTTP/gRPC协议,鉴权中间件做HMAC签名验证和权限校验,限流中间件基于令牌桶做QPS控制,参数校验确保请求格式和必填字段完整。
第二层:处理层,核心业务逻辑处理。模板引擎负责变量替换、内容渲染、多渠道适配。路由引擎根据规则选择渠道(如用户未绑定手机号则降级到邮件)。优先级队列让高优先级消息插队(风控告警优先于订单通知,订单通知优先于营销推送)。去重/幂等模块基于 biz_id 做控制。
第三层:调度层,消息的调度与投递控制。消息队列(Kafka/RabbitMQ)解耦处理层和投递层。延迟队列支持定时发送。重试队列处理投递失败的消息。死信队列接收多次重试仍失败的消息,触发人工介入。
第四层:投递层,对接各渠道服务商完成实际投递。短信网关对接阿里云短信/腾讯云短信等。邮件网关对接SendGrid/AWS SES/自建SMTP。Push网关对接APNs/FCM/厂商Push通道。站内信网关写入用户消息表并推送给客户端。
第五层:存储与监控层。MySQL存储业务数据(模板、配置、日志)。Redis做缓存(模板缓存、配额计数、幂等去重)。Elasticsearch做日志检索。Prometheus + Grafana做指标监控。Jaeger做链路追踪。
架构设计的核心是分而治之:每一层只关心自己的职责,层间通过清晰的接口通信。但分层是有成本的——跨层调用越多,延迟越高。不是分得越细越好,要跟团队规模和业务复杂度匹配。
架构设计的关键决策
决策一:同步 vs 异步
通知发送采用"API同步接收,投递异步执行"的策略。业务方调用API后立即返回"已接收",不等待实际投递完成。投递过程异步进行,通过回调或查询接口获取投递结果。原因是通知投递依赖外部渠道(短信服务商等),延迟不可控,同步等待会拖垮整个系统。
决策二:消息队列选型
Kafka的优点是高吞吐、持久化、可回溯,缺点是运维复杂、无延迟队列,适合大规模消息平台。RabbitMQ的优点是功能丰富、支持延迟队列,缺点是吞吐量较低,适合中小规模。Redis Stream轻量低延迟,但消息可靠性一般。推荐方案:中小规模用RabbitMQ(自带延迟队列插件),大规模用Kafka加自研延迟队列。
决策三:微服务 vs 单体
通知平台初期建议单体架构,按模块清晰分层。当单日消息量超过千万级、团队规模超过10人、不同渠道发布节奏差异大、或某个渠道故障需要独立隔离时,再拆分微服务。
架构决策的本质是取舍。没有最优解,只有当前场景下最合适的解。
数据流设计
一条消息从接入到投递的完整数据流包括11个环节:业务方发送请求到API Gateway、鉴权和限流和参数校验、幂等检查(Redis SETNX biz_id)、模板渲染(从缓存读取模板做变量替换)、渠道路由(根据用户偏好和渠道可用性选择渠道)、写入消息队列(按渠道分Topic)、投递消费者从队列获取消息、调用渠道服务商API发送、记录投递结果、失败消息进入重试队列超过重试次数进入死信队列、回调通知业务方投递结果。
每个环节都需要考虑异常处理:鉴权失败返回401,幂等冲突返回200但标记重复请求,模板不存在返回400,所有渠道不可用时写入死信队列并告警,消费失败消息重新入队,渠道API超时进入重试队列,回调失败记录日志后续补偿。
高可用架构设计
通知平台的高可用采用"同城双活+异地灾备"方案。同城双活是两个机房同时提供服务,通过负载均衡分流,任一机房故障可秒级切换。异地灾备是异地机房做数据备份不提供服务,灾难时切换。渠道层面配置主备服务商(如短信渠道阿里云为主腾讯云为备),主渠道故障自动切备。
高可用不是"加机器",而是"减单点"。架构里每一个组件都要问:它挂了会怎样?有没有备选方案?
1.4 核心模块划分与接口定义
核心模块划分
通知平台划分为6个核心模块:
接入模块(Gateway):接收请求、鉴权、限流、路由。核心实体包括Request、Response、AuthContext。
模板模块(Template):模板管理、变量渲染、多渠道适配。核心实体包括Template、TemplateVariable、RenderResult。
路由模块(Router):渠道路由、降级策略、优先级排序。核心实体包括RouteRule、ChannelStrategy、Priority。
调度模块(Scheduler):消息队列管理、延迟发送、重试调度。核心实体包括Message、DelayTask、RetryPolicy。
投递模块(Delivery):渠道对接、投递执行、结果回调。核心实体包括ChannelClient、DeliveryResult、Callback。
监控模块(Monitor):指标采集、告警、链路追踪。核心实体包括Metric、Alert、Trace。
接口定义
接入模块的核心接口是NotificationService,包含Send(异步发送)、SendBatch(批量发送)、Query(查询结果)、Cancel(取消定时发送)四个方法。SendRequest结构体定义了业务方发送通知所需的全部字段,包括AppID、TemplateID、Channel、Receiver、Variables、Priority、BizID和可选的SendTime。
模板模块的核心接口是TemplateService,包含模板的CRUD和Render(渲染)方法。Template结构体定义了模板ID、业务方ID、名称、渠道、内容、变量定义和状态。渲染结果RenderResult包含渲染后的内容、邮件主题和Push标题。模板状态流转为:草稿、待审核、审核通过、审核拒绝。
路由模块的核心接口是RouterService,包含Route(选择渠道)、AddRule和UpdateRule方法。RouteRule定义了路由规则,包含业务方ID、消息类型、规则优先级、匹配条件和目标渠道列表。当主渠道不可用时,Fallback字段指定降级渠道。
调度模块的核心接口是SchedulerService,包含Enqueue(入队)、Dequeue(出队)、ScheduleDelay(延迟调度)和Retry(重试)方法。Message结构体是平台的核心消息实体,包含消息ID、业务ID、模板ID、渠道、接收者、内容、优先级、状态、重试次数和下次重试时间。
投递模块的核心接口是ChannelClient,包含Send、Health和Name方法。每个渠道(短信、邮件、Push、站内信)各有一个实现。DeliveryResult记录投递结果,包含消息ID、渠道、状态、服务商返回的消息ID和错误信息。
// 投递结果
type DeliveryResult struct {
MessageID string `json:"message_id"`
Channel string `json:"channel"`
Status string `json:"status"` // success/failed/pending
ProviderID string `json:"provider_id"` // 服务商返回的消息ID
Error string `json:"error,omitempty"`
SentAt time.Time `json:"sent_at"`
}
// 消息状态
type MessageStatus string
const (
StatusPending MessageStatus = "pending"
StatusQueued MessageStatus = "queued"
StatusSending MessageStatus = "sending"
StatusSent MessageStatus = "sent"
StatusFailed MessageStatus = "failed"
StatusCancelled MessageStatus = "cancelled"
)模块间依赖关系
接入模块调用模板模块做渲染,调用路由模块选渠道,调用调度模块做延迟和取消。路由模块选定渠道后调用调度模块入队。调度模块从队列取出消息调用投递模块发送。投递模块发送完成后回调接入模块通知结果。监控模块从所有模块采集指标。
这个依赖关系的关键设计原则是单向依赖、无循环依赖。如果出现循环依赖(如A依赖B,B又依赖A),说明模块划分有问题,需要重新切分。
接口定义的黄金原则:参数对象化、返回值结构化、错误显式化。别用5个string参数,用一个struct。别返回error就完事,返回结构化的结果让调用方判断。
模块划分原则
单一职责——每个模块只做一件事,模板只管渲染,投递只管发送。接口隔离——模块间通过接口通信,不依赖具体实现。依赖倒置——接入模块依赖SchedulerService接口,不依赖具体MQ实现。开闭原则——新增渠道只需实现ChannelClient接口,不改路由核心逻辑。数据自治——每个模块管理自己的数据,模板数据在模板库,消息数据在消息库。
1.5 DeepSeek 辅助需求分析与方案设计
AI 辅助开发的定位
在Go技术专家进阶营中,DeepSeek的定位是"辅助"而非"替代"。它能帮你加速信息收集和整理、补充你可能遗漏的场景、生成代码骨架和测试用例、提供方案对比的参考。但它不能替你做架构决策——架构决策需要结合团队能力、业务约束、历史包袱。它不能替你做权衡取舍——性能vs成本、一致性vs可用性需要你自己判断。它不能替你在生产环境排障——需要实际运行时信息和经验。
AI是放大器,不是替代品。它放大的是你已有的能力——如果你基础扎实,AI让你如虎添翼;如果你一知半解,AI只会让你更快地犯错。
DeepSeek 在需求分析阶段的具体用法
用法一:需求文档结构化。 把非结构化的需求文档丢给DeepSeek,让它输出结构化的需求矩阵。让它提取每条需求的来源业务方、功能/非功能分类、优先级(P0/P1/P2)、实现复杂度、依赖关系,输出为表格形式。
用法二:场景穷举。 让AI帮你穷举可能遗漏的场景。比如你已经识别了下单通知、支付通知、发货通知、营销推送、风控告警这些场景,让AI帮你补充:退款失败重试通知、订单超时未支付提醒、库存预警通知、物流异常告警、用户注销确认、优惠券过期提醒、积分到账通知、会员等级变更、商品降价提醒、系统维护公告等。每个场景再让AI分析边界条件和异常情况。
用法三:方案对比。 让AI帮你做方案对比分析。比如消息队列选型,把你的场景告诉AI(日均500万、峰值2000 QPS、需要延迟队列、需要死信处理、团队有Kafka经验),让AI从吞吐量、延迟、可靠性、运维成本、功能支持五个维度对比Kafka和RabbitMQ,给出推荐和理由。
用法四:代码骨架生成。 让AI帮你生成模块的代码骨架。比如告诉AI你要实现一个模板引擎,支持变量替换、条件判断、循环,让AI生成接口定义和核心方法骨架。你在此基础上填充具体逻辑。
DeepSeek 在方案设计阶段的用法
架构评审: 把架构设计文档丢给DeepSeek,让它扮演资深架构师Review。检查架构中有没有明显的单点故障、数据流中有没有遗漏的异常处理、模块边界是否清晰、是否存在循环依赖、扩展性如何。
设计模式建议: 描述设计问题让AI推荐设计模式。比如"通知平台需要支持多种渠道,每种渠道发送逻辑不同,但调用方式希望统一",AI会推荐策略模式或工厂模式并给出代码示例。
性能预估: 描述架构和预期流量让AI做性能预估。判断哪些模块可能是瓶颈、数据库需要什么配置、缓存命中率预期多少、消息队列需要多少Partition。
使用 AI 辅助的注意事项
验证再信任。 AI生成的内容可能有事实性错误。它可能给你一个不存在的API名称或过时的配置参数。所有AI生成的内容都需要自己验证。
上下文要充分。 AI的建议质量取决于你给的上下文。同样是"通知平台消息队列选型",给AI"日均100条"和"日均1000万条"会得到完全不同的建议。
不要用AI替代思考。 AI适合帮你做信息收集和整理,但架构决策的核心逻辑——为什么选A不选B、这个方案在未来一年会不会出问题——需要你自己想清楚。
工具用得好是助力,用不好是阻力。AI辅助开发的正确姿势是:你做决策,AI做执行;你定方向,AI补细节;你负责结果,AI提升效率。
1.6 架构设计文档输出
架构设计文档结构
经过前面的需求分析和架构设计,我们需要输出一份完整的架构设计文档。这份文档是后续开发的蓝图,也是团队沟通的基础。文档结构如下:
第一部分:概述。包含项目背景、项目目标、范围定义、术语表。项目背景说明为什么要做通知平台,解决什么问题。项目目标定义成功标准(如日均1000万消息、P99延迟200ms、可用性99.9%)。范围定义明确做什么不做什么(如第一期不做国际化、不做A/B测试)。
第二部分:需求分析。包含功能需求清单、非功能需求清单、业务约束清单、需求优先级矩阵。这部分直接使用1.1节的四维拆解法输出。
第三部分:系统架构。包含架构总览图、分层说明、模块划分、模块间依赖关系、数据流图、部署架构。架构总览图用框图展示五层架构和各模块的位置。分层说明详细描述每层职责和关键组件。数据流图展示一条消息从接入到投递的完整流转路径。
第四部分:详细设计。包含每个模块的详细设计,包括模块职责、接口定义、核心数据结构、核心流程、异常处理、配置项。这是文档的主体部分,每个模块需要单独一节。
第五部分:数据设计。包含数据库ER图、表结构定义、索引设计、缓存设计、数据生命周期。表结构需要明确字段名、类型、约束、索引、注释。缓存设计需要明确缓存什么数据、缓存策略(TTL/LRU)、缓存更新机制。
第六部分:接口规范。包含外部接口(业务方调用的API)和内部接口(模块间调用的接口)。每个接口需要定义:请求方法、URL、请求参数、响应格式、错误码、示例。
第七部分:非功能设计。包含高可用方案、性能设计、安全设计、可观测性设计。高可用方案描述同城双活和灾备策略。性能设计描述容量规划和性能目标。安全设计描述鉴权、加密、审计。可观测性描述日志、指标、链路追踪的采集和使用方案。
第八部分:风险与应对。识别主要风险并制定应对策略。如:渠道服务商故障(应对:多服务商主备切换)、消息积压(应对:扩容消费者+告警+降级)、数据库性能瓶颈(应对:分库分表+读写分离)。
关键设计决策记录(ADR)
架构决策记录(Architecture Decision Record)是团队协作中的重要文档,每个关键决策都需要记录背景、决策、理由和后果。
ADR-001:消息队列选择RabbitMQ
背景:通知平台需要消息队列解耦处理层和投递层,需要延迟队列支持定时发送。团队规模5人,运维能力有限。
决策:选择RabbitMQ作为消息队列。
理由:RabbitMQ自带延迟队列插件(rabbitmq_delayed_message_exchange),无需自研。功能丰富,支持消息确认、死信队列、优先级队列。团队有使用经验。日均500万消息量在RabbitMQ承受范围内。
后果:未来如果消息量增长到日均亿级,需要迁移到Kafka。但通过抽象SchedulerService接口,迁移成本可控。
ADR-002:模板渲染采用Go text/template
背景:通知模板需要支持变量替换和简单的条件判断。
决策:使用Go标准库的text/template包。
理由:标准库无需引入第三方依赖。性能好,编译后缓存。支持变量替换、条件判断、循环。足够满足通知模板的需求。
后果:模板能力受限于text/template的表达式语法。如果未来需要更复杂的模板逻辑(如数据查询、远程调用),需要扩展或替换模板引擎。
ADR-003:投递结果采用异步回调+主动查询双模式
背景:业务方需要知道通知是否发送成功。
决策:同时支持异步回调通知和主动查询接口。
理由:异步回调实时性好但可能丢失(业务方服务不可用时不一定能收到回调)。主动查询可靠但需要业务方轮询。两种模式互补,业务方按需选择。
后果:需要维护两套逻辑,增加系统复杂度。但通过统一的DeliveryResult模型,代码复用度高。
架构评审Checklist
在架构设计完成后,需要做一次架构评审。以下是评审Checklist:
| 检查项 | 通过标准 |
|---|---|
| 单点故障 | 每个关键组件是否有备选方案 |
| 数据一致性 | 消息是否会丢失、重复、乱序 |
| 性能瓶颈 | 是否有明显的性能瓶颈组件 |
| 可扩展性 | 能否通过加机器线性扩容 |
| 安全性 | 鉴权、加密、防重放是否到位 |
| 可观测性 | 日志、指标、链路追踪是否覆盖 |
| 容错能力 | 各类故障是否有降级/熔断/重试策略 |
| 运维成本 | 部署、配置、监控的复杂度是否可接受 |
| 演进能力 | 未来扩展(新渠道、新功能)是否需要大改 |
1.7 项目启动准备
技术选型确认
在开始编码之前,需要确认技术选型:
| 类别 | 选型 | 理由 |
|---|---|---|
| 编程语言 | Go 1.21+ | 课程要求,性能好、并发强 |
| Web框架 | Gin | 轻量、高性能、生态成熟 |
| ORM | GORM | Go生态最流行的ORM |
| 消息队列 | RabbitMQ | 支持延迟队列、功能丰富 |
| 缓存 | Redis 7+ | 性能好、数据结构丰富 |
| 数据库 | MySQL 8+ | 成熟稳定、团队熟悉 |
| 配置中心 | Viper + etcd | 本地配置+远程配置 |
| 日志 | zap | 高性能结构化日志 |
| 链路追踪 | OpenTelemetry | 开放标准、兼容Jaeger |
| 监控 | Prometheus + Grafana | 开源标配 |
| 容器化 | Docker + docker-compose | 开发环境编排 |
项目目录结构
notification-platform/
├── cmd/
│ ├── api/ # API服务入口
│ └── worker/ # 投递worker入口
├── internal/
│ ├── gateway/ # 接入模块
│ ├── template/ # 模板模块
│ ├── router/ # 路由模块
│ ├── scheduler/ # 调度模块
│ ├── delivery/ # 投递模块
│ │ ├── sms/ # 短信渠道
│ │ ├── email/ # 邮件渠道
│ │ ├── push/ # Push渠道
│ │ └── im/ # 站内信渠道
│ └── monitor/ # 监控模块
├── pkg/ # 可复用包
│ ├── auth/ # 鉴权工具
│ ├── ratelimit/ # 限流工具
│ ├── idempotent/ # 幂等工具
│ └── logger/ # 日志工具
├── configs/ # 配置文件
├── migrations/ # 数据库迁移
├── scripts/ # 脚本
├── tests/ # 集成测试
├── go.mod
└── go.sum这个目录结构遵循Go项目的标准布局:cmd放入口、internal放私有代码、pkg放可复用代码、configs放配置、migrations放数据库迁移。每个模块在internal下有独立的目录,模块内部可以自由组织代码。
开发环境准备
开发环境需要准备以下组件:
- Go 1.21+ 安装
- MySQL 8+ 本地实例(Docker)
- Redis 7+ 本地实例(Docker)
- RabbitMQ 3.12+ 本地实例(Docker,需安装延迟队列插件)
- Docker + docker-compose
- Make(用于Makefile自动化)
- protoc + protoc-gen-go(如果用gRPC)
用docker-compose一键启动依赖组件:
version: '3.8'
services:
mysql:
image: mysql:8
ports: ["3306:3306"]
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: notification
volumes: ["mysql_data:/var/lib/mysql"]
redis:
image: redis:7
ports: ["6379:6379"]
rabbitmq:
image: rabbitmq:3.12-management
ports: ["5672:5672", "15672:15672"]
volumes: ["rabbitmq_data:/var/lib/rabbitmq"]
volumes:
mysql_data:
rabbitmq_data:第一周里程碑
第一周结束时,应该完成以下交付物:
- 需求分析文档(需求清单、优先级矩阵)
- 架构设计文档(五层架构图、模块划分、接口定义)
- 关键决策记录(ADR-001至ADR-003)
- 项目脚手架(目录结构、Docker开发环境、基础配置)
- 数据库初始表结构(业务方表、模板表、消息表、发送日志表)
总结
第一周的核心任务是"想清楚再动手"。需求分析决定了做什么,架构设计决定了怎么做,接口定义确定了模块边界。这三件事做扎实了,后面三周的编码工作会顺利很多。
本周关键知识点回顾:
| 知识点 | 核心内容 |
|---|---|
| 需求拆解 | 四维拆解法:功能、非功能、业务约束、演进需求 |
| 接入模型 | 80%标准化 + 20%扩展点,HMAC签名鉴权 |
| 架构分层 | 五层架构:接入、处理、调度、投递、存储监控 |
| 模块划分 | 6个核心模块,接口隔离,单向依赖 |
| AI辅助 | DeepSeek用于需求结构化、场景穷举、方案对比、代码骨架 |
| 架构文档 | 八部分结构 + ADR决策记录 + 评审Checklist |
架构设计不是画PPT,是在约束条件下做最优取舍。你的每一个决策都要经得起"为什么"的追问。
觉得有用?收藏起来,下次搭建平台服务的时候直接照着这个流程走。你在做多业务方接入时遇到过什么坑?评论区聊聊。
关注怕浪猫,下期我们开始动手写代码——通知平台的核心功能实现,包括通用标准接口、多渠道通知支持、消息模板引擎、业务方接入控制和缓存策略。
系列进度 1/16 — 下一篇:通知平台核心功能实现
怕浪猫说:系列第一篇总是最"干"的,因为没有代码只有设计。但好的设计是好代码的前提。下周开始写代码,会越来越有意思。