JobHarvest——利用springAOP进行运行性能测评(更新中)

本文首先设计了一个简单的测时工具类进行函数耗时计算,然后利用spring AOP测试函数性能,最后分析了系统的耗时函数。

测试准备

测时方法1-工具类-代码入侵:

写了一个简单测试函数耗时的工具类(以后用spring aop代替)

public class ProfileUtils {

    private static Map<String, Long> tempTime = new HashMap<>();
    private static Map<String, Long> avgTime  = new TreeMap<>();

    public static void start(String tag) {
        tempTime.put(tag, System.nanoTime());
    }

    public static void end(String tag) {
        Long preTime = tempTime.get(tag);
        Long avgpre = avgTime.get(tag);
        if (preTime == null) return;
        long cuTime = System.nanoTime() - preTime;
        if (avgpre != null && avgpre != 0) {
            avgpre = (avgpre + cuTime) / 2;
        } else {
            avgpre = cuTime;
        }
        avgTime.put(tag, avgpre);
    }

    public static void print() {
        Set<String> keys = avgTime.keySet();
        for (String key : keys) {
            Long rs = avgTime.get(key);
            System.out.println(key + "-avg: " + rs / 1000000 + "ms");
        }
    }

}

缺点:使用比较麻烦,需要注意前后名称对应,且需要显示入侵代码。

解决方案:SpringAOP

性能评测方法2:spring AOP

spring文件配置中加入一行(基于注解的aop配置)如下:
    <aop:aspectj-autoproxy/>
配置aspect类与切入点:
/**
 * Created by caiqingliang on 2016/8/7.
 * 切面,计算函数耗时,按函数总耗时排序输出(总耗时、平均单次耗时、调用次数)
 */
@Component @Aspect public class TimeAdvice {

    private Map<String, MyProfile> map = new ConcurrentHashMap<>();

    @Around("execution(* com.leocai.bbscraw.crawlers.MyCrawler.nextPage(..))"
            + "||execution(* com.leocai.bbscraw.crawlers.MyCrawler.getCuCaoTarget(..))"
            + "||execution(* com.leocai.bbscraw.crawlers.MyCrawler.getInfoDTO(..))"
            + "||execution(* com.leocai.bbscraw.services.*.*(..))"
            //            + "||execution(* com.leocai.bbscraw.*.*(..))"
            //            + "||execution(* com.leocai.bbscraw.mappers.*.*(..))"
            + "") public Object logTime(ProceedingJoinPoint pointcut) throws Throwable {
        long pre = System.nanoTime();
        Object rs = pointcut.proceed();//此处注意要返回
        String sig = pointcut.getSignature().getName();
        long time = (System.nanoTime() - pre) / 1000000;
        MyProfile profile = map.get(sig);
        if (profile == null) {
            profile = new MyProfile();
            map.put(sig, profile);
        }
        profile.incr();
        profile.addTime(time);
        return rs;
    }

    /**
     * 输出的数据结构,包含总耗时、平均单次耗时、调用次数
     * 大小根据总耗时比较
     */
    public static class MyProfile implements Comparable {

        List<Long> times = new ArrayList<>();

        {
            times = Collections.synchronizedList(times);
        }

        AtomicLong count = new AtomicLong(0);

        public void incr() {
            count.incrementAndGet();
        }

        public void addTime(long time) {
            times.add(time);
        }

        public long getAvg() {
            long avg = 0;
            int count = 0;
            for (long t : times) {
                avg += t;
                count++;
            }
            avg /= count;
            return avg;
        }

        public long getTotalCost() {
            return getAvg() * count.get();
        }

        @Override public String toString() {
            return "total-cost " + getTotalCost() + "ms\tavg-cost " + getAvg() + " ms\tcalled " + count + " times";
        }

        @Override public int compareTo(Object o) {
            return (int) (((MyProfile) o).getTotalCost() - getTotalCost());
        }
    }

