国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

海量日志中統(tǒng)計(jì)次數(shù)最多的100個(gè)IP

Cheng_Gang / 1344人閱讀

摘要:由于標(biāo)題長(zhǎng)度限制,原題是這樣某系統(tǒng)萬,每十分鐘統(tǒng)計(jì)一下請(qǐng)求次數(shù)最多的個(gè)。請(qǐng)求寫到日志的話,其實(shí)就是超大文件中統(tǒng)計(jì)問題。

由于標(biāo)題長(zhǎng)度限制,原題是這樣:某系統(tǒng)QPS100萬,每十分鐘統(tǒng)計(jì)一下請(qǐng)求次數(shù)最多的100個(gè)IP。ip請(qǐng)求寫到日志的話,其實(shí)就是超大文件中統(tǒng)計(jì)top k問題。10分鐘6億條記錄,大約是10G級(jí)別,所以對(duì)于一般單機(jī)處理來講不能一次性加載到內(nèi)存計(jì)算。所以分治算法是處理這類問題的基本思想。

思路

前面說了分治思想。那么具體如何分解問題呢。

思路就是把大文件分割成多個(gè)可以內(nèi)存處理的小文件,對(duì)每個(gè)小文件統(tǒng)計(jì)top k問題,最后再對(duì)所有統(tǒng)計(jì)結(jié)果合并得到最終的top k。

注意,這里的分割并不是隨意分割的,那樣最終結(jié)果顯然是不對(duì)的,必須保證相同的ip記錄都分割到同一個(gè)文件。那么hash算法最合適不過了,可以把相同的ip哈希到同一文件。

關(guān)于top k問題,效率高的解法是使用構(gòu)造最小堆或者借助快速排序的思想,復(fù)雜度為O(nlogk)。這里更適合用最小堆,具體來說,就是先利用前k個(gè)數(shù)據(jù)構(gòu)建一個(gè)固定大小k的最小堆,對(duì)之后的數(shù)據(jù),小于堆頂不做處理,大于則替換堆頂并調(diào)整。這樣,對(duì)每個(gè)文件順序處理完之后就得到最終結(jié)果,而不需要保留每個(gè)文件的top k再歸并。

實(shí)現(xiàn)

博主偷懶,借助TreeSet代替最小堆來維護(hù)top k數(shù)據(jù),TreeSet的話底層是借助紅黑樹排序,比最小堆復(fù)雜些,實(shí)際上對(duì)每個(gè)小文件用紅黑樹全排序再截取前k個(gè)。復(fù)雜度O(nlogm),這里m是每個(gè)小文件中的數(shù)量, m>>k。再有時(shí)間的話再用最小堆優(yōu)化一下,復(fù)雜度應(yīng)為O(nlogk)。

ps:已實(shí)現(xiàn)最小堆版本,見實(shí)現(xiàn)2,并做了對(duì)比實(shí)驗(yàn)

定時(shí)任務(wù)使用quartz實(shí)現(xiàn)。

下面是代碼。

IP類,封裝ip計(jì)數(shù),使用TreeSet存放須實(shí)現(xiàn)comparable接口。注意這里重寫compare方法不要return 0,否則會(huì)被TreeSet視為相同對(duì)象而放不進(jìn)去。這個(gè)可以看一下TreeSet的實(shí)現(xiàn),它實(shí)際上內(nèi)部還是一個(gè)TreeMap,只是把對(duì)象作為key,而value沒有使用。add添加元素時(shí),會(huì)調(diào)用TreeMap的put方法,put內(nèi)部又會(huì)調(diào)用compare方法,如果compare返回結(jié)果為0,只是重新setValue,對(duì)TreeSet相當(dāng)于什么也沒做。

package com.hellolvs;

import org.apache.commons.lang3.builder.ToStringBuilder;

/**
 * IP計(jì)數(shù)POJO
 *
 * @author lvs
 * @date 2017/12/08.
 */
public class IP implements Comparable {

    private String ip;
    private int count;

    public IP() {
    }

    public IP(String ip, int count) {
        this.ip = ip;
        this.count = count;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    @Override
    public int compareTo(IP o) {
        return o.count < this.count ? -1 : 1;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

IPCountJob類,定時(shí)統(tǒng)計(jì)日志文件中top k個(gè)ip。

注意其中的分割文件,這里的分割需要對(duì)文件邊讀邊寫,不能一次性讀入內(nèi)存再分割。guava io的readLines是直接裝入內(nèi)存的,所以不能用。可以使用java原生的io類,或使用commons io的LineIterator更優(yōu)雅一些。

package com.hellolvs;

import com.google.common.base.Charsets;
import com.google.common.base.Objects;
import com.google.common.base.StandardSystemProperty;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 定時(shí)Job,每十分鐘統(tǒng)計(jì)請(qǐng)求次數(shù)前k的ip
 *
 * @author lvs
 * @date 2017/12/08.
 */
public class IPCountJob implements Job {

    private static final Logger LOG = LoggerFactory.getLogger(IPCountJob.class);

    private static final String LINE_SEPARATOR = StandardSystemProperty.LINE_SEPARATOR.value();
    private static final Charset UTF_8 = Charsets.UTF_8;

    private static final String INPUT_PATH = "/home/lvs/logs/ip.log";
    private static final String OUTPUT_PATH = "/home/lvs/logs/split/";

    private static final int SPLIT_NUM = 1024;
    private static final int TOP_K = 100;

    /**
     * 利用TreeSet存儲(chǔ)請(qǐng)求次數(shù)前k的IP
     */
    private TreeSet resultSet = Sets.newTreeSet();

    /**
     * 分割文件用,保存每個(gè)文件的寫入流對(duì)象
     */
    private final Map bufferMap = Maps.newHashMapWithExpectedSize(SPLIT_NUM);

    /**
     * 定時(shí)任務(wù),每十分鐘統(tǒng)計(jì)請(qǐng)求次數(shù)前k的IP
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        // 捕獲異常,防止定時(shí)任務(wù)中斷
        try {
            execute();
        } catch (Exception e) {
            LOG.error("定時(shí)任務(wù)出錯(cuò):{}", e.getMessage(), e);
        }
    }

    /**
     * 統(tǒng)計(jì)大文件中請(qǐng)求次數(shù)前k的IP
     * 
     * @throws IOException I/O error
     */
    public void execute() throws IOException {
        // 這里應(yīng)該每10分鐘獲取當(dāng)前輪替日志文件路徑,此處用常量路徑模擬
        File ipLogFile = new File(INPUT_PATH);

        splitLog(ipLogFile, SPLIT_NUM);

        File logSplits = new File(OUTPUT_PATH);
        for (File logSplit : logSplits.listFiles()) {
            countTopK(logSplit, TOP_K);
        }

        LOG.info("結(jié)果集:{}", resultSet.size());
        for (IP ip : resultSet) {
            LOG.info("{}", ip);
        }
    }

    /**
     * 生成模擬日志文件
     * 
     * @param logNum 生成日志條數(shù)
     * @throws IOException I/O error
     */
    public static void generateLog(long logNum) throws IOException {

        /* 創(chuàng)建文件 */
        File log = new File(INPUT_PATH);
        File parentDir = log.getParentFile();
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        log.createNewFile();

        /* 生成隨機(jī)ip寫入文件 */
        SecureRandom random = new SecureRandom();
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(log))) {
            for (int i = 0; i < logNum; i++) {
                StringBuilder sb = new StringBuilder();
                sb.append("192.").append(random.nextInt(255)).append(".").append(random.nextInt(255)).append(".")
                        .append(random.nextInt(255)).append(LINE_SEPARATOR);
                bw.write(sb.toString());
            }
            bw.flush();
        }
    }

    /**
     * 分割日志文件
     *
     * @param logFile 待分割文件
     * @param fileNum 分割文件數(shù)量
     * @throws IOException I/O error
     */
    private void splitLog(File logFile, int fileNum) throws IOException {

        /* 為每個(gè)分割文件創(chuàng)建寫入流對(duì)象 */
        for (int i = 0; i < fileNum; i++) {
            File file = new File(OUTPUT_PATH + i);
            File parentDir = file.getParentFile();
            if (!parentDir.exists()) {
                parentDir.mkdirs();
            }
            bufferMap.put(i, new BufferedWriter(new FileWriter(file)));
        }

        /* 根據(jù)ip的hashcode將數(shù)據(jù)分割到不同文件中 */
        LineIterator it = null;
        try {
            it = FileUtils.lineIterator(logFile, "UTF-8");
            while (it.hasNext()) {
                String ip = it.nextLine();
                int hashCode = Objects.hashCode(ip);
                hashCode = hashCode < 0 ? -hashCode : hashCode;
                BufferedWriter writer = bufferMap.get(hashCode % fileNum);
                writer.write(ip + LINE_SEPARATOR);
            }
        } finally {
            /* 釋放資源 */
            LineIterator.closeQuietly(it);
            for (Map.Entry buffer : bufferMap.entrySet()) {
                BufferedWriter writer = buffer.getValue();
                writer.flush();
                writer.close();
            }
            bufferMap.clear();
        }
    }

    /**
     * 統(tǒng)計(jì)請(qǐng)求次數(shù)前k的IP
     *
     * @param logSplit 當(dāng)前分割文件
     * @param k top k
     * @throws IOException I/O error
     */
    private void countTopK(File logSplit, int k) throws IOException {

        /* 讀取文件對(duì)ip計(jì)數(shù) */
        HashMap ipCountMap = Files.readLines(logSplit, UTF_8,
                new LineProcessor>() {
                    private HashMap ipCountMap = Maps.newHashMap();

                    @Override
                    public boolean processLine(String line) throws IOException {
                        AtomicInteger ipCount = ipCountMap.get(line.trim());
                        if (ipCount != null) {
                            ipCount.getAndIncrement();
                        } else {
                            ipCountMap.put(line.trim(), new AtomicInteger(1));
                        }
                        return true;
                    }

                    @Override
                    public HashMap getResult() {
                        return ipCountMap;
                    }
                });

        /* 統(tǒng)計(jì)結(jié)果添加到TreeSet */
        for (Map.Entry entry : ipCountMap.entrySet()) {
            resultSet.add(new IP(entry.getKey(), entry.getValue().get()));
        }

        /* TreeSet只保留前k個(gè)ip */
        TreeSet temp = Sets.newTreeSet();
        int i = 0;
        for (IP o : resultSet) {
            temp.add(o);
            i++;
            if (i >= k) {
                break;
            }
        }
        resultSet = temp;
    }

    /**
     * 返回統(tǒng)計(jì)結(jié)果
     *
     * @return 結(jié)果集合
     */
    public TreeSet getResult() {
        return resultSet;
    }
}

Main,定時(shí)任務(wù)啟動(dòng)

package com.hellolvs;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 定時(shí)任務(wù)啟動(dòng)器
 * 
 * @author lvs
 * @date 2017/12/11.
 */
public class Main {
    public static void main(String[] args) throws Exception {
        // 生成模擬日志文件
        IPCountJob.generateLog(600000000);

        JobDetail job = JobBuilder.newJob(IPCountJob.class)
                .withIdentity("ipCountJob", "group1").build();

        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("ipCountTrigger", "group1")
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInMinutes(10).repeatForever())
                .build();

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        scheduler.start();
        scheduler.scheduleJob(job, trigger);
    }
}
實(shí)現(xiàn)2

