services: add qps in orca api (#9866)

This commit is contained in:
yifeizhuang 2023-02-02 15:16:27 -08:00 committed by GitHub
parent fb70a66e2c
commit 6119f6ec94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 68 additions and 15 deletions

View File

@ -95,10 +95,10 @@ def grpc_java_repositories():
if not native.existing_rule("com_github_cncf_xds"): if not native.existing_rule("com_github_cncf_xds"):
http_archive( http_archive(
name = "com_github_cncf_xds", name = "com_github_cncf_xds",
strip_prefix = "xds-d92e9ce0af512a73a3a126b32fa4920bee12e180", strip_prefix = "xds-06c439db220b89134a8a49bad41994560d6537c6",
sha256 = "27be88b1ff2844885d3b2d0d579546f3a8b3f26b4871eed89082c9709e49a4bd", sha256 = "41ea212940ab44bf7f8a8b4169cfbc612ed2166dafabc0a56a8820ef665fc6a4",
urls = [ urls = [
"https://github.com/cncf/xds/archive/d92e9ce0af512a73a3a126b32fa4920bee12e180.tar.gz", "https://github.com/cncf/xds/archive/06c439db220b89134a8a49bad41994560d6537c6.tar.gz",
], ],
) )
if not native.existing_rule("com_github_grpc_grpc"): if not native.existing_rule("com_github_grpc_grpc"):

View File

@ -43,6 +43,7 @@ public final class CallMetricRecorder {
new AtomicReference<>(); new AtomicReference<>();
private double cpuUtilizationMetric = 0; private double cpuUtilizationMetric = 0;
private double memoryUtilizationMetric = 0; private double memoryUtilizationMetric = 0;
private double qps = 0;
private volatile boolean disabled; private volatile boolean disabled;
/** /**
@ -158,6 +159,23 @@ public final class CallMetricRecorder {
return this; return this;
} }
/**
* Records a call metric measurement for qps.
* If RPC has already finished, this method is no-op.
*
* <p>A latter record will overwrite its former name-sakes.
*
* @return this recorder object
* @since 1.54.0
*/
public CallMetricRecorder recordQpsMetric(double value) {
if (disabled) {
return this;
}
qps = value;
return this;
}
/** /**
* Returns all request cost metric values. No more metric values will be recorded after this * Returns all request cost metric values. No more metric values will be recorded after this
@ -187,8 +205,8 @@ public final class CallMetricRecorder {
if (savedUtilizationMetrics == null) { if (savedUtilizationMetrics == null) {
savedUtilizationMetrics = Collections.emptyMap(); savedUtilizationMetrics = Collections.emptyMap();
} }
return new MetricReport(cpuUtilizationMetric, return new MetricReport(cpuUtilizationMetric, memoryUtilizationMetric, qps,
memoryUtilizationMetric, Collections.unmodifiableMap(savedRequestCostMetrics), Collections.unmodifiableMap(savedRequestCostMetrics),
Collections.unmodifiableMap(savedUtilizationMetrics) Collections.unmodifiableMap(savedUtilizationMetrics)
); );
} }

View File

@ -46,8 +46,8 @@ public final class InternalCallMetricRecorder {
} }
public static MetricReport createMetricReport(double cpuUtilization, double memoryUtilization, public static MetricReport createMetricReport(double cpuUtilization, double memoryUtilization,
Map<String, Double> requestCostMetrics, Map<String, Double> utilizationMetrics) { double qps, Map<String, Double> requestCostMetrics, Map<String, Double> utilizationMetrics) {
return new MetricReport(cpuUtilization, memoryUtilization, return new MetricReport(cpuUtilization, memoryUtilization, qps, requestCostMetrics,
requestCostMetrics, utilizationMetrics); utilizationMetrics);
} }
} }

View File

@ -30,6 +30,7 @@ public final class MetricRecorder {
private volatile ConcurrentHashMap<String, Double> metricsData = new ConcurrentHashMap<>(); private volatile ConcurrentHashMap<String, Double> metricsData = new ConcurrentHashMap<>();
private volatile double cpuUtilization; private volatile double cpuUtilization;
private volatile double memoryUtilization; private volatile double memoryUtilization;
private volatile double qps;
public static MetricRecorder newInstance() { public static MetricRecorder newInstance() {
return new MetricRecorder(); return new MetricRecorder();
@ -86,8 +87,22 @@ public final class MetricRecorder {
memoryUtilization = 0; memoryUtilization = 0;
} }
/**
* Update the QPS metrics data.
*/
public void setQps(double value) {
qps = value;
}
/**
* Clear the QPS metrics data.
*/
public void clearQps() {
qps = 0;
}
MetricReport getMetricReport() { MetricReport getMetricReport() {
return new MetricReport(cpuUtilization, memoryUtilization, return new MetricReport(cpuUtilization, memoryUtilization, qps,
Collections.emptyMap(), Collections.unmodifiableMap(metricsData)); Collections.emptyMap(), Collections.unmodifiableMap(metricsData));
} }
} }

