New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SCB-359]Servicecomb support latency statistic #1075
Conversation
Hi, maybe you can merge these three commit into one by And I don't quite understand the meaning of your first commit, could you tell me? |
|
@Override | ||
public void calcMeasurements(List<Measurement> measurements, long msNow, long secondInterval) { | ||
latencyIntervals.forEach(latencyInterval -> { | ||
measurements.add(newMeasurement(rootId.withTag("buckets_interval", latencyInterval.toString()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result of rootId.withTag("buckets_interval", latencyInterval.toString()) never changed, right?
save it to latencyInterval ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. I see
@Override | ||
public void calcMeasurements(List<Measurement> measurements, long msNow, long secondInterval) { | ||
latencyIntervals.forEach(latencyInterval -> { | ||
measurements.add(newMeasurement(rootId.withTag("buckets_interval", latencyInterval.toString()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change buckets_interval to bucket
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe buckets_interval or buckets_latency is better ?
if (arrays == null || arrays.length == 0) { | ||
return results; | ||
} | ||
results.add(new LatencyInterval(0L, arrays[0] * MS_UNIT)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete MS_UNIT
change to TimeUnit.MILLISECONDS.toNanos()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
return results; | ||
} | ||
|
||
public static String getStrFormatFromProperty(List<LatencyInterval> latencyIntervals) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why place this method here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved it to the Class DefaultLogPublisher
} | ||
|
||
public long getAndUpdateLastTimes() { | ||
long result = times.longValue() - lastUpdated; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
save value of times.longValue() first
otherwise will lost some value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
...-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/meter/StatisticsBucket.java
Outdated
Show resolved
Hide resolved
totalTimer = creatStageTimer(MeterInvocationConst.STAGE_TOTAL); | ||
prepareTimer = creatStageTimer(MeterInvocationConst.STAGE_PREPARE); | ||
handlersRequestTimer = creatStageTimer(MeterInvocationConst.STAGE_HANDLERS_REQUEST); | ||
handlersResponseTimer = creatStageTimer(MeterInvocationConst.STAGE_HANDLERS_RESPONSE); | ||
} | ||
|
||
protected StatisticsBucket creatStageBucket(String bucketsValue) { | ||
return new StatisticsBucket(id.withTag(MeterInvocationConst.TAG_STAGE, bucketsValue)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
latency bucket is a invocation stage? seems strange......
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So. what value should I use here ?
@@ -60,27 +62,31 @@ | |||
|
|||
//sample | |||
private static final String SIMPLE_HEADER = "%s:\n simple:\n" | |||
+ " status tps latency operation\n"; | |||
+ " status tps latency %soperation\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
two %s never changed, format them every time is not good
and difficult to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@@ -89,7 +95,9 @@ public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootst | |||
.get()) { | |||
return; | |||
} | |||
|
|||
latencyIntervals = StatisticsBucket |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems delete many empty lines between logic blocks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... maybe it's doesn't matter ? Must I leave the spaces here ?
MeasurementNode timeInterval = stageNode.findChild(StatisticsBucket.TIME_INTERVAL); | ||
// latency buckets | ||
if (timeInterval != null) { | ||
perfInfo.initInterval(timeInterval); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
latency bucket is not belongs to perfInfo, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I move it to the class OperationPerf, as I thought that every operation has it's own latency
public class OperationPerf {
private String operation;
private Map<String, PerfInfo> stages = new HashMap<>();
private Map<String, BucketInfo> buckets = new HashMap<>();
import com.netflix.spectator.api.Id; | ||
import com.netflix.spectator.api.Measurement; | ||
|
||
public class StatisticsBucket extends AbstractPeriodMeter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name is strange, seems can not express logic of this class?
return results; | ||
} | ||
|
||
public static class LatencyInterval { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LatencyScope?
and comment that: [min, max)
public LatencyInterval(long minValue, long maxValue, Id rootId) { | ||
this.minValue = minValue; | ||
this.maxValue = maxValue; | ||
if (rootId != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when will rootId be null?
private List<LatencyInterval> latencyIntervals; | ||
|
||
public StatisticsBucket(Id id) { | ||
this.id = id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why need both id and rootId?
if (arrays == null || arrays.length == 0) { | ||
return results; | ||
} | ||
results.add(new LatencyInterval(0L, arrays[0] * TimeUnit.MILLISECONDS.toNanos(1), rootId)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TimeUnit.MILLISECONDS.toNanos(arrays[0])
|
||
public String getStandardLatencyStr() { | ||
StringBuilder sb = new StringBuilder(); | ||
sb.append("[").append(minValue / TimeUnit.MILLISECONDS.toNanos(1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TimeUnit.NANOSECONDS.toMillis(minValue)
import com.netflix.spectator.api.Id; | ||
import com.netflix.spectator.api.Measurement; | ||
|
||
public class BucketsDistribution extends AbstractPeriodMeter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LatencyDistribution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
return results; | ||
} | ||
|
||
public static class LatencyInterval { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LatencyScope
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will change the class name
public class BucketsDistribution extends AbstractPeriodMeter { | ||
private static final Logger LOGGER = LoggerFactory.getLogger(BucketsDistribution.class); | ||
|
||
public static final String METRICS_LATENCY = DynamicPropertyFactory.getInstance() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default to ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, change the default value is ""
|
||
public LatencyInterval(long minValue, long maxValue, Id rootId) { | ||
this.minValue = TimeUnit.MILLISECONDS.toNanos(minValue); | ||
this.maxValue = maxValue == Long.MAX_VALUE ? Long.MAX_VALUE : TimeUnit.MILLISECONDS.toNanos(maxValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MAX-VALUE -1 will overflow also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have redesign the method.
public static List<LatencyScope> parseLatencyIntervalListFromProperty(String property, Id rootId) {
List<LatencyScope> results = new ArrayList<>();
try {
String[] arrays = property.trim().split(",");
if (arrays.length == 0) {
return results;
}
results.add(new LatencyScope(0L, TimeUnit.MILLISECONDS.toNanos(Integer.parseInt(arrays[0])),
createLatencyScopeId("0", arrays[0], rootId)));
for (int i = 1; i < arrays.length; i++) {
results.add(new LatencyScope(TimeUnit.MILLISECONDS.toNanos(Integer.parseInt(arrays[i - 1])),
TimeUnit.MILLISECONDS.toNanos(Integer.parseInt(arrays[i])),
createLatencyScopeId(arrays[i - 1], arrays[i], rootId)));
}
results.add(new LatencyScope(
TimeUnit.MILLISECONDS.toNanos(Integer.parseInt(arrays[arrays.length - 1])), Long.MAX_VALUE,
createLatencyScopeId(arrays[arrays.length - 1], " ", rootId)));
} catch (Throwable e) {
LOGGER.error("Failed to parse property servicecomb.metrics.invocation.latency.buckets", e);
}
return results;
}
/**
* create LatencyScopeId with format [leftStr,rightStr)
* @param leftStr leftValue
* @param rightStr rightValue
* @param rootId rootId
* @return id
*/
private static Id createLatencyScopeId(String leftStr, String rightStr, Id rootId) {
return rootId.withTag("statistic", LatencyScope.getStandardLatencyScopeStr(leftStr, rightStr, 0));
}
public static class LatencyScope {
private Id id;
private LongAdder times = new LongAdder();
private long lastUpdated = 0L;
private long minNanoSeconds;
private long maxNanoSeconds;
public LatencyScope(long minNanoSeconds, long maxNanoSeconds, Id id) throws Exception {
if (minNanoSeconds >= maxNanoSeconds) {
throw new Exception("maxNanoSeconds must greater than minNanoSeconds");
}
this.minNanoSeconds = minNanoSeconds;
this.maxNanoSeconds = maxNanoSeconds;
this.id = id;
}
// bucket total | ||
private BucketsDistribution totalBucket; | ||
//stage | ||
private Id stageId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to cache stageId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will removed it. and how about the name latencyDistribution
private LatencyDistributionMeter latencyDistribution;
private long lastUpdated;
public AbstractInvocationMeter(Registry registry, Id id) {
this.registry = registry;
this.id = id;
latencyDistribution = createStatisticsBucket(MeterInvocationConst.TAG_LATENCY_DISTRIBUTION);
totalTimer = createStageTimer(MeterInvocationConst.STAGE_TOTAL);
prepareTimer = createStageTimer(MeterInvocationConst.STAGE_PREPARE);
handlersRequestTimer = createStageTimer(MeterInvocationConst.STAGE_HANDLERS_REQUEST);
handlersResponseTimer = createStageTimer(MeterInvocationConst.STAGE_HANDLERS_RESPONSE);
}
@@ -43,20 +44,30 @@ | |||
// handler response | |||
private SimpleTimer handlersResponseTimer; | |||
|
|||
// bucket total | |||
private BucketsDistribution totalBucket; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to latencyDistribution
// latency distribution
private LatencyDistributionMeter latencyDistribution;
+ " sFiltersResp: %-18s sendResp : %s\n"; | ||
|
||
|
||
private List<String> sortedLatencyIntervals; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments these fields with sample configuration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
|
||
public static class LatencyInterval { | ||
|
||
public static final int leastLength = 7; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only for publish, not relate to calc......
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved the leastLength to the class DefaultLogPublisher.
as I thought that this number is relate to the log and has no relation with tag
public class DefaultLogPublisher implements MetricsInitializer {
private static final int LEAST_LATENCY_SCOPE_STR_LENGTH = 7;
public LatencyInterval(long minValue, long maxValue, Id rootId) { | ||
this.minValue = TimeUnit.MILLISECONDS.toNanos(minValue); | ||
this.maxValue = maxValue == Long.MAX_VALUE ? Long.MAX_VALUE : TimeUnit.MILLISECONDS.toNanos(maxValue); | ||
this.id = rootId.withTag("statistic", getStandardLatencyStr(minValue, maxValue, leastLength)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tag no need to same to output format.....
tag is "[0,1)", and output format is "[0,1) ", seems not conflict, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, I will redesign the method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private static Id createLatencyScopeId(String leftStr, String rightStr, Id rootId) {
return rootId.withTag("statistic", LatencyScope.getStandardLatencyScopeStr(leftStr, rightStr, 0));
}
public static String getStandardLatencyScopeStr(String leftStr, String rightStr, int minLength) {
StringBuilder sb = new StringBuilder();
sb.append("[").append(leftStr)
.append(",")
.append(rightStr)
.append(")");
if (sb.length() < minLength) {
for (int i = 0; i < minLength - sb.length(); i++) {
sb.append(' ');
}
}
return sb.toString();
}
return String.format(intervalFormat, array); | ||
} | ||
|
||
public String getLogStrFormat(List<String> latencyIntervals) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1.private
2.change name relate to latency distribution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. the new method is as bellow
/**
* <p>
* get respond str format from list of str. for example
* {@code
* List<String> strList = Arrays.asList("[0,1) ", "[1,4) ", "[4, ) ");
* String strFormat = getLatencyScopeFormat(strList);
* System.out.println(String.format(strFormat,strList.toArray()));
* System.out.println(String.format(strFormat, 1, 23, 433));
* System.out.println(String.format(strFormat, 121, 2, 4));
* }
* In the example above, result is showed as bellow:
* [0,1) [1,4) [4, )
* 1 23 433
* 121 2 4
* </p>
* @param latencyIntervals list of str
* @return str format
*/
private String getLatencyScopeFormat(List<String> latencyIntervals) {
|
||
import com.google.common.annotations.VisibleForTesting; | ||
|
||
public class OperationLatencyDistribution { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try to delete this class, make logic simpler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have replace the class with
public class OperationPerf {
private String operation;
private Map<String, PerfInfo> stages = new HashMap<>();
private List<Integer> latencyDistribution = new ArrayList<>();
* @param latencyIntervals list of str | ||
* @return str format | ||
*/ | ||
private String getLatencyScopeFormat(List<String> latencyIntervals) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change parameter name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Follow this checklist to help us incorporate your contribution quickly and easily:
[SCB-XXX] Fixes bug in ApproximateQuantiles
, where you replaceSCB-XXX
with the appropriate JIRA issue.mvn clean install
to make sure basic checks pass. A more thorough check will be performed on your pull request automatically.