技术是为业务服务的。
好的架构从来都不是一蹴而就的,而是根据实际情况一步步演化而来的。
以上两个观点我是比较认同的,所以正文前两篇先分别介绍下现有的项目背景和技术背景。
本篇内容主要介绍项目背景,我唯一想说清楚的是:为什么我们要将项目改造成微服务架构。
由于现公司主要面向特定的垂直领域,受众面比较小。为了让大家更易于理解,讲述时我特地换成了前公司所服务的行业:“物业行业”。项目背景和业务逻辑都十分相似,感觉正合适。
缘起
公司的产品是一款面向物业行业的ERP(为方便讲述下称“物业系统”),他能满足物业公司日常事务管理,如:财务收费、房产业主信息管理、设备资产管理、客服服务管理,人事管理、协同办公等等。
随着业务发展,为了提升广大业主的满意度,决定推出“幸福家园APP”(由我们公司开发,物业公司运营)。这个app主要面向于小区业主,可以维护家庭成员信息、生成访客二维码、在线缴费、投诉报修等。远期规划,业主还能app里购物,物业公司送货上门。
对,听上去万事俱备,只差一个程序员。 我就是那个程序员。
了解了该项目之后,我觉得用例图可能会是这样:
当然作为程序员,我们需要分析出重要的隐藏需求,所以补充几点:
家庭成员信息变更后需要同步到物业系统的业主管理模块中业主可以到物业公司前台缴物业费,也可以app上在线缴费,这两种形式数据要能相通业主在app里投诉和报修,会推送到物业系统中;如果业主直接电话投诉,物业人员受理登记,业主也能在app中查看处理进度
分析决策
背景已经介绍清楚了,接下来的问题是怎么做?架构怎么搭?(以下讨论都仅限于后台,不包括app前端)
方案一
按照以前的惯性,第一个想法就是将“幸福家园APP”的功能直接做到原有的“物业系统”中,将业主帐号也加到原有的用户表中,增加user_type标识,来标记该帐号时物业服务人员还是业主。能用的接口直接用,不能用的新增一个。这种方式行得通吗?答案是肯定的,但细思极恐。
1、首先,可以预想到的是,代码里大量充斥着这样的逻辑:
if(user.getUserType().equals("物业服务人员")){//do something}else{//do other something}
这样写下去,感觉就是个“焦油坑”
2、“物业系统”目前采用的单服务、单库的架构。压力已经很大,在现有系统里堆功能随时有可能会崩掉。以后的趋势是将“物业系统”按模块拆成多服务,多库。
3、物业系统相对成熟稳定,而“幸福家园APP”这个项目则刚起步,更新迭代会较快。如果做到一起,频繁的升级势必会影响到物业系统。不能因为“幸福家园”改了点小东西,而需要升级这个系统。
方案二
将“幸福家园”后台和“物业系统”后台完全独立。把他们看作是两套完全独立的系统。好处是第一种方案提到三个问题都可以避免掉。但也会带来一些问题,比如:
1、完全独立架构,这意味着很多基础功能需要重写,增加工作量(当然有些公共库可以独立出来直接引用)。
2、通过上面的分析可知,两个系统虽然可独立,但关联十分密切。需要交互的地方,“物业系统”可以提供开放接口供“幸福家园APP”后台调用,反之也成立。这样“幸福家园”需要知道“物业系统”的部署在什么地方,两个系统之前的认证也是需要我们考虑的地方,甚至还需要考虑两个系统间访问超时,崩溃不可用的情况。这些问题都会带来工作量,并且和业务逻辑关系不大。
方案三
采用微服务架构。这也是我们最终采用的方案。原先的“物业系统”作为一个微服务,“幸福家园”后台也作为一个微服务,他们两个微服务共同组成了一个大系统。当然原先的“物业系统”也过于庞大,下一步也打算慢慢的按模块打散成多个微服务(这是后话,本次先确保幸福家园APP能顺利推出)。采用微服务架构,有如下好处:
1、各服务间能保持相对独立,开发、升级、数据库等都各自为政。避免了方案一中的各种问题。
2、方案二中的需要处理的问题,spring cloud都已经提供了,开发是可更聚焦于业务。
3、考虑这样一种交互场景,“幸福家园”业主注册时,填写房产信息,业主需要选择什么小区,几幢几单元等,这些数据由“物业系统”提供。用一张图看下方案二和方案三的区别:
可以看出采用方案三更加简单直接,效率更高。这样的场景在整个系统上还是蛮多的。
4、技术积累。用新的技术/框架去解决新问题,这也给技术人员提供了学习锻炼的机会,解决技术人员的技术焦虑。这其实也是采用方案三很大的一个原因。
总结
啰嗦了这么多,我想讲明白的是为什么我们要采用微服务架构,我们遇到的实际情况是怎样的?我们是如何分析的?分析时主要考虑哪些因素?这对架构老手来说并不难,对新手来说却很值得考虑。