变更副本

This commit is contained in:
许晓东
2021-11-23 19:59:52 +08:00
parent a219551802
commit 62569c4454
7 changed files with 129 additions and 4 deletions

View File

@@ -16,6 +16,8 @@ public class ReplicaAssignment {
private List<Partition> partitions;
private long interBrokerThrottle = -1;
@Data
static class Partition {
private String topic;

View File

@@ -80,6 +80,6 @@ public class TopicController {
@PostMapping("/replica/assignment")
public Object updateReplicaAssignment(@RequestBody ReplicaAssignment assignment) {
return "topicService.getCurrentReplicaAssignment(topic)";
return topicService.updateReplicaAssignment(assignment);
}
}

View File

@@ -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);
}

View File

@@ -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());
}
}

View File

@@ -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)
}
}

View File

@@ -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">

View File

@@ -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",