如果你接到了一个开发需求:开发一个抽奖活动的后台系统。第一反应如果是打开IDEA,新建一个项目,输入项目名:lottery。然后开始根据需求着手开始进行设计数据库,api,然后进行开发,这是太平常不过的开发流程。
过了一段时间,你又接到一个类似的需求:开发另一个抽奖活动的后台系统,但是里面的一些业务逻辑、流程处理不太一样,然后就把前一个完成的后台系统复制过来,准备开始修改。
是时候停止这种看起来很高效但实际上很愚蠢的开发方式了!本文将告诉你如何将你的思想转变过来,给你一个将业务、将系统、甚至将自己升华的机会。我会用偏后端的思维、尽量易懂的图文、尽量精简的代码、尽量多的例子来将你的等级从 熟练的业务驯服者
提升为 初阶架构猎人
。
使用复制、粘贴、修改的方法去开发一个类似的新的业务系统,从开发单个系统上来看开发效率上确实挺高的,但仍然存在以下问题:
简而言之,老鼠的视力很差,它没有办法看到远处的事物,但是我们为了日后业务系统的重复利用,就需要尽量避免鼠目寸光的重复开发。
所以,需要 将业务系统抽象为业务平台 ,支持通用的业务流程,让业务平台为日后的类似的业务系统提供灵活多变的基础业务实现方案,至于特殊的业务流程就单独开发一个特殊的业务系统,两者共同结合提供完整的服务。
另外,平台的使用者应该类似 SAAS ,具备为所有人服务的能力,提供给能让每个用户甚至每个组织都能创建属于自己的独有环境,可以通过在平台上的简单配置构建出属于个体的服务。
如图所示,业务系统与业务平台共同为用户服务。业务平台包含某个业务的通用流程,可能刚好能满足业务的所有需求,那么此时就不需要另外开发一个业务系统。但如果有一些比较特殊的业务流程或者必须单独创建一个业务方便管理控制的流程的话,那么可以将该业务系统与业务平台结合到一起使用,业务系统提供定制接口,业务平台提供通用接口,业务系统也能通过授权的调用接口来调用业务平台获取、修改数据。
首先我们需要想清楚,如何从平台的角度考虑,将设计业务逻辑才能比较通用?如何区分是否为通用的业务逻辑,从而进行业务拆分?
目的:解决业务实现的N种可能。在业务平台上尽量支持多的、通用的业务逻辑。
如何解决:把眼光放长远一些,我们这个业务系统现在需要支持哪些业务逻辑?日后需要支持哪些?然后进行有选择的取舍,不需要考虑太多,否则系统将被设计的特别复杂且用到的部分太少。一个简单有效的方法就是参照以前做过的系统和当前需要实现的系统,将通用的逻辑抽取出来。
举几个例子:
这里的边界指的是业务拆分时的边界,比如,哪些属于平台通用逻辑?就能把这些通用逻辑放到平台里。哪些属于业务特有逻辑?这些逻辑就不需要加到平台里。
比如,对于抽奖活动,配置奖品、分发奖品是 抽奖平台
通用逻辑,但用户排行榜则不够通用,除了游戏相关的场景,很少需要用到排行榜的功能,那么排行榜功能就应该属于业务特有逻辑。
在整个抽奖的业务流程中,还有一个业务流程是当抽奖次数用光,就可以通过分享的方式增加抽奖次数。所以抽奖业务通用逻辑依然可以继续拆分,对于分享功能,是不属于抽奖平台通用逻辑的,那么可以将分享功能也单独抽出来成为 分享平台
,使之也能服务于其他的平台或业务系统。
看似当前已经拆得比较清晰了,但还没有结束,因为这是仅仅针对于【分享成功->增加一次抽奖机会】这样的流程,如果需要分享多次才能增加一次机会呢?如果分享之后每次增加不同的抽奖机会呢?谁负责维护【分享-增加机会】这个奖励机制呢?这就需要一个引擎、流程控制中心来处理,不如就叫 任务调度平台
任务调度平台的核心业务流程是【完成任务-触发奖励】,至于是谁完成的任务,触发谁的奖励对它来说并不重要。只要它能够将任务的触发者与被触发者的对应关系、触发条件、被触发者的奖励接口调用方式维护在内部,当检测到触发者达到了触发条件,能够调用到对应的奖励即可
既然是平台,会因为使用者使用时长、数据量方面就会比一般的特有业务系统多,在设计时需要考虑到提前为书数据量较大的某些表进行 水平分表 设计,贴一个简单的分表的例子:
在创建数据库时按上图进行创建,在代码中进行增删改查时用下面的方法根据分表字段(shard key)来获取表名:
func GetTableNameByActivityId(activityId int64) string { if activityId > 0 { return "activity_prize_redeem_" + strconv.FormatInt(activityId % 16, 10) } return "activity_prize_redeem" }
分表时,根据哪个字段(shard key)进行分表也是需要考虑的,需要使数据能够均衡的分布在多张表中,并且不影响正常的查询,这样才能通过分表的方式将数据均匀分布到不同的表中,根据shard key进行查询时效率与不分表时一样,但如果使用另外的一个字段查询数据可能需要遍历所有的表才能将数据查询到,所以shard key的选择是与业务查询需求、数据均匀分布相关。
分表之后,最直接的影响是开发的时候需要对SQL语句进行动态调整,某些ORM框架不支持导致的开发效率降低,但是改动的代码不多,一劳永逸。
对于平台来说,并发访问量也可能较大,那么缓存、队列、ES必不可少。
对于缓存,现在基本上说的都是使用Redis,可以使用的集群模式有主从、哨兵、集群。使用的策略也有延迟加载、直写,还需要考虑到一些击穿、失效的缓存问题,具体可以看 这里
对于消息队列,在业务解耦、流量削峰方面是一个非常重要的中间件,具体可以看 这里
对于Elastic Search,如果业务上有全文检索的需求就是要结合EFK一起上的一个模块,具体使用方式、场景请自行查阅。
数据太重要了!分析用户行为,预测市场走向,还是以后设计系统的参考指标,我们作为技术开发人员,也需要为运营人员着想,需要统计出运营人员感兴趣的一些数据,最好是直接找他们提前询问清楚,哪些数据他们需要,以便我们在设计数据库的时候将一些关键数据用一些字段保存下来。
比如在抽奖活动中,运营人员需要知道web平台、安卓平台、IOS平台分别参与抽奖的人分别有多少,但是设计出来的数据库字段、代码中打印出的日志可能都不存在或者难以通过现有设计进行统计,那么就需要对这个统计需求进行单独的设计。
在代码中输出日志是必须的,比如通常需要在访问API、某个API里的关键逻辑、结合关键数据打印成功或失败信息。
另外,对于某些业务场景需要严格统计数据操作之前的情况、操作之后的情况、操作类型、操作人员、操作时间。虽然也可以通过输出日志的方式,但不够规范,查询统计难度大,容易丢失。所以需要单独设计出一张操作流水表,将重要信息持久化起来。
在每个需要统计的重要操作执行之后,使用消息队列或者另外的线程去插入一条操作记录到这张表中,如下
go service.Record(⊧.SysOperateRecord{ BizType: dao.BizType_Customer, OperType: dao.OperType_INSERT, OperContent: fmt.Sprintf("batch insert one new customer: %s", customer), Operator: userinfo.Id, CreateTime: currentTime, UpdateTime: currentTime, })
如何让用户有自己的独立环境?让他们可以在平台上简单配置之后创建自己的应用?
其实非常简单,在只考虑用户而不是租户的命名空间下,在系统层面和数据库设计层面多进行一层考虑即可,比如在数据库的主表/主实体上增加两个字段: namespace_id 、 app_id 。
在多个平台(抽奖、分享、任务平台)建立起之后,需要一个后台管理平台将这几个平台统一管理起来,方便为用户提供统一的配置。
以创建一个业务系统为例,如果使用管理平台进行配置,那么用户只需要在管理平台上填写不同平台的对应业务配置即可,在管理平台中将自动处理:
对配置好平台配置进行修改、删除,对业务数据进行统计的操作可通过管理平台的调整配置、统计数据接口进行
为什么说适合用微服务架构来开发平台?
业务如何决定架构?
这里给出另一个比较能体现业务决定架构思想的一篇实例文章参考
如果只考虑性能,那么不能选择微服务架构,因为单体应用在性能上是完全碾压微服务架构的。如果为了全局考虑之后还是得选择微服务,那么如何在使用微服务的情况下尽量提升访问的性能呢?
首先需要通过压测的方式测试出性能的瓶颈在哪里,这篇文章可能有所帮助。
至少需要保证能在性能问题发生之后能够立即解决,所以至少要做到服务能够在任意时刻能够版本回滚、能够动态扩展到更多机器上。然后通过对应的方式如优化代码、使用缓存、队列、添加服务器、改进中间件架构的方式去解决性能问题。
对一个架构师来讲,代码从提交到上线也需要考虑到,甚至需要考虑为团队构建DevOps体系。简单来说,使用自动化流水线将代码提交、测试、构建、部署自动化起来,并在项目上线的过程中协助开发测试运维进行代码版本的切换、部署方式的实践。
为了日后服务的蓝绿部署、回滚、动态伸缩,必须使用容器技术如Docker与容器编排平台如K8S来实现。至于具体的搭建方式、维护细节不用完全掌握,但一定要知道各种部署方式、服务维护方式和其利弊。
对于抽奖系统,因为奖品有实际价值,所以直接跟钱挂钩。为了防止恶意用户撸羊毛,必须对可能存在的抽奖后门进行封杀。
对于抽奖系统,最大的后门是:中奖接口。如何判断用户是真正的玩了这个游戏并一路闯关达到终点夺得奖励的呢?对于web平台来说真的是一个比较困难的问题,因为没办法跟游戏一样实时获得用户的数据进行详细的判定,所以只能在最大程度上增加中奖接口的校验规则。如下:
这是一些比较通用的web安全问题,一般在框架内部已经解决,但也需要确认是否开启相关安全机制。
等等等等,网站安全问题是在太多,没办法都写出来,不过以上问题比较常见,需要在开发时外加注意,这些虽然不会在架构设计图上展示出来,但是会是一个存在的架构隐患
我们从业务、数据、技术、安全方面综合考虑如何将简单的业务设计成为一个平台,看重的是长远的收益,提升的是自己的能力。作为开发人员的你也许已经烦透写业务代码,不妨换一种开发思想挑战一下自己吧。