github.com/kaituanwang/hyperledger@v2.0.1+incompatible/orderer/consensus/kafka/metrics.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package kafka 8 9 import ( 10 "strings" 11 "time" 12 13 "github.com/hyperledger/fabric/common/metrics" 14 15 gometrics "github.com/rcrowley/go-metrics" 16 ) 17 18 /* 19 20 Per the documentation at: https://godoc.org/github.com/Shopify/sarama Sarama exposes the following set of metrics: 21 22 +----------------------------------------------+------------+---------------------------------------------------------------+ 23 | Name | Type | Description | 24 +----------------------------------------------+------------+---------------------------------------------------------------+ 25 | incoming-byte-rate | meter | Bytes/second read off all brokers | 26 | incoming-byte-rate-for-broker-<broker-id> | meter | Bytes/second read off a given broker | 27 | outgoing-byte-rate | meter | Bytes/second written off all brokers | 28 | outgoing-byte-rate-for-broker-<broker-id> | meter | Bytes/second written off a given broker | 29 | request-rate | meter | Requests/second sent to all brokers | 30 | request-rate-for-broker-<broker-id> | meter | Requests/second sent to a given broker | 31 | request-size | histogram | Distribution of the request size in bytes for all brokers | 32 | request-size-for-broker-<broker-id> | histogram | Distribution of the request size in bytes for a given broker | 33 | request-latency-in-ms | histogram | Distribution of the request latency in ms for all brokers | 34 | request-latency-in-ms-for-broker-<broker-id> | histogram | Distribution of the request latency in ms for a given broker | 35 | response-rate | meter | Responses/second received from all brokers | 36 | response-rate-for-broker-<broker-id> | meter | Responses/second received from a given broker | 37 | response-size | histogram | Distribution of the response size in bytes for all brokers | 38 | response-size-for-broker-<broker-id> | histogram | Distribution of the response size in bytes for a given broker | 39 +----------------------------------------------+------------+---------------------------------------------------------------+ 40 41 +-------------------------------------------+------------+--------------------------------------------------------------------------------------+ 42 | Name | Type | Description | 43 +-------------------------------------------+------------+--------------------------------------------------------------------------------------+ 44 | batch-size | histogram | Distribution of the number of bytes sent per partition per request for all topics | 45 | batch-size-for-topic-<topic> | histogram | Distribution of the number of bytes sent per partition per request for a given topic | 46 | record-send-rate | meter | Records/second sent to all topics | 47 | record-send-rate-for-topic-<topic> | meter | Records/second sent to a given topic | 48 | records-per-request | histogram | Distribution of the number of records sent per request for all topics | 49 | records-per-request-for-topic-<topic> | histogram | Distribution of the number of records sent per request for a given topic | 50 | compression-ratio | histogram | Distribution of the compression ratio times 100 of record batches for all topics | 51 | compression-ratio-for-topic-<topic> | histogram | Distribution of the compression ratio times 100 of record batches for a given topic | 52 +-------------------------------------------+------------+--------------------------------------------------------------------------------------+ 53 */ 54 55 const ( 56 IncomingByteRateName = "incoming-byte-rate-for-broker-" 57 OutgoingByteRateName = "outgoing-byte-rate-for-broker-" 58 RequestRateName = "request-rate-for-broker-" 59 RequestSizeName = "request-size-for-broker-" 60 RequestLatencyName = "request-latency-in-ms-for-broker-" 61 ResponseRateName = "response-rate-for-broker-" 62 ResponseSizeName = "response-size-for-broker-" 63 BatchSizeName = "batch-size-for-topic-" 64 RecordSendRateName = "record-send-rate-for-topic-" 65 RecordsPerRequestName = "records-per-request-for-topic-" 66 CompressionRatioName = "compression-ratio-for-topic-" 67 ) 68 69 var ( 70 incomingByteRate = metrics.GaugeOpts{ 71 Namespace: "consensus", 72 Subsystem: "kafka", 73 Name: "incoming_byte_rate", 74 Help: "Bytes/second read off brokers.", 75 LabelNames: []string{"broker_id"}, 76 StatsdFormat: "%{#fqname}.%{broker_id}", 77 } 78 79 outgoingByteRate = metrics.GaugeOpts{ 80 Namespace: "consensus", 81 Subsystem: "kafka", 82 Name: "outgoing_byte_rate", 83 Help: "Bytes/second written to brokers.", 84 LabelNames: []string{"broker_id"}, 85 StatsdFormat: "%{#fqname}.%{broker_id}", 86 } 87 88 requestRate = metrics.GaugeOpts{ 89 Namespace: "consensus", 90 Subsystem: "kafka", 91 Name: "request_rate", 92 Help: "Requests/second sent to brokers.", 93 LabelNames: []string{"broker_id"}, 94 StatsdFormat: "%{#fqname}.%{broker_id}", 95 } 96 97 requestSize = metrics.GaugeOpts{ 98 Namespace: "consensus", 99 Subsystem: "kafka", 100 Name: "request_size", 101 Help: "The mean request size in bytes to brokers.", 102 LabelNames: []string{"broker_id"}, 103 StatsdFormat: "%{#fqname}.%{broker_id}", 104 } 105 106 requestLatency = metrics.GaugeOpts{ 107 Namespace: "consensus", 108 Subsystem: "kafka", 109 Name: "request_latency", 110 Help: "The mean request latency in ms to brokers.", 111 LabelNames: []string{"broker_id"}, 112 StatsdFormat: "%{#fqname}.%{broker_id}", 113 } 114 115 responseRate = metrics.GaugeOpts{ 116 Namespace: "consensus", 117 Subsystem: "kafka", 118 Name: "response_rate", 119 Help: "Requests/second sent to brokers.", 120 LabelNames: []string{"broker_id"}, 121 StatsdFormat: "%{#fqname}.%{broker_id}", 122 } 123 124 responseSize = metrics.GaugeOpts{ 125 Namespace: "consensus", 126 Subsystem: "kafka", 127 Name: "response_size", 128 Help: "The mean response size in bytes from brokers.", 129 LabelNames: []string{"broker_id"}, 130 StatsdFormat: "%{#fqname}.%{broker_id}", 131 } 132 133 batchSize = metrics.GaugeOpts{ 134 Namespace: "consensus", 135 Subsystem: "kafka", 136 Name: "batch_size", 137 Help: "The mean batch size in bytes sent to topics.", 138 LabelNames: []string{"topic"}, 139 StatsdFormat: "%{#fqname}.%{topic}", 140 } 141 142 recordSendRate = metrics.GaugeOpts{ 143 Namespace: "consensus", 144 Subsystem: "kafka", 145 Name: "record_send_rate", 146 Help: "The number of records per second sent to topics.", 147 LabelNames: []string{"topic"}, 148 StatsdFormat: "%{#fqname}.%{topic}", 149 } 150 151 recordsPerRequest = metrics.GaugeOpts{ 152 Namespace: "consensus", 153 Subsystem: "kafka", 154 Name: "records_per_request", 155 Help: "The mean number of records sent per request to topics.", 156 LabelNames: []string{"topic"}, 157 StatsdFormat: "%{#fqname}.%{topic}", 158 } 159 160 compressionRatio = metrics.GaugeOpts{ 161 Namespace: "consensus", 162 Subsystem: "kafka", 163 Name: "compression_ratio", 164 Help: "The mean compression ratio (as percentage) for topics.", 165 LabelNames: []string{"topic"}, 166 StatsdFormat: "%{#fqname}.%{topic}", 167 } 168 169 lastOffsetPersisted = metrics.GaugeOpts{ 170 Namespace: "consensus", 171 Subsystem: "kafka", 172 Name: "last_offset_persisted", 173 Help: "The offset specified in the block metadata of the most recently committed block.", 174 LabelNames: []string{"channel"}, 175 StatsdFormat: "%{#fqname}.%{channel}", 176 } 177 ) 178 179 type Metrics struct { 180 // The first set of metrics are all reported by Sarama 181 IncomingByteRate metrics.Gauge 182 OutgoingByteRate metrics.Gauge 183 RequestRate metrics.Gauge 184 RequestSize metrics.Gauge 185 RequestLatency metrics.Gauge 186 ResponseRate metrics.Gauge 187 ResponseSize metrics.Gauge 188 BatchSize metrics.Gauge 189 RecordSendRate metrics.Gauge 190 RecordsPerRequest metrics.Gauge 191 CompressionRatio metrics.Gauge 192 193 GoMetricsRegistry gometrics.Registry 194 195 // LastPersistedOffset is reported by the Fabric/Kafka integration 196 LastOffsetPersisted metrics.Gauge 197 } 198 199 func NewMetrics(p metrics.Provider, registry gometrics.Registry) *Metrics { 200 return &Metrics{ 201 IncomingByteRate: p.NewGauge(incomingByteRate), 202 OutgoingByteRate: p.NewGauge(outgoingByteRate), 203 RequestRate: p.NewGauge(requestRate), 204 RequestSize: p.NewGauge(requestSize), 205 RequestLatency: p.NewGauge(requestLatency), 206 ResponseRate: p.NewGauge(responseRate), 207 ResponseSize: p.NewGauge(responseSize), 208 BatchSize: p.NewGauge(batchSize), 209 RecordSendRate: p.NewGauge(recordSendRate), 210 RecordsPerRequest: p.NewGauge(recordsPerRequest), 211 CompressionRatio: p.NewGauge(compressionRatio), 212 213 GoMetricsRegistry: registry, 214 215 LastOffsetPersisted: p.NewGauge(lastOffsetPersisted), 216 } 217 } 218 219 // PollGoMetrics takes the current metric values from go-metrics and publishes them to 220 // the gauges exposed through go-kit's metrics. 221 func (m *Metrics) PollGoMetrics() { 222 m.GoMetricsRegistry.Each(func(name string, value interface{}) { 223 recordMeter := func(prefix, label string, gauge metrics.Gauge) bool { 224 if !strings.HasPrefix(name, prefix) { 225 return false 226 } 227 228 meter, ok := value.(gometrics.Meter) 229 if !ok { 230 logger.Panicf("Expected metric with name %s to be of type Meter but was of type %T", name, value) 231 } 232 233 labelValue := name[len(prefix):] 234 gauge.With(label, labelValue).Set(meter.Snapshot().Rate1()) 235 236 return true 237 } 238 239 recordHistogram := func(prefix, label string, gauge metrics.Gauge) bool { 240 if !strings.HasPrefix(name, prefix) { 241 return false 242 } 243 244 histogram, ok := value.(gometrics.Histogram) 245 if !ok { 246 logger.Panicf("Expected metric with name %s to be of type Histogram but was of type %T", name, value) 247 } 248 249 labelValue := name[len(prefix):] 250 gauge.With(label, labelValue).Set(histogram.Snapshot().Mean()) 251 252 return true 253 } 254 255 switch { 256 case recordMeter(IncomingByteRateName, "broker_id", m.IncomingByteRate): 257 case recordMeter(OutgoingByteRateName, "broker_id", m.OutgoingByteRate): 258 case recordMeter(RequestRateName, "broker_id", m.RequestRate): 259 case recordHistogram(RequestSizeName, "broker_id", m.RequestSize): 260 case recordHistogram(RequestLatencyName, "broker_id", m.RequestLatency): 261 case recordMeter(ResponseRateName, "broker_id", m.ResponseRate): 262 case recordHistogram(ResponseSizeName, "broker_id", m.ResponseSize): 263 case recordHistogram(BatchSizeName, "topic", m.BatchSize): 264 case recordMeter(RecordSendRateName, "topic", m.RecordSendRate): 265 case recordHistogram(RecordsPerRequestName, "topic", m.RecordsPerRequest): 266 case recordHistogram(CompressionRatioName, "topic", m.CompressionRatio): 267 default: 268 // Ignore unknown metrics 269 } 270 }) 271 } 272 273 // PollGoMetricsUntilStop should generally be invoked on a dedicated go routine. This go routine 274 // will then invoke PollGoMetrics at the specified frequency until the stopChannel closes. 275 func (m *Metrics) PollGoMetricsUntilStop(frequency time.Duration, stopChannel <-chan struct{}) { 276 timer := time.NewTimer(frequency) 277 defer timer.Stop() 278 for { 279 select { 280 case <-timer.C: 281 m.PollGoMetrics() 282 timer.Reset(frequency) 283 case <-stopChannel: 284 return 285 } 286 } 287 }