60
60
import org .apache .kafka .server .util .timer .SystemTimer ;
61
61
import org .apache .kafka .server .util .timer .SystemTimerReaper ;
62
62
import org .apache .kafka .server .util .timer .Timer ;
63
+ import org .apache .kafka .storage .log .metrics .BrokerTopicStats ;
63
64
64
65
import org .slf4j .Logger ;
65
66
import org .slf4j .LoggerFactory ;
68
69
import java .util .Collection ;
69
70
import java .util .Collections ;
70
71
import java .util .HashMap ;
72
+ import java .util .HashSet ;
71
73
import java .util .LinkedHashMap ;
72
74
import java .util .List ;
73
75
import java .util .Map ;
74
76
import java .util .Objects ;
77
+ import java .util .Optional ;
78
+ import java .util .Set ;
75
79
import java .util .concurrent .CompletableFuture ;
76
80
import java .util .concurrent .ConcurrentHashMap ;
77
81
import java .util .function .BiConsumer ;
82
+ import java .util .function .Consumer ;
78
83
79
84
/**
80
85
* The SharePartitionManager is responsible for managing the SharePartitions and ShareSessions.
@@ -140,6 +145,11 @@ public class SharePartitionManager implements AutoCloseable {
140
145
*/
141
146
private final ShareGroupMetrics shareGroupMetrics ;
142
147
148
+ /**
149
+ * The broker topic stats is used to record the broker topic metrics for share group.
150
+ */
151
+ private final BrokerTopicStats brokerTopicStats ;
152
+
143
153
/**
144
154
* The max fetch records is the maximum number of records that can be fetched by a share fetch request.
145
155
*/
@@ -155,7 +165,8 @@ public SharePartitionManager(
155
165
int maxFetchRecords ,
156
166
Persister persister ,
157
167
GroupConfigManager groupConfigManager ,
158
- Metrics metrics
168
+ Metrics metrics ,
169
+ BrokerTopicStats brokerTopicStats
159
170
) {
160
171
this (replicaManager ,
161
172
time ,
@@ -167,7 +178,8 @@ public SharePartitionManager(
167
178
maxFetchRecords ,
168
179
persister ,
169
180
groupConfigManager ,
170
- metrics
181
+ metrics ,
182
+ brokerTopicStats
171
183
);
172
184
}
173
185
@@ -182,7 +194,8 @@ private SharePartitionManager(
182
194
int maxFetchRecords ,
183
195
Persister persister ,
184
196
GroupConfigManager groupConfigManager ,
185
- Metrics metrics
197
+ Metrics metrics ,
198
+ BrokerTopicStats brokerTopicStats
186
199
) {
187
200
this (replicaManager ,
188
201
time ,
@@ -196,7 +209,8 @@ private SharePartitionManager(
196
209
maxFetchRecords ,
197
210
persister ,
198
211
groupConfigManager ,
199
- metrics
212
+ metrics ,
213
+ brokerTopicStats
200
214
);
201
215
}
202
216
@@ -213,7 +227,8 @@ private SharePartitionManager(
213
227
int maxFetchRecords ,
214
228
Persister persister ,
215
229
GroupConfigManager groupConfigManager ,
216
- Metrics metrics
230
+ Metrics metrics ,
231
+ BrokerTopicStats brokerTopicStats
217
232
) {
218
233
this .replicaManager = replicaManager ;
219
234
this .time = time ;
@@ -227,6 +242,7 @@ private SharePartitionManager(
227
242
this .groupConfigManager = groupConfigManager ;
228
243
this .shareGroupMetrics = new ShareGroupMetrics (Objects .requireNonNull (metrics ), time );
229
244
this .maxFetchRecords = maxFetchRecords ;
245
+ this .brokerTopicStats = brokerTopicStats ;
230
246
}
231
247
232
248
/**
@@ -252,7 +268,7 @@ public CompletableFuture<Map<TopicIdPartition, PartitionData>> fetchMessages(
252
268
partitionMaxBytes .keySet (), groupId , fetchParams );
253
269
254
270
CompletableFuture <Map <TopicIdPartition , PartitionData >> future = new CompletableFuture <>();
255
- processShareFetch (new ShareFetch (fetchParams , groupId , memberId , future , partitionMaxBytes , batchSize , maxFetchRecords ));
271
+ processShareFetch (new ShareFetch (fetchParams , groupId , memberId , future , partitionMaxBytes , batchSize , maxFetchRecords , brokerTopicStats ));
256
272
257
273
return future ;
258
274
}
@@ -274,9 +290,11 @@ public CompletableFuture<Map<TopicIdPartition, ShareAcknowledgeResponseData.Part
274
290
) {
275
291
log .trace ("Acknowledge request for topicIdPartitions: {} with groupId: {}" ,
276
292
acknowledgeTopics .keySet (), groupId );
277
- this .shareGroupMetrics .shareAcknowledgement ();
278
293
Map <TopicIdPartition , CompletableFuture <Throwable >> futures = new HashMap <>();
294
+ // Track the topics for which we have received an acknowledgement for metrics.
295
+ Set <String > topics = new HashSet <>();
279
296
acknowledgeTopics .forEach ((topicIdPartition , acknowledgePartitionBatches ) -> {
297
+ topics .add (topicIdPartition .topic ());
280
298
SharePartitionKey sharePartitionKey = sharePartitionKey (groupId , topicIdPartition );
281
299
SharePartition sharePartition = partitionCacheMap .get (sharePartitionKey );
282
300
if (sharePartition != null ) {
@@ -302,7 +320,13 @@ public CompletableFuture<Map<TopicIdPartition, ShareAcknowledgeResponseData.Part
302
320
}
303
321
});
304
322
305
- return mapAcknowledgementFutures (futures );
323
+ // Update the metrics for the topics for which we have received an acknowledgement.
324
+ topics .forEach (topic -> {
325
+ brokerTopicStats .allTopicsStats ().totalShareAcknowledgementRequestRate ().mark ();
326
+ brokerTopicStats .topicStats (topic ).totalShareAcknowledgementRequestRate ().mark ();
327
+ });
328
+
329
+ return mapAcknowledgementFutures (futures , Optional .of (failedShareAcknowledgeMetricsHandler ()));
306
330
}
307
331
308
332
/**
@@ -363,24 +387,31 @@ public CompletableFuture<Map<TopicIdPartition, ShareAcknowledgeResponseData.Part
363
387
}
364
388
});
365
389
366
- return mapAcknowledgementFutures (futuresMap );
390
+ return mapAcknowledgementFutures (futuresMap , Optional . empty () );
367
391
}
368
392
369
- private CompletableFuture <Map <TopicIdPartition , ShareAcknowledgeResponseData .PartitionData >> mapAcknowledgementFutures (Map <TopicIdPartition , CompletableFuture <Throwable >> futuresMap ) {
393
+ private CompletableFuture <Map <TopicIdPartition , ShareAcknowledgeResponseData .PartitionData >> mapAcknowledgementFutures (
394
+ Map <TopicIdPartition , CompletableFuture <Throwable >> futuresMap ,
395
+ Optional <Consumer <Set <String >>> failedMetricsHandler
396
+ ) {
370
397
CompletableFuture <Void > allFutures = CompletableFuture .allOf (
371
398
futuresMap .values ().toArray (new CompletableFuture [0 ]));
372
399
return allFutures .thenApply (v -> {
373
400
Map <TopicIdPartition , ShareAcknowledgeResponseData .PartitionData > result = new HashMap <>();
401
+ // Keep the set as same topic might appear multiple times. Multiple partitions can fail for same topic.
402
+ Set <String > failedTopics = new HashSet <>();
374
403
futuresMap .forEach ((topicIdPartition , future ) -> {
375
404
ShareAcknowledgeResponseData .PartitionData partitionData = new ShareAcknowledgeResponseData .PartitionData ()
376
405
.setPartitionIndex (topicIdPartition .partition ());
377
406
Throwable t = future .join ();
378
407
if (t != null ) {
379
408
partitionData .setErrorCode (Errors .forException (t ).code ())
380
409
.setErrorMessage (t .getMessage ());
410
+ failedTopics .add (topicIdPartition .topic ());
381
411
}
382
412
result .put (topicIdPartition , partitionData );
383
413
});
414
+ failedMetricsHandler .ifPresent (handler -> handler .accept (failedTopics ));
384
415
return result ;
385
416
});
386
417
}
@@ -554,7 +585,10 @@ void processShareFetch(ShareFetch shareFetch) {
554
585
555
586
List <DelayedShareFetchKey > delayedShareFetchWatchKeys = new ArrayList <>();
556
587
LinkedHashMap <TopicIdPartition , SharePartition > sharePartitions = new LinkedHashMap <>();
588
+ // Track the topics for which we have received a share fetch request for metrics.
589
+ Set <String > topics = new HashSet <>();
557
590
for (TopicIdPartition topicIdPartition : shareFetch .partitionMaxBytes ().keySet ()) {
591
+ topics .add (topicIdPartition .topic ());
558
592
SharePartitionKey sharePartitionKey = sharePartitionKey (
559
593
shareFetch .groupId (),
560
594
topicIdPartition
@@ -598,6 +632,12 @@ void processShareFetch(ShareFetch shareFetch) {
598
632
sharePartitions .put (topicIdPartition , sharePartition );
599
633
}
600
634
635
+ // Update the metrics for the topics for which we have received a share fetch request.
636
+ topics .forEach (topic -> {
637
+ brokerTopicStats .allTopicsStats ().totalShareFetchRequestRate ().mark ();
638
+ brokerTopicStats .topicStats (topic ).totalShareFetchRequestRate ().mark ();
639
+ });
640
+
601
641
// If all the partitions in the request errored out, then complete the fetch request with an exception.
602
642
if (shareFetch .errorInAllPartitions ()) {
603
643
shareFetch .maybeComplete (Collections .emptyMap ());
@@ -695,6 +735,21 @@ private static void removeSharePartitionFromCache(
695
735
}
696
736
}
697
737
738
+ /**
739
+ * The handler to update the failed share acknowledge request metrics.
740
+ *
741
+ * @return A Consumer that updates the failed share acknowledge request metrics.
742
+ */
743
+ private Consumer <Set <String >> failedShareAcknowledgeMetricsHandler () {
744
+ return failedTopics -> {
745
+ // Update failed share acknowledge request metric.
746
+ failedTopics .forEach (topic -> {
747
+ brokerTopicStats .allTopicsStats ().failedShareAcknowledgementRequestRate ().mark ();
748
+ brokerTopicStats .topicStats (topic ).failedShareAcknowledgementRequestRate ().mark ();
749
+ });
750
+ };
751
+ }
752
+
698
753
/**
699
754
* The SharePartitionListener is used to listen for partition events. The share partition is associated with
700
755
* the topic-partition, we need to handle the partition events for the share partition.
@@ -759,10 +814,6 @@ static class ShareGroupMetrics {
759
814
760
815
public static final String METRICS_GROUP_NAME = "share-group-metrics" ;
761
816
762
- public static final String SHARE_ACK_SENSOR = "share-acknowledgement-sensor" ;
763
- public static final String SHARE_ACK_RATE = "share-acknowledgement-rate" ;
764
- public static final String SHARE_ACK_COUNT = "share-acknowledgement-count" ;
765
-
766
817
public static final String RECORD_ACK_SENSOR_PREFIX = "record-acknowledgement" ;
767
818
public static final String RECORD_ACK_RATE = "record-acknowledgement-rate" ;
768
819
public static final String RECORD_ACK_COUNT = "record-acknowledgement-count" ;
@@ -775,7 +826,6 @@ static class ShareGroupMetrics {
775
826
public static final Map <Byte , String > RECORD_ACKS_MAP = new HashMap <>();
776
827
777
828
private final Time time ;
778
- private final Sensor shareAcknowledgementSensor ;
779
829
private final Map <Byte , Sensor > recordAcksSensorMap = new HashMap <>();
780
830
private final Sensor partitionLoadTimeSensor ;
781
831
@@ -787,18 +837,6 @@ static class ShareGroupMetrics {
787
837
788
838
public ShareGroupMetrics (Metrics metrics , Time time ) {
789
839
this .time = time ;
790
-
791
- shareAcknowledgementSensor = metrics .sensor (SHARE_ACK_SENSOR );
792
- shareAcknowledgementSensor .add (new Meter (
793
- metrics .metricName (
794
- SHARE_ACK_RATE ,
795
- METRICS_GROUP_NAME ,
796
- "Rate of acknowledge requests." ),
797
- metrics .metricName (
798
- SHARE_ACK_COUNT ,
799
- METRICS_GROUP_NAME ,
800
- "The number of acknowledge requests." )));
801
-
802
840
for (Map .Entry <Byte , String > entry : RECORD_ACKS_MAP .entrySet ()) {
803
841
recordAcksSensorMap .put (entry .getKey (), metrics .sensor (String .format ("%s-%s-sensor" , RECORD_ACK_SENSOR_PREFIX , entry .getValue ())));
804
842
recordAcksSensorMap .get (entry .getKey ())
@@ -828,10 +866,6 @@ public ShareGroupMetrics(Metrics metrics, Time time) {
828
866
new Max ());
829
867
}
830
868
831
- void shareAcknowledgement () {
832
- shareAcknowledgementSensor .record ();
833
- }
834
-
835
869
void recordAcknowledgement (byte ackType ) {
836
870
// unknown ack types (such as gaps for control records) are intentionally ignored
837
871
if (recordAcksSensorMap .containsKey (ackType )) {
0 commit comments