    @PreDestroy public void print() {
        map = MapUtil.sortByValue(map);
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key+"\t"+map.get(key));
        }
    }
}
优点很明显:只需要在注解中包含需要代理的函数即可
输出:
continueCraw	total-cost 7117ms	avg-cost 7117 ms	called 1 times
getInfoDTO	total-cost 742ms	avg-cost 53 ms	called 14 times
nextPage	total-cost 609ms	avg-cost 203 ms	called 3 times
produceJobInfo	total-cost 378ms	avg-cost 27 ms	called 14 times
getCuCaoTarget	total-cost 126ms	avg-cost 42 ms	called 3 times
getLatestDateBySource	total-cost 11ms	avg-cost 11 ms	called 1 times

性能分析:

现在对CrawlerWriter重要部分函数进行性能分析:

  1. crawSince:单个爬虫爬取总时间
  2. crawOnePage-avg:单个爬虫在爬取一页上的平均耗时(不包括获取网址)
  3. nextPage-avg:获取下一页的耗时

单线程执行:

NJUCSCrawler.crawSince-avg: 12310ms
NJUCSCrawler.crawOnePage-avg: 579ms
NJUCSCrawler.nextPage-avg: 221ms
 
NJUCrawler.crawSince-avg: 14272ms
NJUCrawler.crawOnePage-avg: 1000ms
NJUCrawler.nextPage-avg: 180ms
 
NOWCODERCrawler.crawSince-avg: 33186ms
NOWCODERCrawler.crawOnePage-avg: 2003ms
NOWCODERCrawler.nextPage-avg: 584ms
 
NYUCrawler.crawSince-avg: 27739ms
NYUCrawler.crawOnePage-avg: 1131ms
NYUCrawler.nextPage-avg: 871ms
 
SJUCrawler.crawSince-avg: 17627ms
SJUCrawler.crawOnePage-avg: 1146ms
SJUCrawler.nextPage-avg: 172ms
 
continueCraw-avg: 105215ms
init-avg: 49ms

五个线程执行:

NJUCSCrawler.crawSince-avg: 16404ms
NJUCSCrawler.crawOnePage-avg: 906ms
NJUCSCrawler.nextPage-avg: 193ms
 
NJUCrawler.crawSince-avg: 26351ms
NJUCrawler.crawOnePage-avg: 1221ms
NJUCrawler.nextPage-avg: 272ms
 
NOWCODERCrawler.crawSince-avg: 55302ms
NOWCODERCrawler.crawOnePage-avg: 2125ms
NOWCODERCrawler.nextPage-avg: 614ms
 
NYUCrawler.crawSince-avg: 43536ms
NYUCrawler.crawOnePage-avg: 1328ms
NYUCrawler.nextPage-avg: 980ms
 
SJUCrawler.crawSince-avg: 33862ms
SJUCrawler.crawOnePage-avg: 1168ms
SJUCrawler.nextPage-avg: 214ms
 
continueCraw-avg: 55321ms
init-avg: 4ms


问题分析:

  1. 可以看到单线程执行仅仅比5个线程执行多耗时1,问题可能在webdriver需要同步,cpu核心不够,mysql冲突等。
  2. 五个线程并发执行,最终耗时约等于最耗时间的一个爬虫,从时间分析中看出,爬取牛客网的耗时最高,这可以理解,牛客网一页信息量较大
  3. 爬取一页的耗时比较大,是下一页的1.5-5倍不等。
  4. 所以爬取一页需要优化,问题可能在写mysql,也可能在查找dom
  5. 优化重点在爬取单页的内容上

分析crawlerReader的性能

不用缓存的CrawlerReader性能

getFromCache-avg: 0ms
getJobInfos-avg: 98ms
getJobInfosMysql-avg: 98ms
init-avg: 3ms


使用缓存的CrawlerReader性能

getFromCache-avg: 109ms
getJobInfos-avg: 124ms
getJobInfosMysql-avg: 14ms
init-avg: 4ms

分析:

  1. 使用缓存效果不明显,甚至更差,
  2. 可能缓存使用不当,或是数据量太少
  3. mysql有查询缓存

发布了35 篇原创文章 · 获赞 61 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/cql342624757/article/details/52142784