05、Ribbon负载均衡机制

94 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

05、Ribbon负载均衡机制

负载均衡器

Ribbon 的负载均衡器接口定义了服务器的操作,主要是用于进行服务器选择。在前面 的例子中 客户端使用了 RestClient 在发送请求时,会使用负载均衡器 CILoadBalancer 接口,根据特定的逻辑来选择服务器。 服务器列表可使用 listOfServer 进行配置,也可以 使用动态更新机制。下面使用负载均衡器来选择服务器。

   /**
     * 使用负载均衡器来选择服务器-- ,在默认情况下,会使用 RoundRobinRule 的规则逻辑
     */
    @Test
    public void ChoseServerTest() {
        //创建负载均衡器
        ILoadBalancer lb = new BaseLoadBalancer();

        ArrayList<Server> servers = new ArrayList<>();
        servers.add(new Server("localhost", 8888));
        servers.add(new Server("localhost", 9999));
        lb.addServers(servers);
        //进行6次服务器选择
        for (int i = 0; i < 6; i++) {
            // 选择哪个服务器进行请求处理,由 ILoadBalancer 接口的 choose Server 方法决定。
            // 而在 BaseLoadBalancer 类中 ,则使用 IRule 接口的 choose 方法来 决定选择哪 个服务器对象
            Server server = lb.chooseServer(null);
            System.out.println(server);
        }
    }

自定义负载规则

选择哪个服务器进行请求处理,由 ILoadBalancer 接口的 choose Server 方法决定。而在 BaseLoadBalancer 类中 ,则使用 IRule 接口的 choose 方法来 决定选择哪 个服务器对象 如果想自定义负载均衡规定,可以编写 IRule 接口的 实现类

public class MyRule implements IRule {
    private ILoadBalancer lb;
    public MyRule() {
    }
    public MyRule(ILoadBalancer lb) {
        this.lb = lb;
    }
    public Server choose(Object key) {
	    //在自定义规则类中,实现的 choose 方法调用了 ILoadBalancer getAllServers 方法,
返回全部服务器,为了简单起见,本例只返回第一个服务器。
        List<Server> servers = lb.getAllServers();
        System.out.println("这是自定义服务器定规则类,输出服务器信息:");
        for (Server s : servers) {
            System.out.println("        " + s.getHostPort());
        }
        return servers.get(0);
    }
    public void setLoadBalancer(ILoadBalancer lb) {
        this.lb = lb;
    }
    public ILoadBalancer getLoadBalancer() {
        return this.lb;
    }
}

使用自定义的负载规则两种方式:

/**
     * 使用自定义的负载规则 -- MyRule     使用 BaseLoadBalancer类中的 IRule 接口的 choose 方法
     */
    @Test
    public void ChoseServerTest2() {
        //创建负载均衡器
        BaseLoadBalancer lb = new BaseLoadBalancer();
        //设置自定义的负载规则
        lb.setRule(new MyRule(lb));

        ArrayList<Server> servers = new ArrayList<>();
        servers.add(new Server("localhost", 8888));
        servers.add(new Server("localhost", 9999));
        lb.addServers(servers);

        //进行6次服务器选择
        for (int i = 0; i < 6; i++) {
            //选择哪个服务器进行请求处理,由 ILoadBalancer 接口的 choose Server 方法决定。
            // 而在 BaseLoadBalancer 类中 ,则使用 IRule 接口的 choose 方法来 决定选择哪 个服务器对象
            Server server = lb.chooseServer(null);
            System.out.println(server);
        }
    }
/**
     * 客户端使用了RestClient 在发送请求时,会使用负载均衡器ILoadBalancer接口,根据特定的逻辑来选择服务器。
     *
     * @throws Exception
     */
    @Test
    public void RestClientTest() throws Exception {
       //ConfigurationManager来配置请求的服务器列表
       ConfigurationManager.getConfigInstance().setProperty("my-client.ribbon.listOfServers",
                "localhost:9999,localhost:8888");

        //配置规则处理类     也可在配置文件中配置
        ConfigurationManager.getConfigInstance().setProperty(
                "my-client.ribbon.NFLoadBalancerRuleClassName",
                MyRule.class.getName());

        //获取REST请求的客户端
        RestClient client = (RestClient) ClientFactory.getNamedClient("my-client");
        //创建请求实例
        HttpRequest request = HttpRequest.newBuilder().uri("/person/8").build();
        //
        for (int i = 0; i < 6; i++) {
            HttpResponse response = client.executeWithLoadBalancer(request);
            String result = response.getEntity(String.class);
            System.out.println(result);
        }
    }