IP類

package com.hellolvs;

import org.apache.commons.lang3.builder.ToStringBuilder;

/**
 * IP計(jì)數(shù)POJO
 *
 * @author lvs
 * @date 2017/12/08.
 */
public class IP implements Comparable {

    private String ip;
    private int count;

    public IP() {
    }

    public IP(String ip, int count) {
        this.ip = ip;
        this.count = count;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    @Override
    public int compareTo(IP o) {
        return Integer.compare(this.count, o.count);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

IPCountJob類,最小堆版本統(tǒng)計(jì)top k

package com.hellolvs;

import com.google.common.base.Charsets;
import com.google.common.base.Objects;
import com.google.common.base.StandardSystemProperty;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 定時(shí)Job,每十分鐘統(tǒng)計(jì)請(qǐng)求次數(shù)前k的ip
 *
 * @author lvs
 * @date 2017/12/08.
 */
public class IPCountJob implements Job {

    private static final Logger LOG = LoggerFactory.getLogger(IPCountJob.class);

    private static final String LINE_SEPARATOR = StandardSystemProperty.LINE_SEPARATOR.value();
    private static final Charset UTF_8 = Charsets.UTF_8;

    private static final String INPUT_PATH = "/home/lvs/logs/ip.log";
    private static final String OUTPUT_PATH = "/home/lvs/logs/split/";

    private static final int SPLIT_NUM = 1024;
    private static final int TOP_K = 100;

    /**
     * 利用最小堆結(jié)構(gòu)存儲(chǔ)請(qǐng)求次數(shù)前k的IP
     */
    private List result = Lists.newArrayListWithExpectedSize(TOP_K);

    /**
     * 分割文件用,保存每個(gè)文件的寫入流對(duì)象
     */
    private final Map bufferMap = Maps.newHashMapWithExpectedSize(SPLIT_NUM);

    /**
     * 定時(shí)任務(wù),每十分鐘統(tǒng)計(jì)請(qǐng)求次數(shù)前k的IP
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        // 捕獲異常,防止定時(shí)任務(wù)中斷
        try {
            execute();
        } catch (Exception e) {
            LOG.error("定時(shí)任務(wù)出錯(cuò):{}", e.getMessage(), e);
        }
    }

    /**
     * 統(tǒng)計(jì)大文件中請(qǐng)求次數(shù)前k的IP
     * 
     * @throws IOException I/O error
     */
    public void execute() throws IOException {
        // 這里應(yīng)該每10分鐘獲取當(dāng)前輪替日志文件路徑,此處用常量路徑模擬
        File ipLogFile = new File(INPUT_PATH);

        splitLog(ipLogFile, SPLIT_NUM);
        File logSplits = new File(OUTPUT_PATH);
        for (File logSplit : logSplits.listFiles()) {
            countTopK(logSplit, TOP_K);
        }

        MinHeap.sort(result);
        LOG.info("結(jié)果集:{}", result.size());
        for (int i = result.size() - 1; i >= 0; i--) {
            LOG.info("{}", result.get(i));
        }
    }

    /**
     * 生成模擬日志文件
     * 
     * @param logNum 生成日志條數(shù)
     * @throws IOException I/O error
     */
    public static void generateLog(long logNum) throws IOException {

        /* 創(chuàng)建文件 */
        File log = new File(INPUT_PATH);
        File parentDir = log.getParentFile();
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        log.createNewFile();

        /* 生成隨機(jī)ip寫入文件 */
        SecureRandom random = new SecureRandom();
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(log))) {
            for (int i = 0; i < logNum; i++) {
                StringBuilder sb = new StringBuilder();
                sb.append("192.").append(random.nextInt(255)).append(".").append(random.nextInt(255)).append(".")
                        .append(random.nextInt(255)).append(LINE_SEPARATOR);
                bw.write(sb.toString());
            }
            bw.flush();
        }
    }

    /**
     * 分割日志文件
     *
     * @param logFile 待分割文件
     * @param fileNum 分割文件數(shù)量
     * @throws IOException I/O error
     */
    private void splitLog(File logFile, int fileNum) throws IOException {

        /* 為每個(gè)分割文件創(chuàng)建寫入流對(duì)象 */
        for (int i = 0; i < fileNum; i++) {
            File file = new File(OUTPUT_PATH + i);
            File parentDir = file.getParentFile();
            if (!parentDir.exists()) {
                parentDir.mkdirs();
            }
            bufferMap.put(i, new BufferedWriter(new FileWriter(file)));
        }

        /* 根據(jù)ip的hashcode將數(shù)據(jù)分割到不同文件中 */
        LineIterator it = null;
        try {
            it = FileUtils.lineIterator(logFile, "UTF-8");
            while (it.hasNext()) {
                String ip = it.nextLine();
                int hashCode = Objects.hashCode(ip);
                hashCode = hashCode < 0 ? -hashCode : hashCode;
                BufferedWriter writer = bufferMap.get(hashCode % fileNum);
                writer.write(ip + LINE_SEPARATOR);
            }
        } finally {
            /* 釋放資源 */
            LineIterator.closeQuietly(it);
            for (Map.Entry buffer : bufferMap.entrySet()) {
                BufferedWriter writer = buffer.getValue();
                writer.flush();
                writer.close();
            }
            bufferMap.clear();
        }
    }

    /**
     * 統(tǒng)計(jì)請(qǐng)求次數(shù)前k的IP
     *
     * @param logSplit 當(dāng)前分割文件
     * @param k top k
     * @throws IOException I/O error
     */
    private void countTopK(File logSplit, int k) throws IOException {

        /* 讀取文件對(duì)ip計(jì)數(shù) */
        HashMap ipCountMap = Files.readLines(logSplit, UTF_8,
                new LineProcessor>() {
                    private HashMap ipCountMap = Maps.newHashMap();

                    @Override
                    public boolean processLine(String line) throws IOException {
                        AtomicInteger ipCount = ipCountMap.get(line.trim());
                        if (ipCount != null) {
                            ipCount.getAndIncrement();
                        } else {
                            ipCountMap.put(line.trim(), new AtomicInteger(1));
                        }
                        return true;
                    }

                    @Override
                    public HashMap getResult() {
                        return ipCountMap;
                    }
                });

        /* 前k條數(shù)據(jù)用來構(gòu)建初始最小堆,之后的數(shù)據(jù)比堆頂大則替換堆頂并調(diào)堆 */
        for (Map.Entry entry : ipCountMap.entrySet()) {
            IP ip = new IP(entry.getKey(), entry.getValue().get());
            if (result.size() != k) {
                result.add(ip);
                if (result.size() == k) {
                    MinHeap.initMinHeap(result);
                }
            } else {
                if (ip.compareTo(result.get(0)) > 0) {
                    result.set(0, ip);
                    MinHeap.adjust(result, 0, k);
                }
            }
        }
    }

    /**
     * 返回統(tǒng)計(jì)結(jié)果
     *
     * @return 結(jié)果集合
     */
    public List getResult() {
        return result;
    }
}

MinHeap類,最小堆工具

package com.hellolvs;

import java.util.List;

/**
 * 最小堆
 *
 * @author lvs
 * @date 2017-12-12
 */
public class MinHeap {

