按时间查询消息及时释放内存
This commit is contained in:
@@ -8,7 +8,7 @@ import java.time.Duration
|
|||||||
import java.util
|
import java.util
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
import scala.jdk.CollectionConverters.{CollectionHasAsScala, MapHasAsScala}
|
import scala.jdk.CollectionConverters.{CollectionHasAsScala, MapHasAsScala, SeqHasAsJava}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kafka-console-ui.
|
* kafka-console-ui.
|
||||||
@@ -60,20 +60,48 @@ class MessageConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaConf
|
|||||||
} else {
|
} else {
|
||||||
for ((tp, endOff) <- endOffTable) {
|
for ((tp, endOff) <- endOffTable) {
|
||||||
if (!terminate) {
|
if (!terminate) {
|
||||||
val recordList = records.records(tp)
|
var recordList = records.records(tp)
|
||||||
if (!recordList.isEmpty) {
|
if (!recordList.isEmpty) {
|
||||||
val first = recordList.get(0)
|
val first = recordList.get(0)
|
||||||
if (first.offset() >= endOff) {
|
if (first.offset() >= endOff) {
|
||||||
arrive.remove(tp)
|
arrive.remove(tp)
|
||||||
} else {
|
} else {
|
||||||
res.addAll(recordList)
|
//
|
||||||
|
// (String topic,
|
||||||
|
// int partition,
|
||||||
|
// long offset,
|
||||||
|
// long timestamp,
|
||||||
|
// TimestampType timestampType,
|
||||||
|
// Long checksum,
|
||||||
|
// int serializedKeySize,
|
||||||
|
// int serializedValueSize,
|
||||||
|
// K key,
|
||||||
|
// V value,
|
||||||
|
// Headers headers,
|
||||||
|
// Optional<Integer> leaderEpoch)
|
||||||
|
val nullVList = recordList.asScala.map(record => new ConsumerRecord[Array[Byte], Array[Byte]](record.topic(),
|
||||||
|
record.partition(),
|
||||||
|
record.offset(),
|
||||||
|
record.timestamp(),
|
||||||
|
record.timestampType(),
|
||||||
|
record.checksum(),
|
||||||
|
record.serializedKeySize(),
|
||||||
|
record.serializedValueSize(),
|
||||||
|
record.key(),
|
||||||
|
null,
|
||||||
|
record.headers(),
|
||||||
|
record.leaderEpoch())).toSeq.asJava
|
||||||
|
res.addAll(nullVList)
|
||||||
if (recordList.get(recordList.size() - 1).offset() >= endOff) {
|
if (recordList.get(recordList.size() - 1).offset() >= endOff) {
|
||||||
arrive.remove(tp)
|
arrive.remove(tp)
|
||||||
}
|
}
|
||||||
|
if (recordList != null) {
|
||||||
|
recordList = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (arrive.isEmpty) {
|
if (arrive.isEmpty) {
|
||||||
terminate = true;
|
terminate = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
<a-tab-pane key="1" tab="根据时间查询消息">
|
<a-tab-pane key="1" tab="根据时间查询消息">
|
||||||
<SearchByTime :topic-list="topicList"></SearchByTime>
|
<SearchByTime :topic-list="topicList"></SearchByTime>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane key="2" tab="根据偏移查询消息" force-render>
|
<a-tab-pane key="2" tab="根据偏移查询消息">
|
||||||
<SearchByOffset :topic-list="topicList"></SearchByOffset>
|
<SearchByOffset :topic-list="topicList"></SearchByOffset>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<!-- <a-tab-pane key="3" tab="消息发送"> 消息发送1 </a-tab-pane>-->
|
<a-tab-pane key="3" tab="在线发送">
|
||||||
|
<SendMessage :topic-list="topicList"></SendMessage>
|
||||||
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,9 +22,10 @@ import SearchByOffset from "@/views/message/SearchByOffset";
|
|||||||
import request from "@/utils/request";
|
import request from "@/utils/request";
|
||||||
import { KafkaTopicApi } from "@/utils/api";
|
import { KafkaTopicApi } from "@/utils/api";
|
||||||
import notification from "ant-design-vue/lib/notification";
|
import notification from "ant-design-vue/lib/notification";
|
||||||
|
import SendMessage from "@/views/message/SendMessage";
|
||||||
export default {
|
export default {
|
||||||
name: "Message",
|
name: "Message",
|
||||||
components: { SearchByTime, SearchByOffset },
|
components: { SearchByTime, SearchByOffset, SendMessage },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<a-spin :spinning="loading">
|
<a-spin :spinning="loading">
|
||||||
<div id="components-form-advanced-search">
|
<div id="search-offset-form-advanced-search">
|
||||||
<a-form
|
<a-form
|
||||||
class="ant-advanced-search-form"
|
class="ant-advanced-search-form"
|
||||||
:form="form"
|
:form="form"
|
||||||
@@ -87,7 +87,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
form: this.$form.createForm(this, { name: "message_search_time" }),
|
form: this.$form.createForm(this, { name: "message_search_offset" }),
|
||||||
partitions: [],
|
partitions: [],
|
||||||
selectPartition: undefined,
|
selectPartition: undefined,
|
||||||
rangeConfig: {
|
rangeConfig: {
|
||||||
@@ -97,7 +97,8 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSearch() {
|
handleSearch(e) {
|
||||||
|
e.preventDefault();
|
||||||
this.form.validateFields((err, values) => {
|
this.form.validateFields((err, values) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
const data = Object.assign({}, values, {
|
const data = Object.assign({}, values, {
|
||||||
@@ -176,7 +177,7 @@ const defaultData = [];
|
|||||||
margin-bottom: 1%;
|
margin-bottom: 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#components-form-advanced-search .search-result-list {
|
#search-offset-form-advanced-search .search-result-list {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
border: 1px dashed #e9e9e9;
|
border: 1px dashed #e9e9e9;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<a-spin :spinning="loading">
|
<a-spin :spinning="loading">
|
||||||
<div id="components-form-advanced-search">
|
<div id="search-time-form-advanced-search">
|
||||||
<a-form
|
<a-form
|
||||||
class="ant-advanced-search-form"
|
class="ant-advanced-search-form"
|
||||||
:form="form"
|
:form="form"
|
||||||
@@ -100,7 +100,8 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSearch() {
|
handleSearch(e) {
|
||||||
|
e.preventDefault();
|
||||||
this.form.validateFields((err, values) => {
|
this.form.validateFields((err, values) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
const data = Object.assign({}, values, {
|
const data = Object.assign({}, values, {
|
||||||
@@ -181,7 +182,7 @@ const defaultData = { realNum: 0, maxNum: 0 };
|
|||||||
margin-bottom: 1%;
|
margin-bottom: 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#components-form-advanced-search .search-result-list {
|
#search-time-form-advanced-search .search-result-list {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
border: 1px dashed #e9e9e9;
|
border: 1px dashed #e9e9e9;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|||||||
144
ui/src/views/message/SendMessage.vue
Normal file
144
ui/src/views/message/SendMessage.vue
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<a-form :form="form">
|
||||||
|
<a-form-item label="Topic">
|
||||||
|
<a-select
|
||||||
|
class="topic-select"
|
||||||
|
@change="handleTopicChange"
|
||||||
|
show-search
|
||||||
|
option-filter-prop="children"
|
||||||
|
v-decorator="[
|
||||||
|
'topic',
|
||||||
|
{
|
||||||
|
rules: [{ required: true, message: '请选择一个topic!' }],
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
placeholder="请选择一个topic"
|
||||||
|
>
|
||||||
|
<a-select-option v-for="v in topicList" :key="v" :value="v">
|
||||||
|
{{ v }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="分区">
|
||||||
|
<a-select
|
||||||
|
class="type-select"
|
||||||
|
show-search
|
||||||
|
option-filter-prop="children"
|
||||||
|
v-model="selectPartition"
|
||||||
|
placeholder="请选择一个分区"
|
||||||
|
>
|
||||||
|
<a-select-option v-for="v in partitions" :key="v" :value="v">
|
||||||
|
<span v-if="v == -1">默认</span> <span v-else>{{ v }}</span>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="消息Key">
|
||||||
|
<a-input v-decorator="['key', { initialValue: 'key' }]" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="消息体" has-feedback>
|
||||||
|
<a-input
|
||||||
|
v-decorator="[
|
||||||
|
'body',
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '输入消息体!',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
placeholder="输入消息体!"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="发送的消息数">
|
||||||
|
<a-input-number
|
||||||
|
v-decorator="[
|
||||||
|
'nums',
|
||||||
|
{
|
||||||
|
initialValue: 1,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '输入消息数!',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:min="1"
|
||||||
|
:max="32"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-spin>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import request from "@/utils/request";
|
||||||
|
import { KafkaTopicApi } from "@/utils/api";
|
||||||
|
import notification from "ant-design-vue/lib/notification";
|
||||||
|
export default {
|
||||||
|
name: "SendMessage",
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
topicList: {
|
||||||
|
type: Array,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: this.$form.createForm(this, { name: "message_send" }),
|
||||||
|
loading: false,
|
||||||
|
partitions: [],
|
||||||
|
selectPartition: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getTopicNameList() {
|
||||||
|
request({
|
||||||
|
url: KafkaTopicApi.getTopicNameList.url,
|
||||||
|
method: KafkaTopicApi.getTopicNameList.method,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
this.topicList = res.data;
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: "error",
|
||||||
|
description: res.msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getPartitionInfo(topic) {
|
||||||
|
this.loading = true;
|
||||||
|
request({
|
||||||
|
url: KafkaTopicApi.getPartitionInfo.url + "?topic=" + topic,
|
||||||
|
method: KafkaTopicApi.getPartitionInfo.method,
|
||||||
|
}).then((res) => {
|
||||||
|
this.loading = false;
|
||||||
|
if (res.code != 0) {
|
||||||
|
notification.error({
|
||||||
|
message: "error",
|
||||||
|
description: res.msg,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.partitions = res.data.map((v) => v.partition);
|
||||||
|
this.partitions.splice(0, 0, -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleTopicChange(topic) {
|
||||||
|
this.selectPartition = -1;
|
||||||
|
this.getPartitionInfo(topic);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getTopicNameList();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
Reference in New Issue
Block a user