关于服务分层的意见收集

我先起个头,说一下我的想法。
服务分为4层,并将部分中间件服务划为第一层,从底层向上层如下:
第一层*中间件服务:可以被任何服务调用的服务,为了和以下两种服务区分,可称其为中间件组件
第二层*底层独立微服务:不需要调用别的微服务的服务(但可调用中间件服务),例如财务微服务、基础数据微服务
第三层*业务微服务:从业务角度划分出来的微服务,可调用上面两种服务,但不可调用业务微服务
第四层*组合业务微服务:为抽象重复聚合业务微服务而形成的第二级的业务微服务,是对于业务微服务的包装,可调用上面三种服务(同样不可调用组合业务微服务)

《关于服务分层的意见收集》有21个想法

  1. 我这边觉得微服务应该分2层:

    1、应用服务 ==》 面向业务的服务 (学生提交作业服务,老师批改作业服务)

    2、基础服务 ==》 面向共享主题的服务 (作业服务,积分服务,商品服务,订单中心服务)

  2. 公共微服服务,可以被所有微服务所调用。当然业务场景不同也可以建多个公共微服务,有需则用。
    业务微服务,只给web调用,不能微服务调用。不同业务只能调用该业务的微服务。

  3. 微服务架构就是由一组微服务组成的架构模式。每个微服务都是一个可独立部署的完整系统。一组微服务组成微服务层(注意这里的服务层不同于monolithic架构中的服务层,那个是单系统中的功能模块分层)。微服务层上面一般是应用层,应用层通过组合使用微服务层的各个微服务而向外提供接口(比如HTTP API接口)。各个微服务可以通过RPC接口供应用层调用,比如利用Thrift、Avro。

  4. 服务层级多了,可能增加服务依赖,上层服务可以调用下层的所有服务,服务间跨级调用是否会造成混乱

    1. 只要大体调用方向是固定的,我觉得就是健康的调用关系。例如小循环、大循环依赖不能有。然后为了方便管理以及调用清晰,我们还需要一个可视的视图,静态甚至是实时的

  5. 我理解的微服务体系,应该是分为三层:
    1. 业务服务
    2.共享服务
    3.系统服务
    系统服务实现对底层系统功能的封装,给上面的各个业务使用,比如短信服务/邮件服务/存储服务等。
    共享服务是如积分服务/订单服务/支付服务等。
    业务服务是业务的聚合服务。

  6. 从现状看,当前项目中存在的是:中间件服务、底层独立微服务、业务微服务。

    目前是Controller层的service充当“组合业务微服务”,组合调用其他业务微服务。如果存在“组合业务微服务”,那么controller层是否直接调用“组合业务微服务”?

    1. 赞,这个说到点上了,就是说我的文章里提到的最上层最接近controller的微服务,其实它的定义和范围界定是最困难的,这点甚至是目前没有的出来这一层的原因所在。先收集完大家的意见,然后我们可以一起就这个点讨论一下

  7. dobbo 服务分为两层 dao、service 这个service有可能是普通的spring bean 也有可能是dubbo服务,web层聚合各种dobbo的服务。我感觉无论是写中间件的同学、或者是写业务服务的同学,只需要提供透明的dubbo服务即可。这样会带来一些问题就是,有部分的业务逻辑还是需要在WEB层实现,这就会引入另外两个层 manager、controller层。
    WEB(controller<-manager)<-DUBBO(service <-dao).

  8. 我的理解:

    Controller	
    --> 组合业务微服务
    	--> 业务微服务
    		--> 中间件服务
    		--> 底层独立微服务
    			--> 中间件服务
    	--> 中间件服务
    	--> 底层独立微服务
    		--> 中间件服务
    --> 业务微服务
    --> 底层独立微服务
    --> 中间件服务
    

    这样做,使用上会非常灵活,但问题在于,若使用不当,就如王奕明评论的:
    服务层级多了,可能增加服务依赖,上层服务可以调用下层的所有服务,服务间跨级调用是否会造成混乱。

  9. 赞同
    第一层*中间件服务
    第二层*底层独立微服务
    第三层*业务微服务
    第四层*组合业务微服务

    1.微服务分层原因:业务线多 微服务多,制定为规范可以使各微服务间“健康调用”(老系统各服务间调用无规范 乱调用 导致维护成本极高)。
    2.“一个服务包含所有功能”与“多个微服务各自完成独立的功能”区别。
    前者,缺点:单个项目代码量大,维护成本高;优点:事务处理 一个@Transaction注解全搞定。
    后者,缺点:保证数据一致性是痛点!(需要使用分布式事务或MQ保证最终一致性);优点:各微服务各司其职,业务逻辑清晰,维护成本低。
    我们当然选择后者(可控性更大)。
    3.巧用“套娃”试写法,处理分布式事务(强一致性)。
    eg:
    @Transaction//微服务1
    public void service1(){
    try{
    myMethod1();//1.写本服务内的业务数据
    baseService.writeBaseData();//2.调用底层微服务
    }catch(Exception e){
    logger.error(e.getMessage());//打日志
    throw new RuntimeException(“***”);//手动抛异常回滚
    }
    }
    ————————————————————
    @Transaction//微服务2
    public void service2(){
    try{
    myMethod2();//1.写本服务内的业务数据
    微服务1.service1();//2.调用微服务1的service1方法
    }catch(Exception e){
    logger.error(e.getMessage());//打日志
    throw new RuntimeException(“***”);//手动抛异常回滚
    }
    }
    ————————————————————

    以此类类推,微服务n 调用微服务n-1,n-1 调用 n-2 …. 2调用1。
    调用其他微服务的代码,写在本服务写DB代码最后面,嵌套在最底层的service有异常,会逐层向上抛出,每层的@Transaction都会回滚本服务写入DB的数据。
    “套娃”限制:只能两方协调,不能三方或更多。3想调用2和1,那么需要将2和1的分布式事务整合到一起,然后3再调用这个整合好的服务。“套娃”层数越多,问题越难跟踪,老系统account-service等服务中使用了这种写法,但没有规范,乱嵌套,最终导致同一个表的写操作,在多个服务中都有实现。

    总结:
    (1)“中间件服务”作为工具类服务,可以被任何服务调用。
    (2)“业务微服务”在调用“底层独立服务”时,推荐数据强一致性,可以参考“套娃”写法,方便开发。但多于2方服务参与时,仍应使用传统写法(catch到异常 调用回滚接口)。
    (3)“组合业务微服务”调用“业务微服务”时,多方服务协同工作,推荐使用MQ,保证数据最终一致性。

    1. 赞,从事务相关的和数据一致性方面参考已遇到的问题作出了详细的评论。期待再拔高到一定高度来看待此架构问题,事务相关的问题是服务分层必须要面对的,但还有其他的问题,需要我们一并来面对和整体考虑。

    2. 套娃写法并没有做到所谓的“强一致性”,你说的只是理想状态:微服务报异常,本服务抓住异常并往外抛运行时异常,就能回滚。
      有两种情况不可避免,我拿套娃法1来举例,理解不对的地方多担待:
      情况1:myMethod1();本地方法执行成功
      baseService.writeBaseData();调用底层微服务也成功。
      但在这时候,service1所在服务down机。那myMethod1()对库表的操作会由数据库回滚。而baseService.writeBaseData()并不会回滚。数据不一致!
      情况2:myMethod1();本地方法执行成功
      baseService.writeBaseData();调用底层微服务也成功。
      但在这时候,baseService所在服务断网了。对于service1来说就是方法超时,数据回滚。但baseService.writeBaseData()对库表的操作并不会回滚。数据不一致!

      总结:涉及跨服务间的调用,只要不做分布式事务,如2pc 3pc等,就做不到真正的强一致性。

发表评论

电子邮件地址不会被公开。 必填项已用*标注