软件设计不是CRUD(24):系统耦合性变化对性能的影响以及优化措施

本节内容,我们试图以一个示例场景进行切入,为读者讲解基于业务抽象的设计思想进行的解耦设计时,为什么会对系统的既有性能产生影响,这些对性能的影响又可以通过哪些常规手段进行补偿。
我们先来看一下这样一个示例场景:系统中有两个组织机构类型信息,这两种组织机构类型除了编码、中文名、上级机构等关键数据一致以外,其它业务字段都不一样并且两种组织机构类型对应的业务行为业务也不一样。

在没有进行业务抽象设计时,项目团队为了节约设计成本(或其它客观因素),在业务层采用诸如“if……else……”的编码方式在一套控制逻辑中嵌入两种不同的业务逻辑,而在数据层直接采用“一张表”存储两种不同组织机构的各种数据——就是技术人员常说的“写死”方式。
以上的设计方式首先来说设计门槛较低,只要有1、2年工作经验的开发人员就可以自行设计;其次,这种设计方式虽然没有考虑解耦的问题,但如果系统本身就没有组织机构的扩展需求和维护需求,那么这种设计是最节约研发成本的做法;最后,这种设计思路由于没有考虑降低耦合性的问题,所以也不会因此对模块性能产生影响。

但如果采用了基于业务抽象的设计思路进行组织机构模块的解耦设计,那么首先从业务层来说,组织机构中的控制逻辑和具体业务逻辑会进行分离,模块中至少会有一套固定的控制逻辑(可能会更多),以及两套各自为不同组织机构类型服务的具体业务逻辑;另外从数据层来说,也不会采用“一张数据表”来存储两种不同类型的组织机构的特定业务信息,最多有一张所谓的“公共表”,对各种不同类型组织机构的类型、中文名、编码等同质性信息进行存储。如下图所示:

在这里插入图片描述
以上两种组织机构功能模块的设计方式可以进行这样的概括。后一种设计思路是通过模型抽象和行为抽象的方式建立业务抽象性,以降低组织机构模块的耦合性,还保证了将来可以扩展出第三种或更多种不同的组织机构类型;前一种设计思路是将两种组织机构类型“写死”,这种设计思路没有太多进行详细描述的意义,“写死”可以理解为“把需求翻译成代码”。

显然“写死”设计方式更简单,也不会因为耦合性原因产生任何性能浪费。本文暂不讨论第一种设计是否科学,但第二种设计方式在进行控制逻辑和业务逻辑分离后,会造成了一定性能损失是一个客观事实。这些性能损失主要集中在几个方面:

  • 多数据表的写入查询消耗问题

由于进行了解耦的设计方式,两种不同的组织机构的各种特异性信息(甚至所有信息)不可能存储在同一张数据表中。如果项目新扩展第三种类型的组织机构信息,那么第三种类型的组织机构信息的特异性信息(也可能所有信息)也不可能存储在原有的数据表中,甚至可能不在一种类型的数据库中。
那么一些查询场景中,需要进行多种不同组织机构信息的合并查询(例如各种业务报表),技术人员可能会在SQL层面采用“合表”命令/语法对各种特异性业务数据进行整合。这显然会增加相当的工作量,并且大多数关系型数据库中“合表”命令的性能都不会很高,甚至不推荐使用。这种性能损耗和工作损耗就是由于业务隔离所带来的。

当然,正式环境下处理这样的查询场景一般会采用诸如视图引擎这样的查询工具完成工作,不推荐使用以上示例中所描述的“合表”操作(后文会进行讨论)。

  • 多个具体业务逻辑的调用消耗问题

由于进行了解耦的设计方式,固定的控制逻辑在调用各个具体的业务逻辑一般会过来、判定各个具体的业务逻辑是否匹配本次处理,如下图所示:

在这里插入图片描述

具体的过滤和匹配逻辑往往是由具体的业务逻辑来完成,整个判定顺序是由控制逻辑进行把控。这样势必会造成一定的性能消耗,原因是具体的业务逻辑判定过程需要一定的资源进行执行。

1、耦合度与系统性能的关系

从以上的示例读者可以知道一下几个显而易见的信息:

  • 较高耦合度对提升系统的性能下限有一定帮助

性能下限是指,系统在没有高并发、高可用、高稳定(即系统的“三高”性)要求时,在不需要进行任何性能优化调整的情况下,系统所具备的通常性能指标。例如,某款系统在不进行任何性能优化时,同时100人在线运行合同管理功能,系统也不会出现明显的CPU负载,I/O队列也不会明显变长。

较高的耦合性意味着多个应该隔离的功能模块,将为做一个不可分割的整体对外提供服务能力。那么,这个整体就可以进行合并本应分离的多个调用为一个调用、共享业务层逻辑、共享数据层存储方案等等整合操作。这些技术细节的优势,都有利于节约系统性能开销,从而直接提高系统性能的下限。

  • 较高耦合度会对提升系统的性能上限造成困扰

性能上限是指,系统在具有高并发、高可用、高稳定的运行要求时,在进行了一系列性能调优操作后,系统所具备的性能指标。系统的高并发、高可用、高稳定性就是我们常说的系统的“三高”。

通常情况下,我们都认为系统耦合性高低和系统的“三高”性没有直接影响,只和系统的可维护性(既是系统的可扩展性和可修复性)有直接关系。但是没有可维护性或者可维护性较弱的系统,在进行扩展和修复的过程中将成倍积累技术债务,且这些债务将耗费更多时间才能进行补偿。最终造成的后果就是,无论技术人员怎样应用性能优化手段,系统可做的性能提升都非常有限,甚至没有任何性能变化。

一句话概括就是:由于设计人员不考虑系统耦合性问题,那么自然也不会考虑到较高的耦合性会在日后系统扩展、修复过程中积累更多技术债务的问题,从而间接影响到系统的性能上限。

  • 较低耦合度会对系统的可维护性起到明显的正向作用,会对压制技术债务起到决定性作用,但是会带来一定的性能损耗。

上文已经讲到系统的可维护性包括系统的可扩展性和可修复性,至于较低耦合度是如何对可扩展项和可修复性起到正向支撑作用的,是本系列前几篇文章的重点内容,这里就不再赘述。这里需要重点说明的是,明确进行降低系统耦合性的设计考虑,会对系统性能下限造成负面影响的,本节开篇处的示例就是一个很好的说明。

但好消息是,一方面这种负面影响是可控的、可补偿的。另一方面,这些负面影响是针对性能下限而言的,而对于系统的性能上限来说一旦补偿措施得当,系统的性能上限是可以明显提升的。下面我们就来详细讨论一下这些性能补偿方式,这些性能补偿方式在绝大多数情况下都是适用的。

2、补偿解耦带来的多余性能消耗

在开始具体介绍前,需要和读者进行一些同步说明:

  • 以下这些优化方式,如果读者要像本文一样使用Java语言进行落地,那么读者需要对Java语言中的线程、线程池、异步技术和Java常用工具包有一定了解。

  • 以下这些优化方式的具体落地,虽然都是基于Java语言的知识体系,但这些优化方式的底层逻辑,无论读者使用哪种编程语言都是适用的。

2.1、使用数据缓存

使用缓存技术能有效降低功能模块在“三高”场景下的执行压力,提高功能模块的响应效率。集成数据缓存的思路主要是:对模块执行过程中得到的中间结果或最终结果,在一个较短暂的时间内进行暂存。当同样的操作参数被传入后,模块的控制逻辑或业务逻辑将直接为调用者返回之前暂存的运行结果,而不会再执行计算过程。

相比在业务逻辑中暂存数据,在控制逻辑中暂存数据的方式更被本文推荐,做这样的推荐主要有以下几个考虑要素:

  • 将数据缓存的管理算作控制逻辑的一部分,也就是把功能模块性能兜底的职责交给控制逻辑、交给功能模块的第一设计者,也就是保证了无论如何实现具体的业务逻辑,业务逻辑执行后的数据都可以被缓存(至于需不需要是另一个方面的讨论)。

  • 将数据缓存的管理交给控制逻辑,可以管控由于需要集成数据缓存所带来的设计难度,保证了对具体业务逻辑实现的较低门槛——不只是对技术要求的较低门槛,也是对业务实现的较低门槛。

  • 将数据缓存的管理交给控制逻辑,将使控制逻辑对于缓存的管理有更多的灵活性。例如,控制逻辑可以根据实际情况设计业务接口,将是否使用缓存、缓存Key的精度控制、缓存有效时间等关键配置信息暴露给具体的业务逻辑进行设置,从而在不改变设计难度的基础上,满足不同业务逻辑对使用数据缓存的不同要求。

在以JAVA语言为基础的应用程序设计中,目前最有代表性的缓存组件是Google Guava。实际上Guava是一组来自Google的核心 JAVA库,包括一组好用的集合类型(如 Multimap 和 Multiset)、不可变集合、图形库以及用于并发组件、I/O组件、散列组件和字符串组件等。缓存功能只是Guava的其中一个组件,但架不住真好用。这里我们给出一个使用示例:

<!-- 首先导入依赖 -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1.0-jre</version>
</dependency>

这是Google Guava 缓存组件的一个使用示例

// 这是Google Guava 缓存组件的一个使用示例
public class GuavaCachingExample {
   
  // 创建缓存对象
  private static final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
    // 设置缓存项的过期时间
    .expireAfterWrite(10, TimeUnit.MINUTES)
    // 设置缓存的最大容量,超过后会根据LRU算法来移除缓存项
    .maximumSize(1000)
    // 构建缓存
    .build(new CacheLoader<String, String>() {
   
        // 定义如何加载数据到缓存
        @Override
        public String 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说好不能打脸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值