use of com.github.df.restypass.lb.server.ServerInstance in project RestyPass by darren-fu.
the class RoundRobinLoadBalancer method doChoose.
@Override
protected ServerInstance doChoose(List<ServerInstance> instanceList, RestyCommand command) {
String key = command.getServiceName() + "." + command.getPath();
// 总个数
int length = instanceList.size();
// 最大权重
int maxWeight = 0;
// 最小权重
int minWeight = Integer.MAX_VALUE;
final LinkedHashMap<ServerInstance, IntegerWrapper> invokerToWeightMap = new LinkedHashMap();
int weightSum = 0;
for (int i = 0; i < length; i++) {
int weight = getWeight(instanceList.get(i));
// 累计最大权重
maxWeight = Math.max(maxWeight, weight);
// 累计最小权重
minWeight = Math.min(minWeight, weight);
if (weight > 0) {
invokerToWeightMap.put(instanceList.get(i), new IntegerWrapper(weight));
weightSum += weight;
}
}
AtomicPositiveInteger sequence = sequences.get(key);
if (sequence == null) {
sequences.putIfAbsent(key, new AtomicPositiveInteger());
sequence = sequences.get(key);
}
int currentSequence = sequence.getAndIncrement();
if (maxWeight > 0 && minWeight < maxWeight) {
// 权重不一样
int mod = currentSequence % weightSum;
for (int i = 0; i < maxWeight; i++) {
for (Map.Entry<ServerInstance, IntegerWrapper> each : invokerToWeightMap.entrySet()) {
final ServerInstance instance = each.getKey();
final IntegerWrapper weight = each.getValue();
if (mod == 0 && weight.getValue() > 0) {
return instance;
}
if (weight.getValue() > 0) {
weight.decrement();
mod--;
}
}
}
}
// 取模轮循
return instanceList.get(currentSequence % length);
}
use of com.github.df.restypass.lb.server.ServerInstance in project RestyPass by darren-fu.
the class RestyCommandExecutor method execute.
@Override
public Object execute(LoadBalancer lb, RestyCommand restyCommand) throws RestyException {
if (restyCommand.getRestyCommandConfig().isForceBreakEnabled()) {
throw new CircuitBreakException("circuit breaker is forced to open");
}
// 重试次数
int retry = restyCommand.getRestyCommandConfig().getRetry();
Object result = null;
CircuitBreaker circuitBreaker = CircuitBreakerFactory.createDefaultCircuitBreaker(restyCommand.getServiceName());
// RestyCommand ready to start
restyCommand.ready(circuitBreaker);
// 排除 彻底断路的server, 尝试过的server
// 1.判断command使用的serverInstanceList是否存在被熔断的server
// 1.1 存在的话 server加入 loadBalance 的excludeServerList
Set<String> excludeInstanceIdSet = circuitBreaker.getBrokenServer();
// 负载均衡器 选择可用服务实例
ServerInstance serverInstance = lb.choose(serverContext, restyCommand, excludeInstanceIdSet);
if (serverInstance == null) {
throw new RuntimeException("no instances found:" + restyCommand.getServiceName() + ":" + serverContext.getServerList(restyCommand.getServiceName()));
}
// 重试机制
for (int times = 0; times <= retry; times++) {
try {
boolean shouldPass = circuitBreaker.shouldPass(restyCommand, serverInstance);
if (!shouldPass) {
// fallback or exception
throw new CircuitBreakException("circuit breaker is open");
}
RestyFuture future = restyCommand.start(serverInstance);
RestyFuture futureArg = getFutureArg(restyCommand);
if (restyCommand.isAsyncArg()) {
// 直接返回null, 结果放入出参RestyFuture中
return null;
}
if (restyCommand.isAsyncReturn()) {
// 返回RestyFuture
return future;
}
// 同步调用
result = future.get();
if (restyCommand.getStatus() == RestyCommandStatus.FAILED) {
throw restyCommand.getFailException();
}
if (restyCommand.getStatus() == RestyCommandStatus.SUCCESS) {
// 响应成功,无需重试了
break;
}
} catch (Exception ex) {
if (times == retry) {
throw ex;
} else {
// 将本次使用的server 加入排除列表
if (excludeInstanceIdSet == null || excludeInstanceIdSet == Collections.EMPTY_SET) {
excludeInstanceIdSet = new HashSet<>();
}
if (serverInstance != null) {
excludeInstanceIdSet.add(serverInstance.getInstanceId());
}
// 选择server, 如果没有server可选则无需重试,直接抛出当前异常
serverInstance = lb.choose(serverContext, restyCommand, excludeInstanceIdSet);
if (serverInstance == null || excludeInstanceIdSet.contains(serverInstance.getInstanceId())) {
throw ex;
} else if (log.isDebugEnabled()) {
log.debug("请求切换服务实例重试:{}", serverInstance);
}
}
}
}
return result;
}
use of com.github.df.restypass.lb.server.ServerInstance in project RestyPass by darren-fu.
the class AbstractLoadBalancer method choose.
@Override
public ServerInstance choose(ServerContext context, RestyCommand command, Set<String> excludeInstanceIdSet) {
if (context == null || command == null || StringUtils.isEmpty(command.getServiceName())) {
return null;
}
List<ServerInstance> serverList = context.getServerList(command.getServiceName());
if (serverList == null || serverList.size() == 0) {
return null;
}
List<ServerInstance> usableServerList = new LinkedList();
// 移除未初始化完成或当前状态未存活,版本不匹配,已排除的实例
for (ServerInstance instance : serverList) {
if (instance.isReady() && instance.getIsAlive() && isVersionOk(command, instance) && !shouldExcludeInstance(excludeInstanceIdSet, instance)) {
usableServerList.add(instance);
} else {
if (log.isTraceEnabled()) {
log.trace("剔除本次不可使用的server实例:{}", instance);
}
}
}
if (CommonTools.isEmpty(usableServerList)) {
return null;
}
// 只有一个实例,直接返回,忽视排除的实例ID
if (usableServerList.size() == 1) {
return usableServerList.get(0);
}
return doChoose(usableServerList, command);
}
use of com.github.df.restypass.lb.server.ServerInstance in project RestyPass by darren-fu.
the class VersionRule method onServerInstanceUpdateEvent.
/**
* 服务实例刷新触发此事件,重新计算版本匹配结果
*
* @see ServerInstance#ready()
*/
private void onServerInstanceUpdateEvent() {
this.on(getEventKey(), (instance) -> {
if (instance != null && instance instanceof ServerInstance) {
ServerInstance serverInstance = (ServerInstance) instance;
versionMatchMap.put(serverInstance.getVersionInfo().getId(), this.doMath(serverInstance.getVersionInfo()));
}
});
}
Aggregations