变更副本
This commit is contained in:
@@ -16,6 +16,8 @@ public class ReplicaAssignment {
|
||||
|
||||
private List<Partition> partitions;
|
||||
|
||||
private long interBrokerThrottle = -1;
|
||||
|
||||
@Data
|
||||
static class Partition {
|
||||
private String topic;
|
||||
|
||||
@@ -80,6 +80,6 @@ public class TopicController {
|
||||
|
||||
@PostMapping("/replica/assignment")
|
||||
public Object updateReplicaAssignment(@RequestBody ReplicaAssignment assignment) {
|
||||
return "topicService.getCurrentReplicaAssignment(topic)";
|
||||
return topicService.updateReplicaAssignment(assignment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xuxd.kafka.console.service;
|
||||
|
||||
import com.xuxd.kafka.console.beans.ReplicaAssignment;
|
||||
import com.xuxd.kafka.console.beans.ResponseData;
|
||||
import com.xuxd.kafka.console.beans.enums.TopicType;
|
||||
import java.util.List;
|
||||
@@ -28,4 +29,6 @@ public interface TopicService {
|
||||
ResponseData addPartitions(String topic, int addNum, List<List<Integer>> newAssignmentst);
|
||||
|
||||
ResponseData getCurrentReplicaAssignment(String topic);
|
||||
|
||||
ResponseData updateReplicaAssignment(ReplicaAssignment assignment);
|
||||
}
|
||||
|
||||
@@ -142,4 +142,10 @@ public class TopicServiceImpl implements TopicService {
|
||||
|
||||
return success ? ResponseData.create().data(gson.fromJson(tuple2._2(), ReplicaAssignment.class)).success() : ResponseData.create().failed(tuple2._2());
|
||||
}
|
||||
|
||||
@Override public ResponseData updateReplicaAssignment(ReplicaAssignment assignment) {
|
||||
Tuple2<Object, String> tuple2 = topicConsole.updateReplicas(gson.toJson(assignment), assignment.getInterBrokerThrottle());
|
||||
boolean success = (boolean) tuple2._1();
|
||||
return success ? ResponseData.create().success() : ResponseData.create().failed(tuple2._2());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package kafka.console
|
||||
|
||||
import com.xuxd.kafka.console.config.KafkaConfig
|
||||
import kafka.admin.ReassignPartitionsCommand.compareTopicPartitions
|
||||
import kafka.admin.ReassignPartitionsCommand._
|
||||
import kafka.utils.Json
|
||||
import org.apache.kafka.clients.admin._
|
||||
import org.apache.kafka.common.errors.UnknownTopicOrPartitionException
|
||||
import org.apache.kafka.common.utils.Time
|
||||
import org.apache.kafka.common.{TopicPartition, TopicPartitionReplica}
|
||||
|
||||
import java.util
|
||||
@@ -135,6 +136,65 @@ class TopicConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaConfig
|
||||
}).asInstanceOf[(Boolean, String)]
|
||||
}
|
||||
|
||||
def updateReplicas(reassignmentJson: String, interBrokerThrottle: Long = -1L): (Boolean, String) = {
|
||||
withAdminClientAndCatchError(admin => {
|
||||
executeAssignment(admin, reassignmentJson, interBrokerThrottle)
|
||||
(true, "")
|
||||
}, e => {
|
||||
log.error("executeAssignment error, ", e)
|
||||
(false, e.getMessage)
|
||||
}).asInstanceOf[(Boolean, String)]
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and modify from @{link kafka.admin.ReassignPartitionsCommand#executeAssignment}.
|
||||
*/
|
||||
def executeAssignment(adminClient: Admin,
|
||||
reassignmentJson: String,
|
||||
interBrokerThrottle: Long = -1L,
|
||||
logDirThrottle: Long = -1L,
|
||||
timeoutMs: Long = 30000L,
|
||||
time: Time = Time.SYSTEM): Unit = {
|
||||
val (proposedParts, proposedReplicas) = parseExecuteAssignmentArgs(reassignmentJson)
|
||||
val currentReassignments = adminClient.
|
||||
listPartitionReassignments().reassignments().get().asScala
|
||||
// If there is an existing assignment
|
||||
// This helps avoid surprising users.
|
||||
if (currentReassignments.nonEmpty) {
|
||||
throw new TerseReassignmentFailureException("Cannot execute because there is an existing partition assignment.")
|
||||
}
|
||||
verifyBrokerIds(adminClient, proposedParts.values.flatten.toSet)
|
||||
val currentParts = getReplicaAssignmentForPartitions(adminClient, proposedParts.keySet.toSet)
|
||||
log.info("currentPartitionReplicaAssignment: " + currentPartitionReplicaAssignmentToString(proposedParts, currentParts))
|
||||
log.info(s"newPartitionReplicaAssignment: $reassignmentJson")
|
||||
|
||||
if (interBrokerThrottle >= 0 || logDirThrottle >= 0) {
|
||||
|
||||
if (interBrokerThrottle >= 0) {
|
||||
val moveMap = calculateProposedMoveMap(currentReassignments, proposedParts, currentParts)
|
||||
modifyReassignmentThrottle(adminClient, moveMap, interBrokerThrottle)
|
||||
}
|
||||
|
||||
if (logDirThrottle >= 0) {
|
||||
val movingBrokers = calculateMovingBrokers(proposedReplicas.keySet.toSet)
|
||||
modifyLogDirThrottle(adminClient, movingBrokers, logDirThrottle)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the partition reassignments.
|
||||
val errors = alterPartitionReassignments(adminClient, proposedParts)
|
||||
if (errors.nonEmpty) {
|
||||
throw new TerseReassignmentFailureException(
|
||||
"Error reassigning partition(s):%n%s".format(
|
||||
errors.keySet.toBuffer.sortWith(compareTopicPartitions).map { part =>
|
||||
s"$part: ${errors(part).getMessage}"
|
||||
}.mkString(System.lineSeparator())))
|
||||
}
|
||||
if (proposedReplicas.nonEmpty) {
|
||||
executeMoves(adminClient, proposedReplicas, timeoutMs, time)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current replica assignments for some topics.
|
||||
*
|
||||
@@ -181,4 +241,13 @@ class TopicConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def modifyReassignmentThrottle(admin: Admin, moveMap: MoveMap, interBrokerThrottle: Long): Unit = {
|
||||
val leaderThrottles = calculateLeaderThrottles(moveMap)
|
||||
val followerThrottles = calculateFollowerThrottles(moveMap)
|
||||
modifyTopicThrottles(admin, leaderThrottles, followerThrottles)
|
||||
|
||||
// val reassigningBrokers = calculateReassigningBrokers(moveMap)
|
||||
// modifyInterBrokerThrottle(admin, reassigningBrokers, interBrokerThrottle)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="content-module">
|
||||
<a-card title="Broker管理" style="width: 100%; text-align: left">
|
||||
<p>
|
||||
<a-button type="primary"> 配置限流 </a-button>
|
||||
<label>说明:</label>
|
||||
<span
|
||||
>设置指定broker上的topic的副本之间数据同步占用的带宽,这个设置是broker级别的,但是设置后还要去对应的topic上进行限流配置,指定对这个topic的相关副本进行限制</span
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<a-button type="primary"> 解除限流 </a-button>
|
||||
<label>说明:</label>
|
||||
<span>解除指定broker上的topic副本之间数据同步占用的带宽限制</span>
|
||||
</p>
|
||||
</a-card>
|
||||
</div>
|
||||
<div class="content-module">
|
||||
<a-card title="副本管理" style="width: 100%; text-align: left">
|
||||
<p>
|
||||
@@ -9,6 +25,11 @@
|
||||
<label>说明:</label>
|
||||
<span>将集群中所有分区leader副本设置为首选副本</span>
|
||||
</p>
|
||||
<p>
|
||||
<a-button type="primary"> 副本变更详情 </a-button>
|
||||
<label>说明:</label>
|
||||
<span>查看正在进行副本变更/重分配的任务,或者将其取消</span>
|
||||
</p>
|
||||
</a-card>
|
||||
</div>
|
||||
<div class="content-module">
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div>
|
||||
<a-spin :spinning="loading">
|
||||
<div class="replica-box">
|
||||
<label>副本数:</label
|
||||
<label>设置副本数:</label
|
||||
><a-input-number
|
||||
id="inputNumber"
|
||||
v-model="replicaNums"
|
||||
@@ -23,6 +23,19 @@
|
||||
@change="onChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="replica-box">
|
||||
<label>是否要限流:</label
|
||||
><a-input-number
|
||||
id="inputNumber"
|
||||
v-model="data.interBrokerThrottle"
|
||||
:min="-1"
|
||||
:max="102400"
|
||||
/>
|
||||
<strong>
|
||||
|说明:broker之间副本同步带宽限制,默认值为-1表示不限制,不是-1表示限制,该值并不表示流速,至于流速配置,在
|
||||
<span style="color: red">运维->配置限流</span> 处进行操作.</strong
|
||||
>
|
||||
</div>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="data.partitions"
|
||||
@@ -39,6 +52,11 @@
|
||||
</span>
|
||||
</div>
|
||||
</a-table>
|
||||
<p>
|
||||
*正在进行即尚未完成的副本变更的任务,可以在
|
||||
<span style="color: red">运维->副本变更详情</span>
|
||||
处查看,也可以在那里将正在进行的任务取消。
|
||||
</p>
|
||||
</a-spin>
|
||||
</div>
|
||||
</a-modal>
|
||||
@@ -121,6 +139,9 @@ export default {
|
||||
this.$emit("closeUpdateReplicaDialog", { refresh: false });
|
||||
},
|
||||
onChange(value) {
|
||||
if (value < 1 || value > this.brokerSize) {
|
||||
return false;
|
||||
}
|
||||
if (this.data.partitions.length > 0) {
|
||||
this.data.partitions.forEach((p) => {
|
||||
if (value > p.replicas.length) {
|
||||
@@ -130,7 +151,9 @@ export default {
|
||||
}
|
||||
}
|
||||
if (value < p.replicas.length) {
|
||||
p.replicas.pop();
|
||||
for (let i = p.replicas.length; i > value; i--) {
|
||||
p.replicas.pop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -145,6 +168,7 @@ export default {
|
||||
this.loading = false;
|
||||
if (res.code == 0) {
|
||||
this.$message.success(res.msg);
|
||||
this.$emit("closeUpdateReplicaDialog", { refresh: false });
|
||||
} else {
|
||||
notification.error({
|
||||
message: "error",
|
||||
|
||||
Reference in New Issue
Block a user