小话灰度方案实现

在日常软件建设中,我们有时会遇到一个新旧逻辑、新旧组件灰度切流的过程。如何能够平滑的切流,相信会是每个开发者面临的问题。

好的,我们进入正题。

灰度切流的用例图很简单。

在这里插入图片描述
根据这个用例最直观的设计就是:

在这里插入图片描述
在一个gateway中包含一个Router,通过读取配置去选择究竟是实现A还是实现B。

使用的是策略模式最直接的解决问题。

但是现在Gateway的直接和Router的职责绑定到了一起,带来维护成本的提高,所以为了更加明确就变成了如下的设计:
在这里插入图片描述
Gateway包含了一个包含所有实现的Router,由Router进行根据配置进行调用。

这样的设计对于功能易用性已经OK。假如还需要一些结果合并逻辑怎么办?

从现在结构里,需要在Router里增加除了开关之后额外的合并逻辑。

从现在看,整个切流过程是没问题。不论是如何切流都是能够支持的。

在这种情况下,我们如何增加一个新的切流逻辑或者将清理旧逻辑或者旧组件?

或者我们说一下这种设计的缺点在哪里。

  1. 违反SRP原则。Router的功能不纯粹,除了切流还参与了业务逻辑,在切流完成后需要将部分逻辑移到实现中。
  2. 重复。有多少切流就需要多少的Router

好吧。那如果针对上述问题,可以有更好的设计吗?

首先我们可以将Router有关于业务部分的抽离出来, 将Router设计成为:

在这里插入图片描述
基于配置实现切流逻辑。

有了核心对象,我们就可以设计基于Spring拦截器去实现动态反射调用了。

在这里插入图片描述
基于这种方案,我们实现了基于注解配置的路由开关配置。在集成默认云配置的时候,通过Spel解析的方式实现,保留扩展自定义路由实现能力。

现在增加一个切流或者去掉切流,只需要将注解增加或者移除,不需要改动其他代码。

世界上肯定没有完美的东西,那这种方案缺点有没有呢?

答案是肯定的。

  1. 复杂度上升,在考虑的时候需要考虑可能带来的风险。
  2. 对性能会有影响。

基于这种方案,我们在生产系统上实现了一个路由组件,来灵活支撑我们的切流。这里也总结下遇到的坑

  1. 需要考虑拦截器的顺序,来保证其他已有注解的正常工作
  2. 对于批量接口,因为走多次拦截器,造成性能下降了10ms左右
  3. 路由组件各个过程中使用的外部调用结果多次使用,只能通过缓存解决
  4. 异常处理粗糙。对于反射调用异常InvocationTargetException直接wrap成了组件的异常,造成应用里的监控拦截器捕获异常失败。没有针对各种情况去设置异常类型,方便应用程序去处理。
  5. 将一些基础之外的能力变更可选,避免违反ISP原则
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值