Topic -> 消费详情

This commit is contained in:
许晓东
2021-11-02 17:12:35 +08:00
parent 73080f7eb1
commit 0eb7c273cc
7 changed files with 315 additions and 1 deletions

View File

@@ -116,4 +116,9 @@ public class ConsumerController {
public Object getSubscribeTopicList(@RequestParam String groupId) {
return consumerService.getSubscribeTopicList(groupId);
}
@GetMapping("/topic/subscribed")
public Object getTopicSubscribedByGroups(@RequestParam String topic) {
return consumerService.getTopicSubscribedByGroups(topic);
}
}

View File

@@ -32,4 +32,6 @@ public interface ConsumerService {
ResponseData getGroupIdList();
ResponseData getSubscribeTopicList(String groupId);
ResponseData getTopicSubscribedByGroups(String topic);
}

View File

@@ -38,6 +38,8 @@ public class ConsumerServiceImpl implements ConsumerService {
@Autowired
private ConsumerConsole consumerConsole;
private TopicSubscribedInfo topicSubscribedInfo = new TopicSubscribedInfo();
@Override public ResponseData getConsumerGroupList(List<String> groupIds, Set<ConsumerGroupState> states) {
String simulateGroup = "inner_xxx_not_exit_group_###" + System.currentTimeMillis();
Set<String> groupList = new HashSet<>();
@@ -142,4 +144,63 @@ public class ConsumerServiceImpl implements ConsumerService {
@Override public ResponseData getSubscribeTopicList(String groupId) {
return ResponseData.create().data(consumerConsole.listSubscribeTopics(groupId).keySet()).success();
}
@Override public ResponseData getTopicSubscribedByGroups(String topic) {
if (topicSubscribedInfo.isNeedRefresh(topic)) {
Set<String> groupIdList = consumerConsole.getConsumerGroupIdList(Collections.emptySet());
Map<String, Set<String>> cache = new HashMap<>();
Map<String, List<TopicPartition>> subscribeTopics = consumerConsole.listSubscribeTopics(groupIdList);
subscribeTopics.forEach((groupId, tl) -> {
tl.forEach(topicPartition -> {
String t = topicPartition.topic();
if (!cache.containsKey(t)) {
cache.put(t, new HashSet<>());
}
cache.get(t).add(groupId);
});
});
topicSubscribedInfo.refresh(cache);
}
Set<String> groups = topicSubscribedInfo.getSubscribedGroups(topic);
Map<String, Object> res = new HashMap<>();
Collection<ConsumerConsole.TopicPartitionConsumeInfo> consumerDetail = consumerConsole.getConsumerDetail(groups);
List<ConsumerDetailVO> collect = consumerDetail.stream().filter(c -> topic.equals(c.topicPartition().topic())).map(ConsumerDetailVO::from).collect(Collectors.toList());
Map<String, List<ConsumerDetailVO>> map = collect.stream().collect(Collectors.groupingBy(ConsumerDetailVO::getGroupId));
map.forEach((groupId, list) -> {
Map<String, Object> sorting = new HashMap<>();
Collections.sort(list);
sorting.put("data", list);
sorting.put("lag", list.stream().map(ConsumerDetailVO::getLag).reduce(Long::sum));
res.put(groupId, sorting);
});
return ResponseData.create().data(res).success();
}
class TopicSubscribedInfo {
long lastTime = System.currentTimeMillis();
long refreshThreshold = 120 * 1000;
Map<String, Set<String>> cache = new HashMap<>();
public void refresh(Map<String, Set<String>> newCache) {
cache = newCache;
lastTime = System.currentTimeMillis();
}
public Set<String> getSubscribedGroups(String topic) {
return cache.getOrDefault(topic, Collections.emptySet());
}
public boolean isNeedRefresh(String topic) {
return System.currentTimeMillis() - lastTime > refreshThreshold || !cache.containsKey(topic);
}
}
}

View File

@@ -173,6 +173,10 @@ class ConsumerConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaCon
}).asInstanceOf[(Boolean, String)]
}
/**
*
* @return k: topic, v: list[topic].
*/
def listSubscribeTopics(groupId: String): util.Map[String, util.List[TopicPartition]] = {
val commitOffs = getCommittedOffsets(groupId)
val map: util.Map[String, util.List[TopicPartition]] = new util.HashMap[String, util.List[TopicPartition]]()
@@ -185,6 +189,32 @@ class ConsumerConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaCon
map
}
/**
*
* @return k: groupId, v: list[topic].
*/
def listSubscribeTopics(groups: util.Set[String]): util.Map[String, util.List[TopicPartition]] = {
val map: util.Map[String, util.List[TopicPartition]] = new util.HashMap[String, util.List[TopicPartition]]()
withAdminClientAndCatchError(admin => {
for(groupId <- groups.asScala) {
val commitOffs = admin.listConsumerGroupOffsets(
groupId
).partitionsToOffsetAndMetadata.get.asScala
for (t <- commitOffs.keySet) {
if (!map.containsKey(groupId)) {
map.put(groupId, new util.ArrayList[TopicPartition]())
}
map.get(groupId).add(t)
}
}
map
}, e => {
log.error("listSubscribeTopics error.", e)
map
}).asInstanceOf[util.Map[String, util.List[TopicPartition]]]
}
private def describeConsumerGroups(groupIds: util.Set[String]): mutable.Map[String, ConsumerGroupDescription] = {
withAdminClientAndCatchError(admin => {
admin.describeConsumerGroups(groupIds).describedGroups().asScala.map {