    /**
     * 對(duì)最小堆排序
     * 
     * @param list 已經(jīng)為最小堆結(jié)構(gòu)的列表
     * @param  元素須實(shí)現(xiàn)Comparable接口
     */
    public static > void sort(List list) {
        for (int i = list.size() - 1; i > 0; i--) {
            swap(list, 0, i);
            adjust(list, 0, i);
        }
    }

    /**
     * 初始化最小堆
     *
     * @param list 待初始化為最小堆的列表
     * @param  元素須實(shí)現(xiàn)Comparable接口
     */
    public static > void initMinHeap(List list) {
        /* 從最后一個(gè)非葉節(jié)點(diǎn)開始至根節(jié)點(diǎn)依次調(diào)整 */
        for (int i = list.size() / 2 - 1; i >= 0; i--) {
            adjust(list, i, list.size());
        }
    }

    /**
     * 調(diào)堆
     *
     * @param list 當(dāng)前堆
     * @param  元素須實(shí)現(xiàn)Comparable接口
     * @param cur 待調(diào)整位置
     * @param length 當(dāng)前堆大小
     */
    public static > void adjust(List list, int cur, int length) {
        T tmp = list.get(cur);
        for (int i = 2 * cur + 1; i < length; i = 2 * i + 1) {
            if (i + 1 < length && list.get(i).compareTo(list.get(i + 1)) > 0) {
                i++; // i指向孩子節(jié)點(diǎn)中最小的節(jié)點(diǎn)
            }
            if (tmp.compareTo(list.get(i)) > 0) {
                list.set(cur, list.get(i)); // 最小孩子節(jié)點(diǎn)調(diào)整到其父節(jié)點(diǎn)
                cur = i; // 當(dāng)前節(jié)點(diǎn)置為最小孩子節(jié)點(diǎn),繼續(xù)調(diào)整
            } else {
                break; // 沒有調(diào)整時(shí)退出循環(huán)
            }
        }
        list.set(cur, tmp); // 被調(diào)整節(jié)點(diǎn)最終存放位置
    }

