package resa.optimize; import backtype.storm.generated.StormTopology; import backtype.storm.scheduler.ExecutorDetails; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import resa.metrics.MeasuredData; import resa.metrics.MetricNames; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * Created by ding on 14-3-4. * Note: * Recv-Queue arrival count includes ack for each message * When calculate sum and average, need to adjust (sum - #message, average - 1) for accurate value. */ public class AggResultCalculator { private static final Logger LOG = LoggerFactory.getLogger(AggResultCalculator.class); protected Iterable<MeasuredData> dataStream; private StormTopology rawTopo; private final Map<Integer, AggResult> task2Result = new HashMap<>(); private final Map<String, AggResult[]> results = new HashMap<>(); private final Set<Integer> firstTasks; public AggResultCalculator(Iterable<MeasuredData> dataStream, Map<String, List<ExecutorDetails>> comp2Executors, StormTopology rawTopo) { this.dataStream = dataStream; this.rawTopo = rawTopo; comp2Executors.forEach((comp, exeList) -> { AggResult[] result; if (rawTopo.get_spouts().containsKey(comp)) { result = new SpoutAggResult[exeList.size()]; for (int i = 0; i < result.length; i++) { result[i] = createTaskIndex(new SpoutAggResult(), exeList.get(i)); } } else { result = new BoltAggResult[exeList.size()]; for (int i = 0; i < result.length; i++) { result[i] = createTaskIndex(new BoltAggResult(), exeList.get(i)); } } results.put(comp, result); }); firstTasks = comp2Executors.values().stream().flatMap(e -> e.stream()).map(ExecutorDetails::getStartTask) .collect(Collectors.toSet()); } private AggResult createTaskIndex(AggResult result, ExecutorDetails e) { IntStream.rangeClosed(e.getStartTask(), e.getEndTask()).forEach((task) -> task2Result.put(task, result)); return result; } private AggResult parse(MeasuredData measuredData, AggResult dest) { // parse send queue and recv queue first measuredData.data.computeIfPresent(MetricNames.SEND_QUEUE, (comp, data) -> { parseQueueResult((Map<String, Number>) data, dest.getSendQueueResult()); return data; }); measuredData.data.computeIfPresent(MetricNames.RECV_QUEUE, (comp, data) -> { parseQueueResult((Map<String, Number>) data, dest.getRecvQueueResult()); return data; }); if (firstTasks.contains(measuredData.task)) { measuredData.data.computeIfPresent(MetricNames.DURATION, (comp, data) -> { dest.addDuration(((Number) data).longValue()); return data; }); } if (rawTopo.get_spouts().containsKey(measuredData.component)) { Map<String, Object> data = (Map<String, Object>) measuredData.data.get(MetricNames.COMPLETE_LATENCY); if (data != null) { data.forEach((stream, elementStr) -> { String[] elements = ((String) elementStr).split(","); int cnt = Integer.valueOf(elements[0]); if (cnt > 0) { double val = Double.valueOf(elements[1]); double val_2 = Double.valueOf(elements[2]); ((SpoutAggResult) dest).getCompletedLatency().computeIfAbsent(stream, (k) -> new CntMeanVar()) .addAggWin(cnt, val, val_2); } }); } } else { Map<String, Object> data = (Map<String, Object>) measuredData.data.get(MetricNames.TASK_EXECUTE); if (data != null) { data.forEach((stream, elementStr) -> { String[] elements = ((String) elementStr).split(","); int cnt = Integer.valueOf(elements[0]); if (cnt > 0) { double val = Double.valueOf(elements[1]); double val_2 = Double.valueOf(elements[2]); ((BoltAggResult) dest).getTupleProcess().computeIfAbsent(stream, (k) -> new CntMeanVar()) .addAggWin(cnt, val, val_2); } }); } } return dest; } private void parseQueueResult(Map<String, Number> queueMetrics, QueueAggResult queueResult) { long totalArrivalCnt = queueMetrics.getOrDefault("totalCount", Integer.valueOf(0)).longValue(); if (totalArrivalCnt > 0) { int sampleCnt = queueMetrics.getOrDefault("sampleCount", Integer.valueOf(0)).intValue(); long totalQLen = queueMetrics.getOrDefault("totalQueueLen", Integer.valueOf(0)).longValue(); // long duration = queueMetrics.getOrDefault("duration", Integer.valueOf(0)).longValue(); queueResult.add(totalArrivalCnt, totalQLen, sampleCnt); } } public void calCMVStat() { int count = 0; for (MeasuredData measuredData : dataStream) { ///Real example //69) "objectSpout:4->{\"receive\":{\"sampleCount\":209,\"totalQueueLen\":212,\"totalCount\":4170},\"complete-latency\":{\"default\":\"2086,60635.0,3382707.0\"},\"sendqueue\":{\"sampleCount\":420,\"totalQueueLen\":424,\"totalCount\":8402}}" //70) "projection:7->{\"receive\":{\"sampleCount\":52,\"totalQueueLen\":53,\"totalCount\":1052},\"sendqueue\":{\"sampleCount\":2152,\"totalQueueLen\":4514,\"totalCount\":43052},\"execute\":{\"objectSpout:default\":\"525,709.4337659999997,1120.8007487084597\"}}" //71) "detector:3->{\"receive\":{\"sampleCount\":2769,\"totalQueueLen\":6088758,\"totalCount\":55416},\"sendqueue\":{\"sampleCount\":8921,\"totalQueueLen\":11476,\"totalCount\":178402},\"execute\":{\"projection:default\":\"49200,5167.623237000047,721.6383647758853\"}}" //73) "updater:9->{\"receive\":{\"sampleCount\":3921,\"totalQueueLen\":5495,\"totalCount\":78436},\"sendqueue\":{\"sampleCount\":4001,\"totalQueueLen\":4336,\"totalCount\":80002},\"execute\":{\"detector:default\":\"40000,1651.7782049999894,182.68124734051045\"}}" AggResult car = task2Result.get(measuredData.task); parse(measuredData, car); count++; } LOG.info("calCMVStat, processed measuredData size: " + count); } public Map<String, AggResult[]> getResults() { return results; } public Map<String, AggResult[]> getSpoutResults() { return results.entrySet().stream().filter(e -> rawTopo.get_spouts().containsKey(e.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } public Map<String, AggResult[]> getBoltResults() { return results.entrySet().stream().filter(e -> rawTopo.get_bolts().containsKey(e.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } }