Skip to content
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

Merged
merged 3 commits into from Mar 7, 2019
Merged

[SCB-359]Servicecomb support latency statistic #1075

merged 3 commits into from Mar 7, 2019

Conversation

heyile
Copy link
Contributor

@heyile heyile commented Jan 26, 2019

Follow this checklist to help us incorporate your contribution quickly and easily:

  • Make sure there is a JIRA issue filed for the change (usually before you start working on it). Trivial changes like typos do not require a JIRA issue. Your pull request should address just this issue, without pulling in other changes.
  • Each commit in the pull request should have a meaningful subject line and body.
  • Format the pull request title like [SCB-XXX] Fixes bug in ApproximateQuantiles, where you replace SCB-XXX with the appropriate JIRA issue.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Run mvn clean install to make sure basic checks pass. A more thorough check will be performed on your pull request automatically.
  • If this contribution is large, please file an Apache Individual Contributor License Agreement.

@heyile heyile closed this Jan 26, 2019
@heyile heyile reopened this Jan 26, 2019
@heyile heyile changed the title Metrics interval [SCB-359]Servicecomb support latency statistic Jan 26, 2019
@coveralls
Copy link

Coverage Status

Coverage increased (+0.01%) to 85.928% when pulling 5c85242 on heyile:metricsInterval into d276f41 on apache:master.

@coveralls
Copy link

coveralls commented Jan 26, 2019

Coverage Status

Coverage increased (+0.01%) to 85.462% when pulling e4c7ef2 on heyile:metricsInterval into df2002a on apache:master.

@yhs0092
Copy link
Member

yhs0092 commented Jan 28, 2019

Hi, maybe you can merge these three commit into one by git rebase : )

And I don't quite understand the meaning of your first commit, could you tell me?

@heyile
Copy link
Contributor Author

heyile commented Jan 28, 2019

Hi, maybe you can merge these three commit into one by git rebase : )

And I don't quite understand the meaning of your first commit, could you tell me?
the first commit is because that the name of variable may mislead others... and I want distinguish it from latency statistic. maybe rebase last two commits is better :-)

@Override
public void calcMeasurements(List<Measurement> measurements, long msNow, long secondInterval) {
latencyIntervals.forEach(latencyInterval -> {
measurements.add(newMeasurement(rootId.withTag("buckets_interval", latencyInterval.toString()),
Copy link
Contributor

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 ?

Copy link
Contributor Author

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()),
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor Author

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));
Copy link
Contributor

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()

Copy link
Contributor Author

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) {
Copy link
Contributor

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?

Copy link
Contributor Author

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;
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

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));
Copy link
Contributor

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......

Copy link
Contributor Author

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";
Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor

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?

Copy link
Contributor Author

@heyile heyile Feb 22, 2019

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);
Copy link
Contributor

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?

Copy link
Contributor Author

@heyile heyile Feb 22, 2019

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 {
Copy link
Contributor

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 {
Copy link
Contributor

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) {
Copy link
Contributor

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;
Copy link
Contributor

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));
Copy link
Contributor

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))
Copy link
Contributor

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LatencyDistribution

Copy link
Contributor Author

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LatencyScope

Copy link
Contributor Author

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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default to ""

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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;
Copy link
Contributor

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

Copy link
Contributor Author

@heyile heyile Mar 6, 2019

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change name

Copy link
Contributor Author

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;
Copy link
Contributor

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

Copy link
Contributor Author

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;
Copy link
Contributor

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......

Copy link
Contributor Author

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));
Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor Author

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) {
Copy link
Contributor

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

Copy link
Contributor Author

@heyile heyile Mar 6, 2019

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 {
Copy link
Contributor

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

Copy link
Contributor Author

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change parameter name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@wujimin wujimin merged commit f4ae766 into apache:master Mar 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants