代码上生产后,发现严重的效率问题,查询总是超时,优化效率
原先代码
private void translateAllField(JSONObject item, Object record) {
//边界处理
//递归结束条件
//递归
// 遍历所有字段 取出字典code值,放到map中
Field[] allFields = oConvertUtils.getAllFields(record);
for(Field field:allFields){
if(field.getAnnotation(QueryBaseDict.class)!=null) {
String value = item.getString(field.getName());
//如果内嵌对象
if(field.getAnnotation(QueryBaseDict.class).isTranslation() && !StringUtils.isEmpty(value)) {
Class aClass = field.getAnnotation(QueryBaseDict.class).isClass();
if(value.charAt(0) == '[') {
ArrayList<Object> objects = new ArrayList<>();
List<JSONObject> jsonObjects = JSONObject.parseArray(value, JSONObject.class);
for(JSONObject stringJson:jsonObjects) {
translateAllField(stringJson,stringJson.toJavaObject(aClass));
objects.add(stringJson);
}
item.put(field.getName(),jsonObjects);
} else {
JSONObject jsonObject = JSONObject.parseObject(value);
translateAllField(jsonObject,jsonObject.toJavaObject(aClass));
item.put(field.getName(),jsonObject);
}
} else {
String textValue = translateDictvalue(value);
item.put(field.getName()+"Text",textValue);
}
}
}
}
private String translateDictvalue(String value) {
return commonAPI.getDictName(value);
}
这里一个递归算法,翻译切面翻译字典项码值,这段代码在内网环境执行尚可,但是到了生产环境查询效率就极其缓慢,甚至超时。
其中
String textValue = translateDictvalue(value);
item.put(field.getName()+"Text",textValue);
这段是feign调用用户中心,获得码值表翻译内容,并以属性+text ,增加字段翻译。
可以看出,首先这个是对每个需要翻译的字典项都feign调用,这里表单比较长,需要翻译字段很多,所以做了很多feign调用,而且没有从redis取值
优化:1 首先将字典值放入redis中,查询的时候先查询redis,查不到再在feign调用,从mysql中查找
String textValue;
String keyString = String.format("sys:cache:basedict::"+value);
if (redisTemplate.hasKey(keyString)){
textValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
}else {
textValue = translateDictvalue(value);
}
item.put(field.getName()+"Text",textValue);
baseDictHashMap.put(value,textValue);
优化完能查询出数据,大概快了2,3倍,但是仍然很慢。需要2s左右
2.因为字典项的值不会很多,所有可以设置有个公共静态map,将查询出的字典值放入map中,即jvm缓存中,这样map中存在的数据就不用从redis中查询,少做了IO查询。
public static ConcurrentHashMap<String, String> baseDictHashMap = new ConcurrentHashMap<>();
...
String textValue;
String keyString = String.format("sys:cache:basedict::"+value);
if(baseDictHashMap.get(value)!=null) {
textValue = baseDictHashMap.get(value);
item.put(field.getName()+"Text",textValue);
} else {
if (redisTemplate.hasKey(keyString)){
textValue = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
}else {
textValue = translateDictvalue(value);
}
item.put(field.getName()+"Text",textValue);
baseDictHashMap.put(value,textValue);
}
这次优化完,大概查询效率为1s左右,又提升了2倍。
3.最后我们应用云服务器是部署在北京,而mysql 和 redis等中间件服务器是部署在杭州,考虑不在一个地域,可能会有影响,所以销毁了北京的应用服务器,重新在杭州买了云服务器作为应用服务,同时提升了上传效率5m为20m,效率瞬间降到了200ms,看了下同在一个地域的云服务器走的是内网服务,而不再一个地域走的是公网,应该是很大影响。
最后其实还有个地方可以优化,就是在翻译字典时,可以将需要翻译的字段值一次性放入map集合中,feign调用或者查redis时,一次性查询来,便可以减少多次io调用