背景
最近做的一个项目中,用到了目标驱动架构模式,但由于目标下发的不准确,导致出现了线上bug。
目标驱动
目标驱动是通过不同的轮询目标的状态,决策出需要达到的目标,使得状态能到达到最终的目标;
简单点的意思就是不断循环着四种状态:轮询—>决策—>发送目标—>达到目标。
目标驱动有什么好处的?
- 解耦
系统a可以专注数据的收集,系统b可以进行目标驱动,使得系统c最终可以达成目标
假如没有目标驱动,系统a即要数据的收集,数据的目标决策,数据的最终状态下发管理,通知系统c
- 减少工作量
- 系统b可以一次处理多份数据,产生一个最终目标下发给系统c
- 数据的目标决策过程可能是非常复杂的,数据的变更,依赖系统的变更等也可能导致需要下发的目标改变,这样目标驱动可以统一判断这些数据的变更和系统的依赖;如果不是目标驱动,是不是数据变更的时候需要下发目标,依赖系统变更的时候,也需要下发目标,导致链路分散
bug分析
项目中的代码逻辑demo如下:
private Mapper dataMapper;
public void poolStatus() throws Exception {
// 不断循环决策数据的目标
while(true) {
// 从数据库读取数据
List<Data> dataList = dataMapper.listAll();
// 决策需要下发的目标
List<Data> toSynDataList = dataList.stream()
.filter(d -> validate(d))
.collect(Collectors.toList());
// 下发最终目标
synDataToSys(toSynDataList);
Thread.sleep(1000L);
}
}
private boolean validate(Data data) {
try {
// 判断data是否有效,有可能结合第三方系统进行判断
return true;
} catch (Exception e) {
// 思考一下这里会有什么问题?
return false;
}
}
private void synDataToSys(List<Data> validataDataList) {
// 把有效的dataList同步到其他系统
}
从代码可以看出轮询、决策和下发目标的过程,那导致目标下发不正确的地方到底在哪里呢?
聪明的同学可以看到是在validate函数的思考那里了
原因是这样的
validata函数是对data进行决策的过程,但是validata是需要通过第三方系统等进行决策的
假如第三方系统抛出异常的时候,把异常catch住了,并且返回的是false
那就是说validata函数过滤掉了这data
便导致下发的目标没有data了
正确的处理
应该是异常catch的时候,log日志后,应该直接抛出异常
这样决策的过程便会停止,不会导致错误的目标进行下发
后续改进
- 配置下发应该用同步模式
目标驱动应该是应对比较复杂的目标决策与下发的,但项目中的使用到的目标驱动用于配置的下发,配置是一个很关键的设置,比如系统a设置了什么,就进行修改配置
- 决策出现异常应该停止
不能因为第三方系统的错误,而决策出错误的状态,这是一个很致命的操作
- 故障测试需要充分
如果决策是一个很复杂的过程,需要进行故障的测试,保证决策的状态正确