    /**
     * 交換List中的元素
     * 
     * @param list 待交換列表
     * @param i 第一個(gè)元素位置
     * @param j 第二個(gè)元素位置
     */
    private static > void swap(List list, int i, int j) {
        T tmp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, tmp);
    }
}

Main類,無改動(dòng)

package com.hellolvs;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 定時(shí)任務(wù)啟動(dòng)器
 * 
 * @author lvs
 * @date 2017/12/11.
 */
public class Main {
    public static void main(String[] args) throws Exception {
        // 生成模擬日志文件
        IPCountJob.generateLog(600000000);

        JobDetail job = JobBuilder.newJob(IPCountJob.class)
                .withIdentity("ipCountJob", "group1").build();

        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("ipCountTrigger", "group1")
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInMinutes(10).repeatForever())
                .build();

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        scheduler.start();
        scheduler.scheduleJob(job, trigger);
    }
}

附一下pom文件:



    4.0.0

    com.hellolvs
    ipCount
    1.0.0
    jar

    
        20.0
        3.1
        2.4
        2.6
        2.1.7
        1.7.5
        1.0.13
        4.10
        1.8
        UTF-8
    

    
        
            
            
                com.google.guava
                guava
                ${guava.version}
            

            
            
                org.apache.commons
                commons-lang3
                ${commons-lang3.version}
            

            
            
                commons-io
                commons-io
                ${commons-io.version}
            

            
            
                joda-time
                joda-time
                ${joda-time.version}
            

            
            
                org.quartz-scheduler
                quartz
                ${org.quartz-scheduler.version}
            

            
            
                org.slf4j
                slf4j-api
                ${org.slf4j.version}
            

            
            
                ch.qos.logback
                logback-classic
                ${logback.version}
                runtime
            
            
                ch.qos.logback
                logback-core
                ${logback.version}
                runtime
            

            
            
                junit
                junit-dep
                ${junit.version}
                test
            
        
    

    
        
        
            com.google.guava
            guava
        

        
        
            org.apache.commons
            commons-lang3
        

        
        
            commons-io
            commons-io
        

        
        
            joda-time
            joda-time
        

        
        
            org.quartz-scheduler
            quartz
        

        
        
            org.slf4j
            slf4j-api
        

        
        
            ch.qos.logback
            logback-classic
        
        
            ch.qos.logback
            logback-core
        

        
        
            junit
            junit-dep
        
    

    
        ROOT
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    ${java.version}
                    ${java.version}
                    ${project.build.sourceEncoding}
                
            
        
    

