对原有代码进行升级改造或者组件替换时,一个基本原则是新老逻辑要一致。保证新旧逻辑最常用的手段肯定是线上流量验证最为稳妥,相同的入参,走完原组件逻辑之后,再走一遍新组件的逻辑,比较输出是否一致。但是实际情况中会遇到一种情况,要被替换的组件中包含一些外部依赖,例如需要从Redis中查询一些数据,从第三方介质获取一些信息等,这样可能由于两次查询的结果不一致导致最终新老组件对比的结果存在差异。针对这种情况,一种非常好的解决手段就是将当前请求依赖的外部数据通过缓存存起来,以保证新组件查询的数据和旧组件查询的数据一致。示例代码如下:
/**
* 组件替换模板
* @param <T>
*/
public abstract class PluginReplaceTemplate<T> {
public abstract T queryBusiData();
/** 组件替换Guava队列 */
private GuavaCache<T> pluginReplaceGuava;
public PluginReplaceTemplate() { }
public PluginReplaceTemplate(GuavaCache<T> pluginReplaceGuava) {
this.pluginReplaceGuava = pluginReplaceGuava;
}
/**
* @param guavaKey guava缓存Key
* @param newPluginFlag true代表新组件调用,false代表老组件调用
* @param isHitCompare 是否命中对比阶段
* @return 数据
*/
public T query(String guavaKey, boolean newPluginFlag, boolean isHitCompare){
if (newPluginFlag){
// 新组件:对比阶段查guava,对比结束后不再使用guava
if (isHitCompare){
return pluginReplaceGuava.get(guavaKey);
}else {
return queryBusiData();
}
} else {
// 老组件:始终不使用guava数据,对比阶段需要写guava
T data = queryBusiData();
if (isHitCompare){
try {
pluginReplaceGuava.put(guavaKey, data);
} catch (Exception e) {
LogUtils.error(LogUtils.FILE_EXCEPTION, "PluginReplaceTemplate.put Data to Guava Exception", e);
}
}
return data;
}
}
}