View File

@ -30,14 +30,16 @@ import java.util.Map;
public final class MetricReport { public final class MetricReport {
private double cpuUtilization; private double cpuUtilization;
private double memoryUtilization; private double memoryUtilization;
private double qps;
private Map<String, Double> requestCostMetrics; private Map<String, Double> requestCostMetrics;
private Map<String, Double> utilizationMetrics; private Map<String, Double> utilizationMetrics;
MetricReport(double cpuUtilization, double memoryUtilization, MetricReport(double cpuUtilization, double memoryUtilization, double qps,
Map<String, Double> requestCostMetrics, Map<String, Double> requestCostMetrics,
Map<String, Double> utilizationMetrics) { Map<String, Double> utilizationMetrics) {
this.cpuUtilization = cpuUtilization; this.cpuUtilization = cpuUtilization;
this.memoryUtilization = memoryUtilization; this.memoryUtilization = memoryUtilization;
this.qps = qps;
this.requestCostMetrics = checkNotNull(requestCostMetrics, "requestCostMetrics"); this.requestCostMetrics = checkNotNull(requestCostMetrics, "requestCostMetrics");
this.utilizationMetrics = checkNotNull(utilizationMetrics, "utilizationMetrics"); this.utilizationMetrics = checkNotNull(utilizationMetrics, "utilizationMetrics");
} }
@ -58,6 +60,10 @@ public final class MetricReport {
return utilizationMetrics; return utilizationMetrics;
} }
public double getQps() {
return qps;
}
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
@ -65,6 +71,7 @@ public final class MetricReport {
.add("memoryUtilization", memoryUtilization) .add("memoryUtilization", memoryUtilization)
.add("requestCost", requestCostMetrics) .add("requestCost", requestCostMetrics)
.add("utilization", utilizationMetrics) .add("utilization", utilizationMetrics)
.add("qps", qps)
.toString(); .toString();
} }
} }

View File

