我们说了组件的功能性分析,我们说一下组件的非功能性需求,以及如何设计实现非功能性需求
非功能性需求
对于灰度发布组件,我们通过易用性,扩展性,灵活性,性能,容错性几个方面,来分析其的非功能性需求
易用性
我们提到在设计框架的时候,最好做到低侵入,松耦合的设计思路,框架需要集成到业务系统中使用,所以更加低侵入更好,业务代码松耦合,替换起来更加容易,接口的限流和幂等跟具体的业务是无关的,所以限流和幂等的逻辑,可以直接使用AOP来实现
但是,灰度是需要针对业务来做的,跟业务有强相关,需要跟业务代码完全解耦,是根本不现实的,于是,只能做到一定的妥协,容忍一定程度的侵入
除此外,在灰度的过程中,不停的修改灰度的规则,在测试没出现问题的情况下,逐渐放量,对于运维,每次都需要重启系统来修改规则是不合适的,所以最好能有灰度规则的热更新
也就是说,我们在配置文件中,修改了灰度规则之后,系统可以在不重启的情况下自动加载,更新灰度规则
扩展性,灵活性
最好支持多种格式的配置方式(诸如 JSON,YAML,XML),和多种方式的配置,比如本地配置文件,Zookeeper,配置中心
除此外,之前的说法中,支持三种灰度规则的语法格式,具体值 893,区间值 100-200, 比例值 30%
但是,这都是比较简单的灰度规则,对于更加复杂的灰度规则,比如对于30天内购买了某个商品并且没有退货的用户进行灰度,现在的灰度的规则语法就不能解析如此复杂的了,所以,如何支持更加灵活的规则,是重点和难点
性能
性能方面,对于灰度组件的处理难度,并不像是限流框架那么高,在限流框架中,对分布式限流模式,接口请求访问计数存储在中心存储器,比如Reids,而Reids本身具有一定的读写延迟,从而影响到了接口的响应时间
对于恢复组件,灰度的判断逻辑非常简单,而且不涉及外部存储,一般在配置文件中,所以查找性能不会太慢,但是仍需要我们能够快速的判定某个灰度的对象能够在规定的范围时间内判定成功
容错性
需要我们进行高度的容错,不能因为框架本身的异常,导致接口响应的异常,从业务的上面说,能容忍限流框架的短暂失效,不能影响到实际业务代码的执行
对于幂等框架,不能允许框架的短时间的失效,因为这种失效会导致业务可能多次被执行,发生业务上的数据错误,所以是fail-fast机制,让业务代码终止,从而业务执行失败
对于灰度组件,上面两种对于异常的处理思路都是可以的,在灰度组件出现异常的时候,既可以中止业务,也可以继续执行,但是更倾向于直接fail-fast,在出现异常的时候直接终止掉业务的执行
框架设计思路
根据刚刚给出的几个需求分析和对比,在性能和容错性的方面,灰度的组件并没有什么要特殊处理的地方,重点是更加复杂的灰度规则和热更新
如何支持更加灵活,复杂的灰度规则
灰度配置是和业务强相关的,业务方根据灰度的业务特点,找到灰度的对象,然后按照灰度的语法,配置对应的灰度规则
但是对于复杂的灰度规则,比如30天内购买过某商品且没有退款的用户,来定义语法规则来实现,是很难的,所以给出了两种的解决方案
一种是规则引擎,比如Drools,配置文件中调用Java代码,可以配置文件中直接调用Java的代码,另一种是支持编程和灰度规则,灵活性更加的高,不过缺点是更新灰度规则需要更新代码,重新部署
对于大部分的业务的灰度,我们使用前面定义的最基本的语法规则,,对于极个别的复杂的语法规则,我们使用暴露接口来实现
实现框架的热更新
简单点,我们可以进行创建一个定时器,每隔一定时间,从配置文件,读取灰度规则配置信息,并且更新规则,但是不能因为更新了规则,就暂停了灰度服务,所以,要做到一定量的并发工作
本章重点
我们对比了限流框架,幂等框架等的非功能性的需求,对易用性,扩展性,灵活性,性能,容错,进行了比对和解释
在易用性,讲解了低侵入,松耦合的设计思路,限流,幂等等和业务无关,导致可以和业务的完全解耦,但是,对于灰度业务的强相关性,导致耦合比较紧密,比较难以低侵入
在扩展性方面,我们希望能够支持多种格式,多种存储方式的配合,而且最好能够支持复杂的灰度规则,对于大部分的业务灰度,使用最基本的规则可以实现,对于比较复杂的灰度,通过接口暴露给业务方编程实现
对于性能,灰度组件没有啥特殊处理,但是只希望能够快速的判定某个灰度对象
对于容错性,限流框架需要高度容错,框架错误不影响,对于幂等框架,不能允许幂等功能的失效,出现了异常,那么业务也会失败,对于灰度组件的异常处理,我倾向于幂等框架的处理思路
课后思考
使用Logger的框架,在业务代码中打印日志,是不是对业务代码的侵入,耦合?
从耦合的角度来看,是在业务代码之中打印的,这是和业务代码耦合在了一起,但是和业务无关,需要删去的时候,不需要修改业务代码,只移除非业务代码,我的角度来看,是不属于对于业务代码的侵入耦合的