BlackChen'site

生产环境性能调优

最近进行了一次代码审查及性能调优.

大对象拷贝问题

  • 现象
    • 对象拷贝或赋值经常使⽤ BeanUtil.copyProperties() ⽅法进⾏对象间属性的拷贝,赋值. 但是没有关注⽅法中是如何实现的,在⽇志中发现⼤对象拷贝会出现明显的时间跳跃现象.⼤对象间拷贝耗时太多
  • 解决方案
    • 使⽤ cglib 重写 BeanUtil.copyProperties(),实现快速对象拷贝
public class CachedBeanCopier {  
  
    static final Map<String, BeanCopier> BEAN_COPIERS = new HashMap<String, BeanCopier>();  
  
    public static void copy(Object srcObj, Object destObj) {  
        String key = genKey(srcObj.getClass(), destObj.getClass());  
        BeanCopier copier = null;  
        if (!BEAN_COPIERS.containsKey(key)) {  
            copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false);  
            BEAN_COPIERS.put(key, copier);  
        } else {  
            copier = BEAN_COPIERS.get(key);  
        }  
        copier.copy(srcObj, destObj, null);  
    }  
  
    private static String genKey(Class<?> srcClazz, Class<?> destClazz) {  
        return srcClazz.getName() + destClazz.getName();  
    }  
}  

代码重复调⽤问题

  • 现象
    • 获取⽤户信息时,每次都去执⾏同样的⽅法 userSessionUtil.getUserInfo(), 同⼀个业务流程中,多次调⽤. 每次调⽤,都会进⾏⼀次根据sessionID通过Redis获取user对象的操作. 属于重复调⽤. 针对下单接口,该⽅法的重复调⽤多达5,6次.
  • 解决方案
    • controller⼊口处调⽤⼀次 userSessionUtil.getUserInfo() 获取到⽤户信息,之后逻辑需要该数据时,将⽤户信息作为参数传递过去。
    • 服务内部有⼀个拦截器也获取了⼀次⽤户信息,通过thradlocal,结合拦截器,保证每个接⼜中获取⽤户信息时只与其它系统交互⼀次。

JSON序列化问题

  • 现象
    • ⽇志输出时,经常使⽤ logger.info("xxxxx,{}",GSON.toJsonStr(Obejct)) 类似代码进⾏⽇志打印输出.遇到⼤对象时, json序列化,反序列化 会对系统性能有⼀定影响。
  • 解决方案
    • 重写 JAVA toString() ⽅法代替 JSON 进⾏⽇志打印, 同时减少⼤对象的⽇志打印

重复⽇志

  • 现象
    • 以请求参数打印为例,已经有controller的⼊口处对请求参数的打印,service层还是进⾏了⼀次打印。属于重复打印.

Tomcat连接池线程数量 & MySQL连接池线程数

  • 现象
    • 进行服务压测的时候, Cpu使用率一直没有达到一个顶峰, 因应用属于IO密集型, 大量时间在进行等待网络IO或磁盘IO.
  • 解决方案
    • 增大Tomcat最大连接数量.增大MySQL连接最大数量.

评论