KAFKA-1359: Ensure all topic/server metrics registered at once.

This commit is contained in:
Jay Kreps 2014-04-16 10:19:18 -07:00
parent 9a6f7113ed
commit ec075c5a85
2 changed files with 119 additions and 77 deletions

View File

@ -774,27 +774,35 @@ public class Sender implements Runnable {
public SenderMetrics(Metrics metrics) { public SenderMetrics(Metrics metrics) {
this.metrics = metrics; this.metrics = metrics;
this.batchSizeSensor = metrics.sensor("batch-size"); this.batchSizeSensor = metrics.sensor("batch-size");
this.queueTimeSensor = metrics.sensor("queue-time");
this.requestTimeSensor = metrics.sensor("request-time");
this.recordsPerRequestSensor = metrics.sensor("records-per-request");
this.retrySensor = metrics.sensor("record-retries");
this.errorSensor = metrics.sensor("errors");
this.maxRecordSizeSensor = metrics.sensor("record-size-max");
this.batchSizeSensor.add("batch-size-avg", "The average number of bytes sent per partition per-request.", new Avg()); this.batchSizeSensor.add("batch-size-avg", "The average number of bytes sent per partition per-request.", new Avg());
this.retrySensor.add("record-retry-rate", "The average per-second number of retried record sends", new Rate());
this.queueTimeSensor = metrics.sensor("queue-time");
this.queueTimeSensor.add("record-queue-time-avg",
"The average time in ms record batches spent in the record accumulator.",
new Avg());
this.queueTimeSensor.add("record-queue-time-max",
"The maximum time in ms record batches spent in the record accumulator.",
new Max());
this.requestTimeSensor = metrics.sensor("request-time");
this.requestTimeSensor.add("request-latency-avg", "The average request latency in ms", new Avg()); this.requestTimeSensor.add("request-latency-avg", "The average request latency in ms", new Avg());
this.requestTimeSensor.add("request-latency-max", "The maximum request latency in ms", new Max()); this.requestTimeSensor.add("request-latency-max", "The maximum request latency in ms", new Max());
this.queueTimeSensor.add("record-queue-time-avg",
"The average time in ms record batches spent in the record accumulator.", this.recordsPerRequestSensor = metrics.sensor("records-per-request");
new Avg());
this.queueTimeSensor.add("record-queue-time-max",
"The maximum time in ms record batches spent in the record accumulator.",
new Max());
this.errorSensor.add("record-error-rate", "The average per-second number of record sends that resulted in errors", new Rate());
this.recordsPerRequestSensor.add("record-send-rate", "The average number of records sent per second.", new Rate()); this.recordsPerRequestSensor.add("record-send-rate", "The average number of records sent per second.", new Rate());
this.recordsPerRequestSensor.add("records-per-request-avg", "The average number of records per request.", new Avg()); this.recordsPerRequestSensor.add("records-per-request-avg", "The average number of records per request.", new Avg());
this.retrySensor = metrics.sensor("record-retries");
this.retrySensor.add("record-retry-rate", "The average per-second number of retried record sends", new Rate());
this.errorSensor = metrics.sensor("errors");
this.errorSensor.add("record-error-rate", "The average per-second number of record sends that resulted in errors", new Rate());
this.maxRecordSizeSensor = metrics.sensor("record-size-max");
this.maxRecordSizeSensor.add("record-size-max", "The maximum record size", new Max()); this.maxRecordSizeSensor.add("record-size-max", "The maximum record size", new Max());
this.metrics.addMetric("requests-in-flight", "The current number of in-flight requests awaiting a response.", new Measurable() { this.metrics.addMetric("requests-in-flight", "The current number of in-flight requests awaiting a response.", new Measurable() {
public double measure(MetricConfig config, long now) { public double measure(MetricConfig config, long now) {
return inFlightRequests.totalInFlightRequests(); return inFlightRequests.totalInFlightRequests();
@ -807,32 +815,53 @@ public class Sender implements Runnable {
}); });
} }
public void maybeRegisterTopicMetrics(String topic) {
// if one sensor of the metrics has been registered for the topic,
// then all other sensors should have been registered; and vice versa
String topicRecordsCountName = "topic." + topic + ".records-per-batch";
Sensor topicRecordCount = this.metrics.getSensor(topicRecordsCountName);
if (topicRecordCount == null) {
topicRecordCount = this.metrics.sensor(topicRecordsCountName);
topicRecordCount.add("topic." + topic + ".record-send-rate", new Rate());
String topicByteRateName = "topic." + topic + ".bytes";
Sensor topicByteRate = this.metrics.sensor(topicByteRateName);
topicByteRate.add("topic." + topic + ".byte-rate", new Rate());
String topicRetryName = "topic." + topic + ".record-retries";
Sensor topicRetrySensor = this.metrics.sensor(topicRetryName);
topicRetrySensor.add("topic." + topic + ".record-retry-rate", new Rate());
String topicErrorName = "topic." + topic + ".record-errors";
Sensor topicErrorSensor = this.metrics.sensor(topicErrorName);
topicErrorSensor.add("topic." + topic + ".record-error-rate", new Rate());
}
}
public void updateProduceRequestMetrics(List<InFlightRequest> requests) { public void updateProduceRequestMetrics(List<InFlightRequest> requests) {
long ns = time.nanoseconds(); long ns = time.nanoseconds();
for (int i = 0; i < requests.size(); i++) { for (int i = 0; i < requests.size(); i++) {
InFlightRequest request = requests.get(i); InFlightRequest request = requests.get(i);
int records = 0; int records = 0;
if (request.batches != null) { if (request.batches != null) {
for (RecordBatch batch : request.batches.values()) { for (RecordBatch batch : request.batches.values()) {
// per-topic record count // register all per-topic metrics at once
String topicRecordsCountName = "topic." + batch.topicPartition.topic() + ".records-per-batch"; String topic = batch.topicPartition.topic();
Sensor topicRecordCount = this.metrics.getSensor(topicRecordsCountName); maybeRegisterTopicMetrics(topic);
if (topicRecordCount == null) {
topicRecordCount = this.metrics.sensor(topicRecordsCountName); // per-topic record send rate
topicRecordCount.add("topic." + batch.topicPartition.topic() + ".record-send-rate", new Rate()); String topicRecordsCountName = "topic." + topic + ".records-per-batch";
} Sensor topicRecordCount = Utils.notNull(this.metrics.getSensor(topicRecordsCountName));
topicRecordCount.record(batch.recordCount); topicRecordCount.record(batch.recordCount);
// per-topic bytes-per-second // per-topic bytes send rate
String topicByteRateName = "topic." + batch.topicPartition.topic() + ".bytes"; String topicByteRateName = "topic." + topic + ".bytes";
Sensor topicByteRate = this.metrics.getSensor(topicByteRateName); Sensor topicByteRate = Utils.notNull(this.metrics.getSensor(topicByteRateName));
if (topicByteRate == null) {
topicByteRate = this.metrics.sensor(topicByteRateName);
topicByteRate.add("topic." + batch.topicPartition.topic() + ".byte-rate", new Rate());
}
topicByteRate.record(batch.records.sizeInBytes()); topicByteRate.record(batch.records.sizeInBytes());
// global metrics
this.batchSizeSensor.record(batch.records.sizeInBytes(), ns); this.batchSizeSensor.record(batch.records.sizeInBytes(), ns);
this.queueTimeSensor.record(batch.drained - batch.created, ns); this.queueTimeSensor.record(batch.drained - batch.created, ns);
this.maxRecordSizeSensor.record(batch.maxRecordSize, ns); this.maxRecordSizeSensor.record(batch.maxRecordSize, ns);
@ -847,35 +876,22 @@ public class Sender implements Runnable {
this.retrySensor.record(count); this.retrySensor.record(count);
String topicRetryName = "topic." + topic + ".record-retries"; String topicRetryName = "topic." + topic + ".record-retries";
Sensor topicRetrySensor = this.metrics.getSensor(topicRetryName); Sensor topicRetrySensor = this.metrics.getSensor(topicRetryName);
if (topicRetrySensor == null) { if (topicRetrySensor != null) topicRetrySensor.record(count);
topicRetrySensor = this.metrics.sensor(topicRetryName);
topicRetrySensor.add("topic." + topic + ".record-retry-rate", new Rate());
}
topicRetrySensor.record(count);
} }
public void recordErrors(String topic, int count) { public void recordErrors(String topic, int count) {
this.errorSensor.record(count); this.errorSensor.record(count);
String topicErrorName = "topic." + topic + ".record-errors"; String topicErrorName = "topic." + topic + ".record-errors";
Sensor topicErrorSensor = this.metrics.getSensor(topicErrorName); Sensor topicErrorSensor = this.metrics.getSensor(topicErrorName);
if (topicErrorSensor == null) { if (topicErrorSensor != null) topicErrorSensor.record(count);
topicErrorSensor = this.metrics.sensor(topicErrorName);
topicErrorSensor.add("topic." + topic + ".record-error-rate", new Rate());
}
topicErrorSensor.record(count);
} }
public void recordLatency(int node, long latency, long nowNs) { public void recordLatency(int node, long latency, long nowNs) {
this.requestTimeSensor.record(latency, nowNs); this.requestTimeSensor.record(latency, nowNs);
if (node >= 0) { if (node >= 0) {
String nodeTimeName = "server." + node + ".latency"; String nodeTimeName = "node-" + node + ".latency";
Sensor nodeRequestTime = this.metrics.getSensor(nodeTimeName); Sensor nodeRequestTime = this.metrics.getSensor(nodeTimeName);
if (nodeRequestTime == null) { if (nodeRequestTime != null) nodeRequestTime.record(latency, nowNs);
nodeRequestTime = this.metrics.sensor(nodeTimeName);
nodeRequestTime.add("node-" + node + ".latency-avg", new Avg());
nodeRequestTime.add("node-" + node + ".latency-max", new Max());
}
nodeRequestTime.record(latency, nowNs);
} }
} }
} }

View File

@ -221,6 +221,10 @@ public class Selector implements Selectable {
Transmissions transmissions = transmissions(key); Transmissions transmissions = transmissions(key);
SocketChannel channel = channel(key); SocketChannel channel = channel(key);
// register all per-broker metrics at once
sensors.maybeRegisterNodeMetrics(transmissions.id);
try { try {
/* complete any connections that have finished their handshake */ /* complete any connections that have finished their handshake */
if (key.isConnectable()) { if (key.isConnectable()) {
@ -401,33 +405,41 @@ public class Selector implements Selectable {
public SelectorMetrics(Metrics metrics) { public SelectorMetrics(Metrics metrics) {
this.metrics = metrics; this.metrics = metrics;
this.connectionClosed = this.metrics.sensor("connections-closed"); this.connectionClosed = this.metrics.sensor("connections-closed");
this.connectionClosed.add("connection-close-rate", "Connections closed per second in the window.", new Rate());
this.connectionCreated = this.metrics.sensor("connections-created"); this.connectionCreated = this.metrics.sensor("connections-created");
this.connectionCreated.add("connection-creation-rate", "New connections established per second in the window.", new Rate());
this.bytesTransferred = this.metrics.sensor("bytes-sent-received"); this.bytesTransferred = this.metrics.sensor("bytes-sent-received");
this.bytesSent = this.metrics.sensor("bytes-sent", bytesTransferred);
this.bytesReceived = this.metrics.sensor("bytes-received", bytesTransferred);
this.selectTime = this.metrics.sensor("select-time");
this.ioTime = this.metrics.sensor("io-time");
bytesTransferred.add("network-io-rate", bytesTransferred.add("network-io-rate",
"The average number of network operations (reads or writes) on all connections per second.", "The average number of network operations (reads or writes) on all connections per second.",
new Rate(new Count())); new Rate(new Count()));
this.bytesSent = this.metrics.sensor("bytes-sent", bytesTransferred);
this.bytesSent.add("outgoing-byte-rate", "The average number of outgoing bytes sent per second to all servers.", new Rate()); this.bytesSent.add("outgoing-byte-rate", "The average number of outgoing bytes sent per second to all servers.", new Rate());
this.bytesSent.add("request-rate", "The average number of requests sent per second.", new Rate(new Count())); this.bytesSent.add("request-rate", "The average number of requests sent per second.", new Rate(new Count()));
this.bytesSent.add("request-size-avg", "The average size of all requests in the window..", new Avg()); this.bytesSent.add("request-size-avg", "The average size of all requests in the window..", new Avg());
this.bytesSent.add("request-size-max", "The maximum size of any request sent in the window.", new Max()); this.bytesSent.add("request-size-max", "The maximum size of any request sent in the window.", new Max());
this.bytesReceived = this.metrics.sensor("bytes-received", bytesTransferred);
this.bytesReceived.add("incoming-byte-rate", "Bytes/second read off all sockets", new Rate()); this.bytesReceived.add("incoming-byte-rate", "Bytes/second read off all sockets", new Rate());
this.bytesReceived.add("response-rate", "Responses received sent per second.", new Rate(new Count())); this.bytesReceived.add("response-rate", "Responses received sent per second.", new Rate(new Count()));
this.connectionCreated.add("connection-creation-rate", "New connections established per second in the window.", new Rate());
this.connectionClosed.add("connection-close-rate", "Connections closed per second in the window.", new Rate()); this.selectTime = this.metrics.sensor("select-time");
this.selectTime.add("select-rate", this.selectTime.add("select-rate",
"Number of times the I/O layer checked for new I/O to perform per second", "Number of times the I/O layer checked for new I/O to perform per second",
new Rate(new Count())); new Rate(new Count()));
this.selectTime.add("io-wait-time-ns-avg", this.selectTime.add("io-wait-time-ns-avg",
"The average length of time the I/O thread speant waiting for a socket ready for reads or writes in nanoseconds.", "The average length of time the I/O thread spent waiting for a socket ready for reads or writes in nanoseconds.",
new Avg()); new Avg());
this.selectTime.add("io-wait-ratio", "The fraction of time the I/O thread spent waiting.", new Rate(TimeUnit.NANOSECONDS)); this.selectTime.add("io-wait-ratio", "The fraction of time the I/O thread spent waiting.", new Rate(TimeUnit.NANOSECONDS));
this.ioTime = this.metrics.sensor("io-time");
this.ioTime.add("io-time-ns-avg", "The average length of time for I/O per select call in nanoseconds.", new Avg()); this.ioTime.add("io-time-ns-avg", "The average length of time for I/O per select call in nanoseconds.", new Avg());
this.ioTime.add("io-ratio", "The fraction of time the I/O thread spent doing I/O", new Rate(TimeUnit.NANOSECONDS)); this.ioTime.add("io-ratio", "The fraction of time the I/O thread spent doing I/O", new Rate(TimeUnit.NANOSECONDS));
this.metrics.addMetric("connection-count", "The current number of active connections.", new Measurable() { this.metrics.addMetric("connection-count", "The current number of active connections.", new Measurable() {
public double measure(MetricConfig config, long now) { public double measure(MetricConfig config, long now) {
return keys.size(); return keys.size();
@ -435,35 +447,49 @@ public class Selector implements Selectable {
}); });
} }
public void maybeRegisterNodeMetrics(int node) {
if (node >= 0) {
// if one sensor of the metrics has been registered for the node,
// then all other sensors should have been registered; and vice versa
String nodeRequestName = "node-" + node + ".bytes-sent";
Sensor nodeRequest = this.metrics.getSensor(nodeRequestName);
if (nodeRequest == null) {
nodeRequest = this.metrics.sensor(nodeRequestName);
nodeRequest.add("node-" + node + ".outgoing-byte-rate", new Rate());
nodeRequest.add("node-" + node + ".request-rate", "The average number of requests sent per second.", new Rate(new Count()));
nodeRequest.add("node-" + node + ".request-size-avg", "The average size of all requests in the window..", new Avg());
nodeRequest.add("node-" + node + ".request-size-max", "The maximum size of any request sent in the window.", new Max());
String nodeResponseName = "node-" + node + ".bytes-received";
Sensor nodeResponse = this.metrics.sensor(nodeResponseName);
nodeResponse.add("node-" + node + ".incoming-byte-rate", new Rate());
nodeResponse.add("node-" + node + ".response-rate",
"The average number of responses received per second.",
new Rate(new Count()));
String nodeTimeName = "node-" + node + ".latency";
Sensor nodeRequestTime = this.metrics.sensor(nodeTimeName);
nodeRequestTime.add("node-" + node + ".request-latency-avg", new Avg());
nodeRequestTime.add("node-" + node + ".request-latency-max", new Max());
}
}
}
public void recordBytesSent(int node, int bytes) { public void recordBytesSent(int node, int bytes) {
this.bytesSent.record(bytes); this.bytesSent.record(bytes);
if (node >= 0) { if (node >= 0) {
String name = "node-" + node + ".bytes-sent"; String nodeRequestName = "node-" + node + ".bytes-sent";
Sensor sensor = this.metrics.getSensor(name); Sensor nodeRequest = this.metrics.getSensor(nodeRequestName);
if (sensor == null) { if (nodeRequest != null) nodeRequest.record(bytes);
sensor = this.metrics.sensor(name);
sensor.add("node-" + node + ".outgoing-byte-rate", new Rate());
sensor.add("node-" + node + ".request-rate", "The average number of requests sent per second.", new Rate(new Count()));
sensor.add("node-" + node + ".request-size-avg", "The average size of all requests in the window..", new Avg());
sensor.add("node-" + node + ".request-size-max", "The maximum size of any request sent in the window.", new Max());
}
sensor.record(bytes);
} }
} }
public void recordBytesReceived(int node, int bytes) { public void recordBytesReceived(int node, int bytes) {
this.bytesReceived.record(bytes); this.bytesReceived.record(bytes);
if (node >= 0) { if (node >= 0) {
String name = "node-" + node + ".bytes-received"; String nodeRequestName = "node-" + node + ".bytes-received";
Sensor sensor = this.metrics.getSensor(name); Sensor nodeRequest = this.metrics.getSensor(nodeRequestName);
if (sensor == null) { if (nodeRequest != null) nodeRequest.record(bytes);
sensor = this.metrics.sensor(name);
sensor.add("node-" + node + ".incoming-byte-rate", new Rate());
sensor.add("node-" + node + ".response-rate",
"The average number of responses received per second.",
new Rate(new Count()));
}
sensor.record(bytes);
} }
} }
} }