Search in sources :

Example 1 with ServerInstance

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);
}
Also used : AtomicPositiveInteger(com.github.df.restypass.util.AtomicPositiveInteger) ServerInstance(com.github.df.restypass.lb.server.ServerInstance) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) LinkedHashMap(java.util.LinkedHashMap)

Example 2 with ServerInstance

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;
}
Also used : CircuitBreaker(com.github.df.restypass.cb.CircuitBreaker) RestyFuture(com.github.df.restypass.command.RestyFuture) CircuitBreakException(com.github.df.restypass.exception.execute.CircuitBreakException) ServerInstance(com.github.df.restypass.lb.server.ServerInstance) CircuitBreakException(com.github.df.restypass.exception.execute.CircuitBreakException) RestyException(com.github.df.restypass.exception.execute.RestyException) ExecutionException(java.util.concurrent.ExecutionException) HashSet(java.util.HashSet)

Example 3 with ServerInstance

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);
}
Also used : ServerInstance(com.github.df.restypass.lb.server.ServerInstance)

Example 4 with ServerInstance

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()));
        }
    });
}
Also used : ServerInstance(com.github.df.restypass.lb.server.ServerInstance)

Aggregations

ServerInstance (com.github.df.restypass.lb.server.ServerInstance)4 CircuitBreaker (com.github.df.restypass.cb.CircuitBreaker)1 RestyFuture (com.github.df.restypass.command.RestyFuture)1 CircuitBreakException (com.github.df.restypass.exception.execute.CircuitBreakException)1 RestyException (com.github.df.restypass.exception.execute.RestyException)1 AtomicPositiveInteger (com.github.df.restypass.util.AtomicPositiveInteger)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 Map (java.util.Map)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ExecutionException (java.util.concurrent.ExecutionException)1