Merge pull request #1765 from lioolli/master

Add AgentStatAggr table
This commit is contained in:
Jongho Moon
2016-05-12 17:57:30 +09:00
9 changed files with 253 additions and 13 deletions
@@ -35,6 +35,7 @@ public final class HBaseTables {
public static final int APPLICATION_TRACE_INDEX_ROW_DISTRIBUTE_SIZE = 1; // applicationIndex hash size
public static final TableName AGENT_STAT = TableName.valueOf("AgentStat");
public static final TableName AGENT_STAT_AGGR = TableName.valueOf("AgentStatAggr");
public static final byte[] AGENT_STAT_CF_STATISTICS = Bytes.toBytes("S"); // agent statistics column family
// FIXME (2014.08) Legacy column for storing serialzied TAgentStat Thrift DTO.
@Deprecated public static final byte[] AGENT_STAT_CF_STATISTICS_V1 = Bytes.toBytes("V1"); // qualifier
+1
View File
@@ -21,6 +21,7 @@ For example, you can create Pinpoint tables by running the following line from s
* ApplicationIndex, HostApplicationMap : Tables for applicationIds and agentIds registered under them
* AgentInfo : Table for basic agent information ex) ip, hostname agentversion, start time, etc
* AgentStat : Table for agents statistical data ex) cpuload, gc, heap etc
* AgentStatAggr : Table for agents statistical data aggregated for long term view
* AgentLifeCycle : Table for agents life cycle data.
* AgentEvent : Table for various agent events ex) request for thread dump, etc
* ApiMetaData : Meta-table for method information
+1
View File
@@ -1,5 +1,6 @@
create 'AgentInfo', { NAME => 'Info', TTL => 31536000, COMPRESSION => 'SNAPPY', DATA_BLOCK_ENCODING => 'PREFIX' }
create 'AgentStat', { NAME => 'S', TTL => 5184000, COMPRESSION => 'SNAPPY', DATA_BLOCK_ENCODING => 'PREFIX' }, {SPLITS=>["\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"]}
create 'AgentStatAggr', { NAME => 'S', TTL => 5184000, COMPRESSION => 'SNAPPY', DATA_BLOCK_ENCODING => 'PREFIX' }, {SPLITS=>["\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"]}
create 'ApplicationIndex', { NAME => 'Agents', TTL => 31536000, COMPRESSION => 'SNAPPY', DATA_BLOCK_ENCODING => 'PREFIX' }
create 'AgentLifeCycle', { NAME => 'S', TTL => 5184000, COMPRESSION => 'SNAPPY', DATA_BLOCK_ENCODING => 'PREFIX' }
create 'AgentEvent', { NAME => 'E', TTL => 5184000, COMPRESSION => 'SNAPPY', DATA_BLOCK_ENCODING => 'PREFIX' }
+1
View File
@@ -1,5 +1,6 @@
create 'AgentInfo', { NAME => 'Info', TTL => 31536000, DATA_BLOCK_ENCODING => 'PREFIX' }
create 'AgentStat', { NAME => 'S', TTL => 5184000, DATA_BLOCK_ENCODING => 'PREFIX' }, {SPLITS=>["\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"]}
create 'AgentStatAggr', { NAME => 'S', TTL => 5184000, DATA_BLOCK_ENCODING => 'PREFIX' }, {SPLITS=>["\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00","\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"]}
create 'ApplicationIndex', { NAME => 'Agents', TTL => 31536000, DATA_BLOCK_ENCODING => 'PREFIX' }
create 'AgentLifeCycle', { NAME => 'S', TTL => 5184000, DATA_BLOCK_ENCODING => 'PREFIX' }
create 'AgentEvent', { NAME => 'E', TTL => 5184000, DATA_BLOCK_ENCODING => 'PREFIX' }
+1
View File
@@ -1,5 +1,6 @@
disable 'AgentInfo'
disable 'AgentStat'
disable 'AgentStatAggr'
disable 'AgentLifeCycle'
disable 'AgentEvent'
disable 'ApplicationIndex'
+1
View File
@@ -1,5 +1,6 @@
flush 'AgentInfo'
flush 'AgentStat'
flush 'AgentStatAggr'
flush 'AgentLifeCycle'
flush 'AgentEvent'
flush 'ApplicationIndex'
@@ -1,5 +1,6 @@
major_compact 'AgentInfo'
major_compact 'AgentStat'
major_compact 'AgentStatAggr'
major_compact 'AgentLifeCycle'
major_compact 'AgentEvent'
major_compact 'ApplicationIndex'
@@ -19,19 +19,9 @@ package com.navercorp.pinpoint.web.dao.hbase;
import static com.navercorp.pinpoint.common.hbase.HBaseTables.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.navercorp.pinpoint.common.hbase.HBaseTables;
import com.navercorp.pinpoint.common.hbase.HbaseOperations2;
import com.navercorp.pinpoint.common.hbase.ResultsExtractor;
import com.navercorp.pinpoint.common.hbase.RowMapper;
import com.navercorp.pinpoint.common.util.BytesUtils;
import com.navercorp.pinpoint.common.util.RowKeyUtils;
import com.navercorp.pinpoint.common.util.TimeUtils;
import com.navercorp.pinpoint.web.dao.AgentStatDao;
import com.navercorp.pinpoint.web.vo.AgentStat;
import com.navercorp.pinpoint.web.vo.Range;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
@@ -41,6 +31,17 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import com.navercorp.pinpoint.common.hbase.HBaseTables;
import com.navercorp.pinpoint.common.hbase.HbaseOperations2;
import com.navercorp.pinpoint.common.hbase.ResultsExtractor;
import com.navercorp.pinpoint.common.hbase.RowMapper;
import com.navercorp.pinpoint.common.util.BytesUtils;
import com.navercorp.pinpoint.common.util.RowKeyUtils;
import com.navercorp.pinpoint.common.util.TimeUtils;
import com.navercorp.pinpoint.web.dao.AgentStatDao;
import com.navercorp.pinpoint.web.util.AgentStats;
import com.navercorp.pinpoint.web.vo.AgentStat;
import com.navercorp.pinpoint.web.vo.Range;
import com.sematext.hbase.wd.AbstractRowKeyDistributor;
/**
@@ -49,6 +50,9 @@ import com.sematext.hbase.wd.AbstractRowKeyDistributor;
*/
@Repository
public class HbaseAgentStatDao implements AgentStatDao {
private static final long USE_AGGR_THRESHOLD = 4L * 60 * 60 * 1000;
private static final int AGGR_INTERVAL = 10 * 60 * 1000;
private static final int AGGR_MAX_INTERVAL = AGGR_INTERVAL * 2;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -81,8 +85,15 @@ public class HbaseAgentStatDao implements AgentStatDao {
if (logger.isDebugEnabled()) {
logger.debug("scanAgentStat : agentId={}, {}", agentId, range);
}
if (range.getRange() < USE_AGGR_THRESHOLD) {
return getAgentStatListFromRaw(agentId, range);
} else {
return getAgentStatListFromAggr(agentId, range);
}
}
private List<AgentStat> getAgentStatListFromRaw(String agentId, Range range) {
Scan scan = createScan(agentId, range);
scan.addFamily(HBaseTables.AGENT_STAT_CF_STATISTICS);
@@ -97,7 +108,56 @@ public class HbaseAgentStatDao implements AgentStatDao {
return merged;
}
public List<AgentStat> getAgentStatListFromAggr(String agentId, Range range) {
Scan scan = createScan(agentId, range);
scan.addFamily(HBaseTables.AGENT_STAT_CF_STATISTICS);
List<List<AgentStat>> intermediate = hbaseOperations2.find(HBaseTables.AGENT_STAT_AGGR, scan, rowKeyDistributor, agentStatMapper);
List<AgentStat> merged = new ArrayList<>();
for (List<AgentStat> each : intermediate) {
merged.addAll(each);
}
Collections.sort(merged, AgentStats.TIMESTAMP_COMPARATOR);
List<Range> missingRanges = new ArrayList<>();
long last = range.getFrom();
for (AgentStat stat : merged) {
if (last + AGGR_MAX_INTERVAL < stat.getTimestamp()) {
Range r = new Range(last, stat.getTimestamp() - stat.getCollectInterval());
missingRanges.add(r);
}
last = stat.getTimestamp();
}
if (last + AGGR_MAX_INTERVAL < range.getTo()) {
Range r = new Range(last, range.getTo());
missingRanges.add(r);
}
for (Range r : missingRanges) {
logger.debug("AgentStatAggr doesn't have range: " + r.prettyToString() + " of " + agentId);
List<AgentStat> list = getAgentStatListFromRaw(agentId, r);
if (list.isEmpty()) {
logger.debug("AgentStat also doesn't have range: " + r.prettyToString() + " of " + agentId);
continue;
}
List<AgentStat> aggregated = AgentStats.aggregate(list, AGGR_INTERVAL);
merged.addAll(aggregated);
}
return merged;
}
@Override
public boolean agentStatExists(String agentId, Range range) {
if (agentId == null) {
@@ -0,0 +1,173 @@
/**
* Copyright 2014 NAVER Corp.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.navercorp.pinpoint.web.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.navercorp.pinpoint.web.vo.AgentStat;
/**
* @author Jongho Moon
*
*/
public class AgentStats {
public static final Comparator<AgentStat> TIMESTAMP_COMPARATOR = new Comparator<AgentStat>() {
@Override
public int compare(AgentStat o1, AgentStat o2) {
return Long.compare(o1.getTimestamp(), o2.getTimestamp());
}
};
public static List<AgentStat> aggregate(List<AgentStat> stats, int newInterval) {
return new Aggregator(stats, newInterval).aggregate();
}
private static class Aggregator {
private final List<AgentStat> stats;
private final int interval;
public Aggregator(List<AgentStat> stats, int interval) {
this.interval = interval;
this.stats = new ArrayList<>(stats);
Collections.sort(this.stats, TIMESTAMP_COMPARATOR);
}
public List<AgentStat> aggregate() {
if (stats.isEmpty()) {
return stats;
}
List<AgentStat> result = new ArrayList<>();
AgentStat current = toAggregatedAgentStat(stats.get(0));
for (AgentStat stat : stats.subList(1, stats.size())) {
long timestamp = targetTimestamp(stat);
if (current.getTimestamp() == timestamp) {
current = add(current, stat);
} else {
result.add(current);
current = toAggregatedAgentStat(stat);
}
}
result.add(current);
return result;
}
private AgentStat toAggregatedAgentStat(AgentStat stat) {
long timestamp = targetTimestamp(stat);
AgentStat result = new AgentStat(stat.getAgentId(), timestamp);
result.setCollectInterval(interval);
result.setGcType(stat.getGcType());
result.setGcOldCount(stat.getGcOldCount());
result.setGcOldTime(stat.getGcOldTime());
result.setHeapUsed(stat.getHeapUsed());
result.setHeapMax(stat.getHeapMax());
result.setNonHeapUsed(stat.getNonHeapUsed());
result.setNonHeapMax(stat.getNonHeapMax());
result.setJvmCpuUsage(stat.getJvmCpuUsage());
result.setSystemCpuUsage(stat.getSystemCpuUsage());
result.setSampledNewCount(stat.getSampledNewCount());
result.setSampledContinuationCount(stat.getSampledContinuationCount());
result.setUnsampledNewCount(stat.getUnsampledNewCount());
result.setUnsampledContinuationCount(stat.getUnsampledContinuationCount());
result.setHistogramSchema(stat.getHistogramSchema());
result.setActiveTraceCounts(stat.getActiveTraceCounts());
return result;
}
private long targetTimestamp(AgentStat stat) {
long timestamp = (stat.getTimestamp() / interval) * interval;
if (stat.getTimestamp() != timestamp) {
timestamp += interval;
}
return timestamp;
}
public AgentStat add(AgentStat s1, AgentStat s2) {
AgentStat latest = s1.getTimestamp() > s2.getTimestamp() ? s1 : s2;
AgentStat stat = new AgentStat(s1.getAgentId(), s1.getTimestamp());
stat.setGcType(latest.getGcType());
stat.setGcOldCount(latest.getGcOldCount());
stat.setGcOldTime(latest.getGcOldTime());
stat.setHeapUsed(latest.getHeapUsed());
stat.setHeapMax(maxValue(s1.getHeapMax(), s2.getHeapMax()));
stat.setNonHeapUsed(latest.getNonHeapUsed());
stat.setNonHeapMax(maxValue(s1.getNonHeapMax(), s2.getNonHeapMax()));
stat.setJvmCpuUsage(latest.getJvmCpuUsage());
stat.setSystemCpuUsage(latest.getSystemCpuUsage());
stat.setSampledNewCount(addValue(s1.getSampledNewCount(), s2.getSampledNewCount()));
stat.setSampledContinuationCount(addValue(s1.getSampledContinuationCount(), s2.getSampledContinuationCount()));
stat.setUnsampledNewCount(addValue(s1.getUnsampledNewCount(), s2.getUnsampledNewCount()));
stat.setUnsampledContinuationCount(addValue(s1.getUnsampledContinuationCount(), s2.getUnsampledContinuationCount()));
stat.setHistogramSchema(latest.getHistogramSchema());
stat.setActiveTraceCounts(latest.getActiveTraceCounts());
return stat;
}
private long addValue(long v1, long v2) {
if (v1 == AgentStat.NOT_COLLECTED) {
if (v2 == AgentStat.NOT_COLLECTED) {
return AgentStat.NOT_COLLECTED;
} else {
return v2;
}
} else {
if (v1 == AgentStat.NOT_COLLECTED) {
return v1;
} else {
return v1 + v2;
}
}
}
private long maxValue(long v1, long v2) {
if (v1 == AgentStat.NOT_COLLECTED) {
return v2;
} else if (v2 == AgentStat.NOT_COLLECTED) {
return v1;
}
return v1 < v2 ? v2 : v1;
}
}
}