@ -46,6 +46,7 @@ public class CallMetricRecorderTest {
recorder.recordRequestCostMetric("cost3", 1.0); recorder.recordRequestCostMetric("cost3", 1.0);
recorder.recordCpuUtilizationMetric(0.1928); recorder.recordCpuUtilizationMetric(0.1928);
recorder.recordMemoryUtilizationMetric(47.4); recorder.recordMemoryUtilizationMetric(47.4);
recorder.recordQpsMetric(2522.54);
MetricReport dump = recorder.finalizeAndDump2(); MetricReport dump = recorder.finalizeAndDump2();
Truth.assertThat(dump.getUtilizationMetrics()) Truth.assertThat(dump.getUtilizationMetrics())
@ -54,6 +55,7 @@ public class CallMetricRecorderTest {
.containsExactly("cost1", 37465.12, "cost2", 10293.0, "cost3", 1.0); .containsExactly("cost1", 37465.12, "cost2", 10293.0, "cost3", 1.0);
Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0.1928); Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0.1928);
Truth.assertThat(dump.getMemoryUtilization()).isEqualTo(47.4); Truth.assertThat(dump.getMemoryUtilization()).isEqualTo(47.4);
Truth.assertThat(dump.getQps()).isEqualTo(2522.54);
} }
@Test @Test
@ -75,6 +77,8 @@ public class CallMetricRecorderTest {
recorder.recordUtilizationMetric("util1", 28374.21); recorder.recordUtilizationMetric("util1", 28374.21);
recorder.recordMemoryUtilizationMetric(9384.0); recorder.recordMemoryUtilizationMetric(9384.0);
recorder.recordUtilizationMetric("util1", 84323.3); recorder.recordUtilizationMetric("util1", 84323.3);
recorder.recordQpsMetric(1928.3);
recorder.recordQpsMetric(100.8);
MetricReport dump = recorder.finalizeAndDump2(); MetricReport dump = recorder.finalizeAndDump2();
Truth.assertThat(dump.getRequestCostMetrics()) Truth.assertThat(dump.getRequestCostMetrics())
@ -83,6 +87,7 @@ public class CallMetricRecorderTest {
Truth.assertThat(dump.getUtilizationMetrics()) Truth.assertThat(dump.getUtilizationMetrics())
.containsExactly("util1", 84323.3); .containsExactly("util1", 84323.3);
Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0); Truth.assertThat(dump.getCpuUtilization()).isEqualTo(0);
Truth.assertThat(dump.getQps()).isEqualTo(100.8);
} }
@Test @Test

View File

@ -254,8 +254,8 @@ public abstract class OrcaPerRequestUtil {
static MetricReport fromOrcaLoadReport(OrcaLoadReport loadReport) { static MetricReport fromOrcaLoadReport(OrcaLoadReport loadReport) {
return InternalCallMetricRecorder.createMetricReport(loadReport.getCpuUtilization(), return InternalCallMetricRecorder.createMetricReport(loadReport.getCpuUtilization(),
loadReport.getMemUtilization(), loadReport.getRequestCostMap(), loadReport.getMemUtilization(), loadReport.getRpsFractional(),
loadReport.getUtilizationMap()); loadReport.getRequestCostMap(), loadReport.getUtilizationMap());
} }
/** /**

View File

@ -150,6 +150,7 @@ public final class OrcaServiceImpl implements BindableService {
InternalMetricRecorder.getMetricReport(metricRecorder); InternalMetricRecorder.getMetricReport(metricRecorder);
return OrcaLoadReport.newBuilder().setCpuUtilization(internalReport.getCpuUtilization()) return OrcaLoadReport.newBuilder().setCpuUtilization(internalReport.getCpuUtilization())
.setMemUtilization(internalReport.getMemoryUtilization()) .setMemUtilization(internalReport.getMemoryUtilization())
.setRpsFractional(internalReport.getQps())
.putAllUtilization(internalReport.getUtilizationMetrics()) .putAllUtilization(internalReport.getUtilizationMetrics())
.build(); .build();
} }

View File

@ -143,19 +143,23 @@ public class OrcaServiceImplTest {
ClientCall<OrcaLoadReportRequest, OrcaLoadReport> call = channel.newCall( ClientCall<OrcaLoadReportRequest, OrcaLoadReport> call = channel.newCall(
OpenRcaServiceGrpc.getStreamCoreMetricsMethod(), CallOptions.DEFAULT); OpenRcaServiceGrpc.getStreamCoreMetricsMethod(), CallOptions.DEFAULT);
defaultTestService.putUtilizationMetric("buffer", 0.2); defaultTestService.putUtilizationMetric("buffer", 0.2);
defaultTestService.setQps(1.9);
call.start(listener, new Metadata()); call.start(listener, new Metadata());
call.sendMessage(OrcaLoadReportRequest.newBuilder() call.sendMessage(OrcaLoadReportRequest.newBuilder()
.setReportInterval(Duration.newBuilder().setSeconds(0).setNanos(500).build()).build()); .setReportInterval(Duration.newBuilder().setSeconds(0).setNanos(500).build()).build());
call.halfClose(); call.halfClose();
call.request(1); call.request(1);
OrcaLoadReport expect = OrcaLoadReport.newBuilder().putUtilization("buffer", 0.2).build(); OrcaLoadReport expect = OrcaLoadReport.newBuilder().putUtilization("buffer", 0.2)
.setRpsFractional(1.9).build();
verify(listener).onMessage(eq(expect)); verify(listener).onMessage(eq(expect));
reset(listener); reset(listener);
defaultTestService.removeUtilizationMetric("buffer0"); defaultTestService.removeUtilizationMetric("buffer0");
defaultTestService.clearQps();
assertThat(fakeClock.forwardTime(500, TimeUnit.NANOSECONDS)).isEqualTo(0); assertThat(fakeClock.forwardTime(500, TimeUnit.NANOSECONDS)).isEqualTo(0);
verifyNoInteractions(listener); verifyNoInteractions(listener);
assertThat(fakeClock.forwardTime(1, TimeUnit.SECONDS)).isEqualTo(1); assertThat(fakeClock.forwardTime(1, TimeUnit.SECONDS)).isEqualTo(1);
call.request(1); call.request(1);
expect = OrcaLoadReport.newBuilder().putUtilization("buffer", 0.2).build();
verify(listener).onMessage(eq(expect)); verify(listener).onMessage(eq(expect));
} }
@ -245,17 +249,20 @@ public class OrcaServiceImplTest {
.setMemUtilization(random.nextDouble()) .setMemUtilization(random.nextDouble())
.putAllUtilization(firstUtilization) .putAllUtilization(firstUtilization)
.putUtilization("queue", 1.0) .putUtilization("queue", 1.0)
.setRpsFractional(1239.01)
.build(); .build();
defaultTestService.setCpuUtilizationMetric(goldenReport.getCpuUtilization()); defaultTestService.setCpuUtilizationMetric(goldenReport.getCpuUtilization());
defaultTestService.setMemoryUtilizationMetric(goldenReport.getMemUtilization()); defaultTestService.setMemoryUtilizationMetric(goldenReport.getMemUtilization());
defaultTestService.setAllUtilizationMetrics(firstUtilization); defaultTestService.setAllUtilizationMetrics(firstUtilization);
defaultTestService.putUtilizationMetric("queue", 1.0); defaultTestService.putUtilizationMetric("queue", 1.0);
defaultTestService.setQps(1239.01);
Iterator<OrcaLoadReport> reports = OpenRcaServiceGrpc.newBlockingStub(channel) Iterator<OrcaLoadReport> reports = OpenRcaServiceGrpc.newBlockingStub(channel)
.streamCoreMetrics(OrcaLoadReportRequest.newBuilder().build()); .streamCoreMetrics(OrcaLoadReportRequest.newBuilder().build());
assertThat(reports.next()).isEqualTo(goldenReport); assertThat(reports.next()).isEqualTo(goldenReport);
defaultTestService.clearCpuUtilizationMetric(); defaultTestService.clearCpuUtilizationMetric();
defaultTestService.clearMemoryUtilizationMetric(); defaultTestService.clearMemoryUtilizationMetric();
defaultTestService.clearQps();
fakeClock.forwardTime(1, TimeUnit.SECONDS); fakeClock.forwardTime(1, TimeUnit.SECONDS);
goldenReport = OrcaLoadReport.newBuilder() goldenReport = OrcaLoadReport.newBuilder()
.putAllUtilization(firstUtilization) .putAllUtilization(firstUtilization)