對(duì)比實(shí)驗(yàn)

生成了6億條數(shù)據(jù)的日志。

TreeSet版本:
生成6億條日志時(shí)間:521582
分割文件時(shí)間:173219
分割后統(tǒng)計(jì)top k時(shí)間:195037
定時(shí)任務(wù)執(zhí)行時(shí)間:368294

注:定時(shí)任務(wù)執(zhí)行時(shí)間指的是對(duì)大文件的總統(tǒng)計(jì)時(shí)間,主要是分割文件+分割后統(tǒng)計(jì)top k。

cpu和堆使用情況:

可以看到堆變化明顯分為三階段:對(duì)應(yīng)了生成日志、分割日志、分割后統(tǒng)計(jì)top k。

最小堆版本:
生成6億條日志時(shí)間:513840
分割文件時(shí)間:148861
分割后統(tǒng)計(jì)top k時(shí)間:190966
定時(shí)任務(wù)執(zhí)行時(shí)間:339870

cpu和堆使用情況:

總結(jié):

生成日志和分割文件是沒有改動(dòng)的,運(yùn)行時(shí)間不一樣,可能有一定誤差。

倒是兩個(gè)版本統(tǒng)計(jì)top k時(shí)間沒有明顯的變化,按上面分析O(nlogm)和O(nlogk)應(yīng)該有比較明顯的差距才對(duì),這里n=600000000,m約600000,k=100,各位可以幫忙分析一下效率差距不大的原因。

