在日常开发中,老大经常要求我们给出一个完善并合理的技术方案之后才能进行开发。并且要求技术方案一定要细,要重点覆盖监控、异常处理、灰度、降级方案。同时要注重边界处理。最初,我的技术方案写的很粗,也没有理解老大说的边界处理到底是怎么一回事。于是乎,辛辛苦苦写了一周的方案,就会在技术方案评审的时候直接打回重做,甚至多次打回。
不过还好,在经历过几次大项目的方案设计后,我的方案设计越来越完善,直到最后老大非常认可并在组内进行参考。随着我的方案设计逐渐完善,也逐渐发现,不但编码效率越来越高,编码时思维更加清晰,而且方案中的每一个模块都贯穿了整个软件生命周期。
在这里我会总结以往方案设计,给出一个方案设计模板,并给出模板中每一个模块的具体说明和案例,同时介绍如何通过领域驱动设计的思想拆分业务逻辑引入到这个设计模板中。
这一切看起来可能很枯燥乏味,但如果你认真读下去我想会对你有所帮助。
如果你在一个垃圾公司做的项目从来没上过线,或者上线就崩溃,可以认真看看,一个大流量、高稳定性的系统是如何实现的。
如果你有更好的方案设计,欢迎留言讨论,或者喷我。让我能够更加完善我的设计,谢谢!
在说如何编写一个好的技术方案之前,先说说一个错误的方案。
其实要说错误的方案设计是什么样子的,是很难界定出来的。错误可能有很多点,导致的后果也是不同的。比如:
好吧,上面说了那么多问题,接下来应该说说如何写好一个方案设计了。直接敲黑板说重点!个人认为一个好的方案设计就是为了完全避免上面的那些问题而设计的。所以重点就在于:
好了,这些都是重点。不过你会发现,8个重点里4、5、6、7、8都是在考虑各种异常情况下的各种补救措施,所以一个好的技术方案设计就是考虑到所有的异常情况。同样,一个技术人,我觉得不是看看“阿里p8”在今日头条和QQ群里发的课程内容就能修炼成精的,经历了N多次的线上事故总结,并总结如何避免事故的发生,才是技术人应该做的。
这里,给出一个我总结的技术方案设计模板,我会拿这个模板来说说如何做一个正确的方案设计。这个模板包含了上面说的所有重点项。如果你能够理解上面我所说的一切,利用好这套模板,拿出去吹nb是没什么问题的!
模板如下(忽略格式):
1. 背景
详细描述项目背景,简单说明以往业务带来的效果。给出为何要进行本次项目迭代的原因。
2. 目标
列出预计产出的业务指标(如:提升用户转化率30%)和技术指标(如:支撑多大QPS)。
3. 现有业务分析
现有业务分析中通常给出原有业务(本次基于原有业务迭代)或对比业内业务和技术的选型(新技术或原有业务迭代)。可以用表格列出原有业务和技术产生的效果、不足点,也可以用表格给出对比行业内多个现有方案的对比,写出每个方案的优缺点,以及是否与自己业务实际情况相匹配。
同时这里需要给出通用语言。
4. 系统整体架构
微服务提倡使用领域驱动设计的方式实现整体架构设计。将业务系统划分出核心域、支撑域、通用域。
核心域:通常要投入的成本比较大,在做技术方案设计时可以主要强调核心域。
通用域:可以引用通用域,在技术方案中进行简要的说明,给出如何依赖通用域,描述涉及到的调用关系以及如何调用的。
支撑域:通常项目的开发也会涉及到围绕着核心域的支撑域,所以可以和核心域一样进行设计。如果支撑域是现成的,同样给出依赖关系以及如何调用。
业务模型
业务模型是领域驱动设计的核心,也是战略设计时必须圈定出来的。可以画图给出子域、边界上下文、聚合,可以用表格标记出事件风暴规划出的域、聚合根、边界上下文、驱动类型。从业务边界和业务角色两种给出模型图。
域 | 聚合根 | 驱动类型(消息/接口) | 边界上下文 |
---|---|---|---|
层 | 聚合 | 对象 | 类型 | 依赖对象 | 包名 | 类名 | 方法名 |
---|---|---|---|---|---|---|---|
整体架构
上面给出了业务模型,划分出各层边界,这里就可以通过一张图给出领域模型经典的四层模型,用箭头画出上下层的依赖关系。画图时用不同的图标和颜色区分出层次、模块、角色、基础服务。如果能够区分出读写事件和命令,那么可以用CQRS的模型做。
画出图后,用适当的文字描述出关键模块、依赖关系、约束边界。
如果你是在修改以前的架构,这里给出修改之前的架构和修改之后的对比图。
5. 详细设计
进入详细设计,就要给出详细的流程图,并用文字描述出流程。用表格给出实体、值对象、域内服务,架构层面做了CQRS的话,这里明确出给出CQRS的职责。
xxx实体/域内服务
属性 | 类型 | 备注 |
---|---|---|
方法名 | 出参 | 入参 |
---|---|---|
xxx值对象
属性 | 类型 | 备注 |
---|---|---|
如果你是流程改造,要给出原有流程和现有流程的对比。若原有流程产生过问题,这里可以给出问题现象、原因,来证明新的流程进行优化原有流程。
对于关键部分可以给出伪代码,关键说明要用比较明显的字体样式。
6. 存储设计
用表格的形式给出存储结构(包括MySQL、ES、Redis等),说明Schema、字段类型、默认值、描述信息等。
表/索引xxx
字段名 | 字段类型 | 默认值 | 是否可空 | 备注 |
---|---|---|---|---|
7. 灰度方案
如果你的公司有灰度条件的话(业务有一定流量),用表格给出灰度范围、配置灰度开关的参数、灰度周期。灰度的三个周期:
a. 第一周:20%流量,比如某些二三线城市
b. 第二周:50%流量,比如一些一线城市+二线城市
c. 第三周:100%流量,比如全国
灰度可以让你在及时出现bug的情况下损失降到最低。
模块 | 灰度维度 | 配置变更 | 灰度周期(1) | 灰度周期(2) | 灰度周期(3) |
---|---|---|---|---|---|
8. 降级方案
及时通过灰度跑了很长时间,也不能100%保证你的代码是没有问题的。通常一个业务刚上线很稳定,但是随着时间的推移问题逐渐暴露,原因可能有很多:
a. 数据量积累大了,业务响应能力降低
b. 流量积累大了,现有计算力不够(并不是横向扩容就能解决的)
c.用户操作花样倍出,防不胜防
d.依赖的服务逐渐不稳定(包括网络、基础设施等)
所以降级方案是必须要有的,防止出现问题之后没有退路。降级方案可以说是一个长期的及时止损方案,灰度是一个短期的及时止损方案。
降级方案用表格给出业务模块或接口、降级方式(自动、手动)、降级是否对主要业务流程有损失、若有损失修复方案。在设计降级方案时,一定要与产品、测试、业务人员进行充分沟通,说明降级方案,一起讨论可行性。
模块 | 主流程 | 是否可降级 | 降级流程 | 是否有损(对主流程) | 备注 |
---|---|---|---|---|---|
9. 异常处理
有了降级方案依然不能代表你的业务会100%可靠。完成功能谁都可以,但是能把所有异常情况都考虑到,是最难的。没有人能考虑到所有异常,但是只要考虑到,总会让你的业务更可靠一点。
异常处理也是需要通过表格,主要写明以下几个阶段:
a.异常出现阶段:给出异常情况
b.异常处理阶段:是否可以降级,修复异常方案(精确写出处理流程,有必要的话给出流程图)
c.异常恢复阶段:给出带来的损失以及数据如何修复
模块 | 异常情景 | 处理流程 | 降级方案 | 损失与数据恢复 |
---|---|---|---|---|
10. 容量预估
容量预估里包含了流量预估,这一部分是可以保证你的业务不会在极端情况下压垮(大数据量、高并发)。
流量预估
用表格的形式给出你的接口平均QPS、峰值QPS、接口请求和返回报文大小,消息队列的平均消息数、峰值消息数、报文大小。
这一部分如果是改动的业务,可以参考以前的监控,如果是新业务一定要拉运营、产品确定业务量。若预估峰值会很高,一定要进行压测。
如下表:
模块 | 接口/Topic | 报文大小 | 上线一周 | 上线一个月 | 上线半年 | 上线一年 |
---|---|---|---|---|---|---|
容量预估
列出表格,指定业务模块,给出你用到的所有存储在一段时间的数据量增长:
a.上线一周:评估灰度时会产生的数据量,有助于推导出后续产生的数据量
b.上线一个月:此时已经稳定的全量跑了一个月,如果业务比较火爆,这个时候产生的数据量足以计算出半年和一年的数据量
c.上线半年:如果你的业务并不火爆,半年的数据量基本是定型了。你的业务未来发展也不会增长太多。但是如果你的数据量预估是一个比较大的值,就要考虑方案是不是可以扛得住这个数据量。
d.上线一年:这个时候随着数据量的积累,可能会暴露出一些问题。需要考虑你的方案在每个细节方面是否可靠了。
这里有一个需要注意的,并不是只是评估存储大小就够了,如果预估你的流量很大,一定要精确计算出你的一个请求过程产生的对象大小,防止应用服务被频繁gc Hang死。
模块 | 表/索引 | 上线一周 | 上线一个月 | 上线半年 | 上线一年 |
---|---|---|---|---|---|
11. 监控报警
上面的一切做完,依然不完美,出现问题要及时的发现,有一个nb的监控策略是很重要的。这里要用表格的形式给出关键模块或接口的异常报警形式(短信、邮件、IM、电话等),给出核心的业务指标和非业务指标(QPS、响应耗时、消息积压数等),指标出现异常(低于某个阈值)要进行报警。如果有监控系统可以接入,给出需要接入的指标参数。
如下表:
模块 | 指标 | 阈值 | 报警形式 |
---|---|---|---|
12. 参考文档
给出产品设计文档、需求文档、以往的方案设计文档、接口文档、依赖基础组件或服务的说明文档。给出文档链接或附件,方便review的过程中直接打开看。