Ribbon负载均衡 算法

1.Ribbon 简介

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为。为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多的负载均衡算法,例如轮询、随机等。当然,我们也可以为Ribbon实现自定义的负载均衡算法。
在这里插入图片描述
a. RoundRobinRule
默认的,轮询规则,也是很多高级规则中退避的一种策略
BaseLoadBalancer类中的setRule方法
在这里插入图片描述

b. AvailabilityFilteringRule
会过滤掉打开熔断的服务或者是高并发连接数量的服务

c. WeightedResponseTimeRule
通过服务的平均响应时间,给每一个服务一个权重,响应时间越长,权重越小,开始统计信息不足,应用轮询策略

// 开启权重配置
spring-cloud-order-service.ribbon.NFLoadBalancerRuleClassName=com.gupaoedu.springcloud.example.springclouduserservice.GpDefineIpHashRule

在这里插入图片描述

d. RetryRule
先按照轮询策略,如果请求服务失败,会在指定时间内(30s)进行重试

e. BestAvailableRule
先过滤掉断路器的服务,然后选择一个并发量最小的

f. RandomRule
随机获取一个服务

2. RoundRobinRule 轮询

 public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();
            List<Server> allServers = lb.getAllServers();
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount);
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

3.RandomRule 随机

 /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }

            int index = chooseRandomInt(serverCount);
            server = upList.get(index);

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

4.RetryRule 重试

默认先使用轮训算法(IRule subRule = new RoundRobinRule()),再使用重试算法;
默认0.5s重试一次(long maxRetryMillis = 500)

package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;

public class RetryRule extends AbstractLoadBalancerRule {
	IRule subRule = new RoundRobinRule();
	long maxRetryMillis = 500;

	public RetryRule() {
	}

	public RetryRule(IRule subRule) {
		this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
	}

	public RetryRule(IRule subRule, long maxRetryMillis) {
		this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
		this.maxRetryMillis = (maxRetryMillis > 0) ? maxRetryMillis : 500;
	}

	public void setRule(IRule subRule) {
		this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
	}
	public IRule getRule() {
		return subRule;
	}
	public void setMaxRetryMillis(long maxRetryMillis) {
		if (maxRetryMillis > 0) {
			this.maxRetryMillis = maxRetryMillis;
		} else {
			this.maxRetryMillis = 500;
		}
	}
	public long getMaxRetryMillis() {
		return maxRetryMillis;
	}
	@Override
	public void setLoadBalancer(ILoadBalancer lb) {		
		super.setLoadBalancer(lb);
		subRule.setLoadBalancer(lb);
	}
	/*
	 * Loop if necessary. Note that the time CAN be exceeded depending on the
	 * subRule, because we're not spawning additional threads and returning
	 * early.
	 */
	 //具体重试代码
	public Server choose(ILoadBalancer lb, Object key) {
		long requestTime = System.currentTimeMillis();
		long deadline = requestTime + maxRetryMillis;
		Server answer = null;
		answer = subRule.choose(key);

		if (((answer == null) || (!answer.isAlive()))
				&& (System.currentTimeMillis() < deadline)) {

			InterruptTask task = new InterruptTask(deadline
					- System.currentTimeMillis());
			while (!Thread.interrupted()) {
				answer = subRule.choose(key);

				if (((answer == null) || (!answer.isAlive()))
						&& (System.currentTimeMillis() < deadline)) {
					/* pause and retry hoping it's transient */
					Thread.yield();
				} else {
					break;
				}
			}
			task.cancel();
		}

		if ((answer == null) || (!answer.isAlive())) {
			return null;
		} else {
			return answer;
		}
	}
	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}
	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
	}
}

5.自定义的负载均衡算法

根据ip的hash获取访问地址

package com.example.demo;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.List;

/**
 * 自定义根据IP的hash值取模访问服务提供者集群
 */
public class CustomizeIpHashRule extends AbstractLoadBalancerRule {

  public Server choose(ILoadBalancer lb,Object key){
      if (lb==null){
          return null;
      }else {
          Server server = null;
          while (server==null){
              //获取可用的服务实例列表
              List<Server> upList = lb.getReachableServers();
              //获取所有的服务实例列表
              List<Server> allList = lb.getAllServers();
              int serverCount = allList.size();
              if(serverCount == 0){
                  return null;
              }
               int i=ipAddressHash(serverCount);
               server = upList.get(i);
          }
          return  server;
      }

  }

    private int ipAddressHash(int serverCount) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String remoteAddr = requestAttributes.getRequest().getRemoteAddr();
        int code = Math.abs(remoteAddr.hashCode());
        return code%serverCount;

    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }
    
    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(),key);
    }

}

6. 配置负载均衡算法引用

spring.application.name=eureka-user-service

server.port=8081
eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka

#命名规则: 服务提供者[applicationName].ribbon.NFLoadBalancerRuleClassName= 引用 负载均衡算法 路径
#eureka-product-service.ribbon.NFLoadBalancerRuleClassName = com.netflix.loadbalancer.RandomRule
#自定义负载均衡算法引用
eureka-product-service.ribbon.NFLoadBalancerRuleClassName=com.example.demo.CustomizeIpHashRule

#clientName.ribbon.NFLoadBalancerClass; #配置ILoadBalancer的实现类
#lientName.ribbon.NFLoadBalancerRuleClassName; #配置IRule的实现类
#clientName.ribbon.NFLoadBalancerPingClassName; #配置IPing的实现类
#clientName.ribbon.NFWSServerListClassName;  配置ServerList的实现类
#clientName.ribbon.NIWSServerListFilterClassName; 配置ServerListFilter的实现类

ping服务器(默认10s),比重试retry30秒要快

import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.Server;


public class MyPing implements IPing{

    @Override
    public boolean isAlive(Server server) {
        System.out.println("isAlive"+server.getHost()+":"+server.getPort());
        return true;
    }
}
spring.application.name=spring-cloud-user-service

management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always


# spring cloud access&secret config
# 可以访问如下地址查看: https://usercenter.console.aliyun.com/#/manage/ak
alibaba.cloud.access-key=****
alibaba.cloud.secret-key=****

# 应用服务 WEB 访问端口
server.port=8088

# 配置指定服务的提供者的地址列表
spring-cloud-order-service.ribbon.listOfServers=\
  localhost:8080,localhost:8082

//ping 服务器配置
spring-cloud-order-service.ribbon.NFLoadBalancerPingClassName=com.gupaoedu.springcloud.example.springclouduserservice.MyPing

spring-cloud-order-service.ribbon.NFLoadBalancerRuleClassName=com.gupaoedu.springcloud.example.springclouduserservice.GpDefineIpHashRule
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

unix_sky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值