Ribbon自带的负载规则

  • Ribbon提供了若干个内置的负载规则,使用者完全可以直接使用
  1. RoundRobinRule:系统默认的规则,通过简单的轮询服务列表来选择服务器,其他的规则在很多情况下,仍然使用RoundRobinRule
  2. AvailablilityFilteringRule:该各种会忽略以下服务器
  • 无法连接的服务器:在默认情况下,如果3次连接失败,该服务器将会被置为“短路”的状态,该状态将持续30秒,如果再次连接失败,“短路”状态的持续时间将会以几何级增加。可以通过修改niws.loadbalance..connerctionFailureCountThreshold属性来配置连接失败的次数
  • 并发数过高的服务器:如果连接到该服务器的并发数过高,也会被这个规则忽略,可以通过修改.ribbon.ActiveConnectionLimit属性来设定最高并发数
  1. WeightedResponseTimeRule:为每个服务器赋予一个权重值,服务器的响应时间越长,该权重值就越少,这个规则会随机选择服务器,这个权重值有可以能会决定服务器的选择

  2. ZoneAvoidanceRule:该规则以区域、可用服务器为基础,进行服务器选择。使用Zone对服务器进行分类,可以理解为机架或者机房

  3. BestAvailiableRule:忽略“短路”的服务器,并选择并发数较低的服务器

  4. RandomRule:随机选择可用服务器

  5. RetryRule:含有重试的选择逻辑,如果使用RoundRobinRule

  • 以上提供的负载规则,基本上可以满足大部分的需求

ping机制

在负载均衡器中,提供了 Ping 机制,每隔一段时间,会去 Ping 服务器,判断服务器是否存活。 该工作由 !Ping 接口的实现类负责,如果单独使用 Ribbon 在默认情况下,不会激活 Ping 机制,默认的实现类为 DummyPing 代码 使用了另外 IPing 实现类PingUrl

/**
 * 使用Ping机制   ****** 不知道为嘛   在Earue Server 注册过的服务器访问不通 ,其它可以
 */
@Test
public void TestPingUrl() throws InterruptedException {
    //创建负载均衡器
    BaseLoadBalancer lb = new BaseLoadBalancer();
    ArrayList<Server> servers = new ArrayList<>();
    servers.add(new Server("localhost", 8888));
    servers.add(new Server("localhost", 8762));
    lb.addServers(servers);

    //设置 IPing 实现类
    lb.setPing(new PingUrl());
    //设置 Ping 时间间隔为2秒
    lb.setPingInterval(2);

    Thread.sleep(6000);
    for (Server s : lb.getAllServers()) {
        System.out.println(s.getHostPort() + "状态:" + s.isAlive());
    }
}

在配置中设置IPing实现类:

 /**
     * 在配置中设置Iping实现类  也可以使用在配置文件中  ***** 在注册中心注册的两个节点不知道为什么也访问不通
     *
     * @throws Exception
     */
    @Test
    public void RestPingUrlConfig() throws Exception {
        //ConfigurationManager来配置请求的服务器列表
        ConfigurationManager.getConfigInstance().setProperty("my-client.ribbon.listOfServers",
                "localhost:8761,localhost:8888");

        //配置IPing处理类
        ConfigurationManager.getConfigInstance().setProperty(
                "my-client.ribbon.NFLoadBalancerPingClassName",
                PingUrl.class.getName());

        //配置Ping时间间隔
        ConfigurationManager.getConfigInstance().setProperty(
                "my-client.ribbon.NFLoadBalancerPingInterval",
                2);

        //获取REST请求的客户端
        RestClient client = (RestClient) ClientFactory.getNamedClient("my-client");
        Thread.sleep(6000);
        for (Server s : client.getLoadBalancer().getAllServers()) {
            System.out.println(s.getHostPort() + "状态:" + s.isAlive());
        }
    }

注意代码中的以下两个配置。

  • my-client.ribbon.NFLoadBalancerPingClassName :配置 !Ping 的实现类。
  • my-client.ribbon.NFLoadBalancerPinglnterval :配置 Ping 操作的时间间隔。

以上两个配置同样可以使用在配置文件中。

自定义Ping

实现自定义Ping较为简单,先实现IPing接口,再通过配置来设定具体的Ping实现类

/**
 * 自定义IPing实现类
 */
public class MyPing implements IPing {
    @Override
    public boolean isAlive(Server server) {
        System.out.println("这是自定义的Ping实现类:"+server.getHostPort());
        return true;
    }
}

要使用自定义的Ping类,通 过修改client.nameSpace.NFLoadBalancerPingClassName 配置即可

其他配置

NFLoadBalancerClassName:指定负载均衡器的实现类,可利用该配置,实现自己的负载均衡器。 NIWSServerListClassName:服务器列表处理类,用来维护服务器列表,Ribbon 已经实现动态服务器列表。 NIWSServerListFilterClassName:用于处理服务器列表拦截。