不過可以看到堆內(nèi)存使用明顯降低了約100MB,因?yàn)門reeSet需要添加m個(gè)元素再截取k個(gè),而MinHeap只需要添加k個(gè)元素。

個(gè)人博客:www.hellolvs.com

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70785.html

相關(guān)文章

  • shell在手分析服務(wù)器日志不愁?

    摘要:自己的小網(wǎng)站跑在阿里云的上面偶爾也去分析分析自己網(wǎng)站服務(wù)器日志看看網(wǎng)站的訪問量。然后統(tǒng)計(jì)最終返回的數(shù)字就是當(dāng)前所有端口的已建立連接的總數(shù)。 自己的小網(wǎng)站跑在阿里云的ECS上面,偶爾也去分析分析自己網(wǎng)站服務(wù)器日志,看看網(wǎng)站的訪問量。看看有沒有黑闊搞破壞!于是收集,整理一些服務(wù)器日志分析命令,大家可以試試! 1、查看有多少個(gè)IP訪問: awk {print $1} log_file|sor...

    fyber 評(píng)論0 收藏0
  • 2017雙11技術(shù)揭秘—雙十一海量數(shù)據(jù)下EagleEye的使命和挑戰(zhàn)

    摘要:今年的無論是常態(tài)全鏈路壓測(cè)或者是雙十一當(dāng)天,面臨的主要問題是如何保障自身系統(tǒng)在海量數(shù)據(jù)沖擊下的穩(wěn)定性,以及如何更快的展現(xiàn)各個(gè)系統(tǒng)的狀態(tài)及更好的幫助開發(fā)同學(xué)發(fā)現(xiàn)及定位問題。在整個(gè)雙十一備戰(zhàn)過程中,遇到并解決了很多疑難雜癥。 摘要: EagleEye作為阿里集團(tuán)老牌的鏈路跟蹤系統(tǒng),其自身業(yè)務(wù)雖不在交易鏈路上,但卻監(jiān)控著全集團(tuán)的鏈路狀態(tài),特別是在中間件的遠(yuǎn)程調(diào)用上,覆蓋了集團(tuán)絕大部分的場(chǎng)景,...

    ssshooter 評(píng)論0 收藏0
  • Linux運(yùn)維小命令

    摘要:自己的小網(wǎng)站跑在阿里云的上面偶爾也去分析分析自己網(wǎng)站服務(wù)器日志看看網(wǎng)站的訪問量。表示能夠處理個(gè)并發(fā)請(qǐng)求,這個(gè)值可根據(jù)負(fù)載情況自動(dòng)調(diào)整。最終返回的數(shù)字就是當(dāng)前所有端口的請(qǐng)求總數(shù)。 自己的小網(wǎng)站跑在阿里云的ECS上面,偶爾也去分析分析自己網(wǎng)站服務(wù)器日志,看看網(wǎng)站的訪問量。看看有沒有黑闊搞破壞!于是收集,整理一些服務(wù)器日志分析命令,大家可以試試! 1、查看有多少個(gè)IP訪問: awk {pr...

    Invoker 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<