org.apache.rocketmq.controller.impl.manager.RaftReplicasInfoManager Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.controller.impl.manager;
import com.alibaba.fastjson.JSON;
import org.apache.rocketmq.common.ControllerConfig;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.controller.helper.BrokerValidPredicate;
import org.apache.rocketmq.controller.impl.event.ControllerResult;
import org.apache.rocketmq.controller.impl.heartbeat.BrokerIdentityInfo;
import org.apache.rocketmq.controller.impl.heartbeat.BrokerLiveInfo;
import org.apache.rocketmq.controller.impl.task.BrokerCloseChannelRequest;
import org.apache.rocketmq.controller.impl.task.BrokerCloseChannelResponse;
import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerRequest;
import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerResponse;
import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoRequest;
import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoResponse;
import org.apache.rocketmq.controller.impl.task.RaftBrokerHeartBeatEventRequest;
import org.apache.rocketmq.controller.impl.task.RaftBrokerHeartBeatEventResponse;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class RaftReplicasInfoManager extends ReplicasInfoManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.CONTROLLER_LOGGER_NAME);
private final Map brokerLiveTable = new ConcurrentHashMap<>(256);
public RaftReplicasInfoManager(ControllerConfig controllerConfig) {
super(controllerConfig);
}
public ControllerResult getBrokerLiveInfo(final GetBrokerLiveInfoRequest request) {
BrokerIdentityInfo brokerIdentityInfo = request.getBrokerIdentity();
ControllerResult result = new ControllerResult<>(new GetBrokerLiveInfoResponse());
Map resBrokerLiveTable = new HashMap<>();
if (brokerIdentityInfo == null || brokerIdentityInfo.isEmpty()) {
resBrokerLiveTable.putAll(this.brokerLiveTable);
} else {
if (brokerLiveTable.containsKey(brokerIdentityInfo)) {
resBrokerLiveTable.put(brokerIdentityInfo, brokerLiveTable.get(brokerIdentityInfo));
} else {
log.warn("GetBrokerLiveInfo failed, brokerIdentityInfo: {} not exist", brokerIdentityInfo);
result.setCodeAndRemark(ResponseCode.CONTROLLER_BROKER_LIVE_INFO_NOT_EXISTS, "brokerIdentityInfo not exist");
}
}
try {
result.setBody(JSON.toJSONBytes(resBrokerLiveTable));
} catch (Throwable e) {
log.error("json serialize resBrokerLiveTable {} error", resBrokerLiveTable, e);
result.setCodeAndRemark(ResponseCode.SYSTEM_ERROR, "serialize error");
}
return result;
}
public ControllerResult onBrokerHeartBeat(
RaftBrokerHeartBeatEventRequest request) {
BrokerIdentityInfo brokerIdentityInfo = request.getBrokerIdentityInfo();
BrokerLiveInfo brokerLiveInfo = request.getBrokerLiveInfo();
ControllerResult result = new ControllerResult<>(new RaftBrokerHeartBeatEventResponse());
BrokerLiveInfo prev = brokerLiveTable.computeIfAbsent(brokerIdentityInfo, identityInfo -> {
log.info("new broker registered, brokerIdentityInfo: {}", identityInfo);
return brokerLiveInfo;
});
prev.setLastUpdateTimestamp(brokerLiveInfo.getLastUpdateTimestamp());
prev.setHeartbeatTimeoutMillis(brokerLiveInfo.getHeartbeatTimeoutMillis());
prev.setElectionPriority(brokerLiveInfo.getElectionPriority());
if (brokerLiveInfo.getEpoch() > prev.getEpoch() || brokerLiveInfo.getEpoch() == prev.getEpoch() && brokerLiveInfo.getMaxOffset() > prev.getMaxOffset()) {
prev.setEpoch(brokerLiveInfo.getEpoch());
prev.setMaxOffset(brokerLiveInfo.getMaxOffset());
prev.setConfirmOffset(brokerLiveInfo.getConfirmOffset());
}
return result;
}
public ControllerResult onBrokerCloseChannel(BrokerCloseChannelRequest request) {
BrokerIdentityInfo brokerIdentityInfo = request.getBrokerIdentityInfo();
ControllerResult result = new ControllerResult<>(new BrokerCloseChannelResponse());
if (brokerIdentityInfo == null || brokerIdentityInfo.isEmpty()) {
log.warn("onBrokerCloseChannel failed, brokerIdentityInfo is null");
} else {
brokerLiveTable.remove(brokerIdentityInfo);
log.info("onBrokerCloseChannel success, brokerIdentityInfo: {}", brokerIdentityInfo);
}
return result;
}
public ControllerResult checkNotActiveBroker(CheckNotActiveBrokerRequest request) {
List notActiveBrokerIdentityInfoList = new ArrayList<>();
long checkTime = request.getCheckTimeMillis();
final Iterator> iterator = this.brokerLiveTable.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry next = iterator.next();
long last = next.getValue().getLastUpdateTimestamp();
long timeoutMillis = next.getValue().getHeartbeatTimeoutMillis();
if (checkTime - last > timeoutMillis) {
notActiveBrokerIdentityInfoList.add(next.getKey());
iterator.remove();
log.warn("Broker expired, brokerInfo {}, expired {}ms", next.getKey(), timeoutMillis);
}
}
List needReElectBrokerNames = scanNeedReelectBrokerSets(new BrokerValidPredicate() {
@Override
public boolean check(String clusterName, String brokerName, Long brokerId) {
return !isBrokerActive(clusterName, brokerName, brokerId, checkTime);
}
});
Set alreadyReportedBrokerName = notActiveBrokerIdentityInfoList.stream()
.map(BrokerIdentityInfo::getBrokerName)
.collect(Collectors.toSet());
// avoid to duplicate report, filter by name,
// because BrokerIdentityInfo in needReElectBrokerNames does not have brokerId or clusterName
notActiveBrokerIdentityInfoList.addAll(needReElectBrokerNames.stream()
.filter(brokerName -> !alreadyReportedBrokerName.contains(brokerName))
.map(brokerName -> new BrokerIdentityInfo(null, brokerName, null))
.collect(Collectors.toList()));
ControllerResult result = new ControllerResult<>(new CheckNotActiveBrokerResponse());
try {
result.setBody(JSON.toJSONBytes(notActiveBrokerIdentityInfoList));
} catch (Throwable e) {
log.error("json serialize notActiveBrokerIdentityInfoList {} error", notActiveBrokerIdentityInfoList, e);
result.setCodeAndRemark(ResponseCode.SYSTEM_ERROR, "serialize error");
}
return result;
}
public boolean isBrokerActive(String clusterName, String brokerName, Long brokerId, long invokeTime) {
final BrokerLiveInfo info = this.brokerLiveTable.get(new BrokerIdentityInfo(clusterName, brokerName, brokerId));
if (info != null) {
long last = info.getLastUpdateTimestamp();
long timeoutMillis = info.getHeartbeatTimeoutMillis();
return (last + timeoutMillis) >= invokeTime;
}
return false;
}
public BrokerLiveInfo getBrokerLiveInfo(String clusterName, String brokerName, Long brokerId) {
return this.brokerLiveTable.get(new BrokerIdentityInfo(clusterName, brokerName, brokerId));
}
@Override
public byte[] serialize() throws Throwable {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
final byte[] superSerialize = super.serialize();
putInt(outputStream, superSerialize.length);
outputStream.write(superSerialize);
putInt(outputStream, this.brokerLiveTable.size());
for (Map.Entry entry : brokerLiveTable.entrySet()) {
final byte[] brokerIdentityInfo = hessianSerialize(entry.getKey());
final byte[] brokerLiveInfo = hessianSerialize(entry.getValue());
putInt(outputStream, brokerIdentityInfo.length);
outputStream.write(brokerIdentityInfo);
putInt(outputStream, brokerLiveInfo.length);
outputStream.write(brokerLiveInfo);
}
return outputStream.toByteArray();
} catch (Throwable e) {
log.error("serialize replicaInfoTable or syncStateSetInfoTable error", e);
throw e;
}
}
@Override
public void deserializeFrom(byte[] data) throws Throwable {
int index = 0;
this.brokerLiveTable.clear();
try {
int superTableSize = getInt(data, index);
index += 4;
byte[] superTableData = new byte[superTableSize];
System.arraycopy(data, index, superTableData, 0, superTableSize);
super.deserializeFrom(superTableData);
index += superTableSize;
int brokerLiveTableSize = getInt(data, index);
index += 4;
for (int i = 0; i < brokerLiveTableSize; i++) {
int brokerIdentityInfoLength = getInt(data, index);
index += 4;
byte[] brokerIdentityInfoArray = new byte[brokerIdentityInfoLength];
System.arraycopy(data, index, brokerIdentityInfoArray, 0, brokerIdentityInfoLength);
BrokerIdentityInfo brokerIdentityInfo = (BrokerIdentityInfo) hessianDeserialize(brokerIdentityInfoArray);
index += brokerIdentityInfoLength;
int brokerLiveInfoLength = getInt(data, index);
index += 4;
byte[] brokerLiveInfoArray = new byte[brokerLiveInfoLength];
System.arraycopy(data, index, brokerLiveInfoArray, 0, brokerLiveInfoLength);
BrokerLiveInfo brokerLiveInfo = (BrokerLiveInfo) hessianDeserialize(brokerLiveInfoArray);
index += brokerLiveInfoLength;
this.brokerLiveTable.put(brokerIdentityInfo, brokerLiveInfo);
}
} catch (Throwable e) {
log.error("deserialize replicaInfoTable or syncStateSetInfoTable error", e);
throw e;
}
}
public static class BrokerValidPredicateWithInvokeTime implements BrokerValidPredicate {
private final long invokeTime;
private final RaftReplicasInfoManager raftBrokerHeartBeatManager;
public BrokerValidPredicateWithInvokeTime(long invokeTime, RaftReplicasInfoManager raftBrokerHeartBeatManager) {
this.invokeTime = invokeTime;
this.raftBrokerHeartBeatManager = raftBrokerHeartBeatManager;
}
@Override
public boolean check(String clusterName, String brokerName, Long brokerId) {
return raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId, invokeTime);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy