zoukankan      html  css  js  c++  java
  • 业务拆分的思考

    从最初的单体应用,即将进行业务拆分,分而治之,虽心不免有些激动,但是很快就陷入深思。

    因为我不得不考虑如何拆分比较好及其现在要不要拆分的问题。

    目前我们开发的是一个多租户系统应用,考虑到公共通用功能,例如用户功能、组织功能、菜单功能、模块功能、系统监控、审批功能、权限管理等,我们将其作为公共模块,而像共享方面的系统或者是智能门锁方面的系统,我们决定将其抽象另外的模块,当特定的用户需要该功能时,只需与我方沟通签订对应的合作协议,我方后台超级管理员只需配置下相应的权限即可。

    一、先谈谈是否要拆分的问题

    孙子曰:“不尽知用兵之害者,则不能尽知用兵之利“。

    还是回到之前的那个问题,业务是否真正需要拆分呢?这里要结合具体的业务需求。

    比如,目前我对这个多租户系统有这么样一个想法,如果要拆分,按照上述的原则公共模块进行抽取,抽取为一个后台web应用。

    而像共享方面(例如共享汽车等)和智能门锁可单独作为另外的一个应用。之所以这么做的原因在于处于如下考虑:

    (1)解耦性和可维护性

    如果所有的系统都要放入一个庞大的war下,那么代码耦合度可能会比较高,而且不易维护,就好比git分支开发,之所以强调每个人在自己的分支下开发对应的功能模块,是因为避免全部都在主分支开发时,导致出现的代码混乱和冲突问题。另外还有一个考虑是,通常主分支,也就是master分支,一般情况下,主分支的代码是不存在问题的,或者问题非常小,但是由于都在主分支上进行开发,导致有的时候,因为没有严格的代码审核机制,导致有些开发人员,比如曾经的我,仅仅只是为了完成任务而开发,写程序时,很少思考不考虑到是否会不会影响到其他同事的代码,最后的结果是,陷入的一个死循环,改bug,改bug....

    之所以强调可维护性,是因为,对于这个多租户而言,后台模块单独作为一个应用,由部分人负责,而像智能门锁或者是共享汽车等应用是另外一个模块,也由专门的开发人员负责,这样一来,你打你的我打我的,总的原则,坚持一个,“高内聚,低耦合,代码可读性良好,可扩展性良好”。

    当然了,实际情况也不能你打你的,我打我的,各自为战,该及时沟通还是得及时沟通,对于项目组长而言就需要时刻了解自己的组员工作进度及其代码方面的情况,因为这样一来当项目经理问起时,也不必胆战心惊。

    作为项目经理,处于整个项目的领路人,项目的成败,很大程度不仅仅是由底层的开发人员所决定,还有就是项目经理的决策和管理。

    (2)稳定性

    有这么一句话,“鸡蛋不能同时放在一个笼子下”。

    后台应用,一般情况下仅仅只是管理人员使用,或者是管理员通过权限分配指定某一些人使用。这样一来,基本上,不用考虑高并发。

    而像智能门锁这样的,不得不考虑高并发和性能方面的问题,如果全部将其放在一个war下,一个出问题,全部出问题,将会导致宕机,影响项目的正常服务,容错性差。

    这样看来,业务拆分,也是为了提高稳定性。

    二、谈谈业务拆分的思路

    (1)梳理所有的业务功能环节

    主要以粗分为主,例如智能门锁系统的智能门锁、智能网关等等这样的。

    (2)业务功能细分

    例如智能门锁系统中的智能门锁,它不仅包含门锁列表展示、安装门锁、门锁详情信息、门锁授权人、一次性密码和系统密码等,还包括如何开锁等等。

    (3)梳理业务主体,进行分门别类划分

    这里主要强调的是将业务分类,类似开发中的紧急并非常重要、紧急但不重要这样的开发优先级。

    (4)将金字塔结构图结合业务泳道图通过关键指标来识别关键业务功能

    也许这句话不是特别好理解,比较官方,不过当我说完后,你一定会非常明白。

    其实整个项目就是一个金字塔结构

    从顶层到下层,自顶向下,如图(画的有点丑,大家凑合着看吧)

     根据这幅图可归纳为如下四点:

    a. 将所有的通过用业务逻辑组成公共服务,比如配置服务,调度服务,缓存服务等;

    b.如果有一个业务主体,得到了各方面的关注,那么就把这个业务首先拆分出来独立成一个模块;

    c.长流程业务就符合业务主体特殊一条标准,可以提取为一个独立的服务;

    d. 分渠道,比如将接口调用的逻辑和界面方式的逻辑解耦成两个服务,比如后台和接口,使得两个变成独立的管道互不影响;

    (6)重构
    拆分的过程也意味着对代码进行重构。

    a.首先拆除所有的公共服务(校验服务,规则服务,开通服务,归档服务),然后再拆分特殊业务主体服务(重点业务,长流程业务),最后拆不同驱动实现方式(接口服务和界面服务);

    b.因为业务量特别大,系统采用消息队列的方式进行处理,通过接骨法接触代码之间的耦合,并提供对外服务的接口;

    c. 比如创建订单的环节,设计所有的业务主体,影响大,所以这个服务不能一下子全拆出来,要通过修路法,先建设一个订单服务和原来的系统并行使用,同时分流出几个试点业务到订单服务。当上下游调用没有问题,可以正常创建订单后,再通过分批逃跑法,逐步地将其他业务的处理迁移到这个微服务上面,最终当所有的业务都迁移成功之后,原来的系统的订单处理逻辑就废弃了;

    d.业务的拆分过程中,数据库拆分的工作也同时进行(主从和读写分离);

    三、分布式拆分

    提到分布式,普及下什么是分布式系统,这里我引用图片:

    引用百度百科:

    分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。内聚性是指每一个数据库分布节点高度自治,有本地的数据库管理系统。透明性是指每一个数据库分布节点对用户的应用来说都是透明的,看不出是本地还是远程。在分布式数据库系统中,用户感觉不到数据是分布的,即用户不须知道关系是否分割、有无副本、数据存于哪个站点以及事务在哪个站点上执行等。

    关于分布式拆分,我主要围绕三个方面讲,需求,原则,方法等三个方面。

    (1)需求

    a.组织结构变化

    从最初的一个团队逐渐成长并拆分为几个团队,团队按照业务线不同进行划分,为了减少各个业务系统和代码间的关联和耦合,几个团队不再可能共同向一个代码库中提交代码,必须对原有系统进行拆分,以减少团队间的干扰。

    b.安全

    这里所指的安全不是系统级别的安全,而是指代码或成果的安全,尤其是对于很多具有核心算法的系统,为了代码不被泄露,需要对相关系统进行模块化拆分,隔离核心功能,保护知识产权。

    c.替换性

    有些产品为了提供差异化的服务,需要产品具有可定制功能,根据用户的选择自由组合为一个完整的系统,比如一些模块,免费用户使用的功能与收费用户使用的功能肯定是不一样的,这就需要这些模块具有替换性,判断是免费用户还是收费用户使用不同的模块组装,这也需要对系统进行模块化拆分。

    d.交互速度

    单体程序最大的问题在于系统错综复杂,牵一发而动全身,也许一个小的改动就造成很多功能没办法正常工作,极大的降低了软件的交付速度,因为每次改动都需要大量的回归测试确保每个模块都能正确工作,因为我们不清楚改动会影响到什么,所以需要做大量重复工作,增加了测试成本。这时候就需要对系统进行拆分,理清各个功能间的关系并解耦。

    e.技术需求

    单体程序由于技术栈固定,尤其的是比较庞大的系统,不能很方便的进行技术升级,或者说对引入新技术或框架等处于封闭状态;每种语言都有自己的特点,单体程序没有办法享受到其它语言带来的便利;对应到团队中,团队技术相对比较单一。

    相比于基于业务的垂直拆分,基于技术的横向拆分也很重要,使用数据访问层可以很好的隐藏对数据库的直接访问、减少数据库连接数、增加数据使用效率等;横向拆分可以极大的提高各个层级模块的重用性。

    f.业务需求

    由于业务上的某些特殊要求,比如对某个功能或模块的高可用性、高性能、可伸缩性等的要求,虽然也可以将单体整体部署到分布式环境中实现高可用、高性能等,但是从系统维护的角度来考虑,每次改动都要重新部署所有节点,显然会增加很多潜在的风险和不确定定性因素,所以有时候不得不选择将那些有特殊要求的功能从系统中抽取出来,独立部署和扩展。

    (2)原则

    a.业务优先

    每个系统天然都会按业务功能分成多个模块,每个模块又包含许多业务相关的功能,在系统拆分时,我们就可以优先考虑按照业务边界进行切割,切割完成后再针对每个模块进行拆解,循序渐进,逐渐迭代深入,最终完成系统的拆解。这个过程类似庖丁解牛,要找到关节之处下刀,方能事半功倍。

    b.循环渐进

    系统拆分过程中包含两个非常重要的工作:拆分和测试。二者缺一不可,并且二者是并行进行的,一定要边拆分边测试。每一步拆分完成都要保证系统功能是完整的,保证系统的测试是完整的。拆分要小步前进,如此以来可以减少累计错误的发生。这一点在《重构》这本书中也讲到了。

    c.兼顾技术

    系统不能为了分布式而分布式,系统拆分的代价相当昂贵;当然如果有拆分的需要,我们也不能白白浪费这么好的学习机会:

    可靠测试:“重构之前,首先检查自己是否有一套可靠的测试机制”,这是MartinFowler在《重构》这本书中说到的,它同样对系统拆分有效。拆分是在对系统进行大手术,每一次的改动都要保证系统保持原来的行为不变。测试使得我有足够的信心进行下一步的拆分或重构,不至于在错误的道路上越走越远,以至于错误累积。测试与拆分如影随形,每一步都要有足够的测试。没有测试的拆分和重构我真的不敢想象结果会是什么样子。

    关于测试的重要性可以参考我的这篇文章:论单元测试之重要性

    之前我强调过,测试由底层的单元到高层的UI,其中单元是最有利于发现问题解决问题的。

    (3)方法

    a.公共模块复用;

    b.增加代理,解耦;

    小结:

    本文主要讲三个大方面,第一个是业务拆分是否有必要拆分;第二个是业务拆分的思路;最后一个是分布式业务拆分。

    本文的重点在于第一个和第二个,因为这两个我深有体会,试验过,应用过。至于分布式的话,此次主要普及下相关的知识和给有这方面需求的人启发。

    本文主要参考如下两篇文章:

    业务系统拆分的基本思路:https://blog.csdn.net/u011402896/article/details/80506394

    分布式拆分:https://blog.csdn.net/zzz34k/article/details/52576731

    当然了,也加上了我自己的理解和想法。

    希望能给广大的IT友友们带来有益的收获。

  • 相关阅读:
    Spring Boot (20) 拦截器
    Spring Boot (19) servlet、filter、listener
    Spring Boot (18) @Async异步
    Spring Boot (17) 发送邮件
    Spring Boot (16) logback和access日志
    Spring Boot (15) pom.xml设置
    Spring Boot (14) 数据源配置原理
    Spring Boot (13) druid监控
    Spring boot (12) tomcat jdbc连接池
    Spring Boot (11) mybatis 关联映射
  • 原文地址:https://www.cnblogs.com/youcong/p/9688300.html
Copyright © 2011-2022 走看看