Ribbon实现负载均衡

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套【客户端】负载均衡工具。

Ribbon会自动帮助你基于某种规则(简单轮询、随机连接等),也可以实现自定义的负载均衡算法。 


负载均衡介绍:

    简单来说负载均衡就是将用户的请求ping平摊的分配到多个任务上,从而是系统达到HA(高可用)。


目前主要分两种负载均衡:
  1. 集中式LB:偏硬件,服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5。也可以是软件,如Nginx),由该设施负责把访问请求以某种策略转发至服务的提供方。
  2. 进程内LB:偏软件, 将LB逻辑集成到消费方,消费方从服务注册中心指导哪些地址可用,再自己选择一个合适的服务器(如Ribbon)。



 总结:Ribbon其实就是一个软负载均衡的客户端组件,可以和其他需要请求的客户端结合使用。


Ribbon初步配置:

分析图如下

实现前提:构建服务提供者集群,新开两个provider模块,注册入Eureka,提供服务,集群中服务名称必须一致。


Ribbon是客户端负载均衡工具!所以应该配置在客户端。此处使用consume工程为例,配置仅需要在客户端配置即可。配置步骤如下:

1.加入依赖,因为Riboon需要依赖Eureka运行,所以要同时加入Eureka依赖。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

2.对实现类加入@LoadBalanced注解,即以之前实现的RestTemplate为例。

在consume工程中的SpringBoot配置类ConfigBean中增加如下注解:

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/*  @Configuration 注解相当于代表该类是 applicationContext.xml */
@Configuration
public class ConfigBean
{ 
	@Bean
	@LoadBalanced
	public RestTemplate getRestTemplate(){
		return new RestTemplate();
	}
	
}
3. 在application.yml文件中配置向注册中心注册,如果是作为消费者模块不提供服务,不应该注册自己;
server:
  port: 9001

eureka:
  client:
    register-with-eureka: false #作为消费者不提供服务,不应该注册自己
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

4. 主启动类中加入@EnableEurekaClient注解;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@EnableEurekaClient
public class DeptConsumer_9001_App {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_9001_App.class, args);
    }
}

5. 以上步骤1~4完成后即可在controller中直接通过服务名访问系统中的微服务,服务名作为URI

consumer应用中controller实现如下:

    /* 原服务url */
    //private static final String REST_URL_PREFIX = "http://localhost:8001";
    /* 以服务名作为URI */
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUDDEMO-PROVIDER-DEPT";

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/dept/list")
    public List<Dept> list() {
        return restTemplate.getForObject(REST_URL_PREFIX + "/provider/dept/list", List.class);
    }

完成以上5个步骤就已经实现客户端负载均衡功能(此处使用的是默认轮询的规则进行负载均衡),可以访问客户端进行测试(略过)。




Ribbon核心组件IRule:根据特定算法从服务列表中选取一个需要访问的服务;

其中IRule是一个接口,有七个自带的落地实现类,可以实现不同的负载均衡算法规则:

RoundRobinRule                                                                                                       
轮询规则(默认方法)

RandomRule


随机

AvailabilityFilteringRule


先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务进行轮询

WeightedResponseTimeRule


根据平均响应时间计算服务的权重。统计信息不足时会按照轮询,统计信息足够会按照响应的时间选择服务
RetryRule
正常时按照轮询选择服务,若过程中有服务出现故障,在轮询一定次数后依然故障,则会跳过故障的服务继续轮询。
BestAvailableRule
先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务

ZoneAvoidanceRule


默认规则,符合判断server所在的区域的性能和server的可用性选择服务

如何切换Ribbon中赋值均衡的规则,而不是使用默认的轮询方式?

只需在客户端(consume)工程中的SpringBoot配置类ConfigBean配置一个返回具体方法的bean即可,如下:

@Bean
	public IRule MyRule(){
		/* RandomRule为Ribbon中自带规则实现之一,随机规则 */
		return new RandomRule();
	}


自定义Ribbon负载均衡算法

    如果觉得Ribbon中自带的负载均衡规则无法满足你的需求,那也可以自定义Ribbon负载均衡算法。


需要注意的地方;

    自定义的Ribbon算法类不能放在主启动类所在的包及子包下(确切来说是不能放在@ComponentScan注解的包及子包下),否则会被全局应用到Ribbon服务中。 应该把自定义算法类放在另外新建的包下,且这个类应该是为【配置类】即加上注解@Configuration

    

实现自定义Ribbon负载均衡算法的步骤:

1。将原来consumer工程中的配置类ConfigBean中返回 IRule 的Bean删掉,然后新建一个包,定义配置类,返回自定义的负载均衡规则的实现类:

package com.wangcw.ribbon;

import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MySelfRule
{
	@Bean
	public IRule myRule() {
		/* 此处返回自定义的负载算法规则 */
		return new RandomRule_Myself();
	}
}

2.实现自定义规则实现类RandomRule_Myself(此处实现每台服务器调用5次后,再继续轮询下一台服务器)

package com.wangcw.ribbon;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;

public class RandomRule_Myself extends AbstractLoadBalancerRule {

     /*
     total = 0 // 当total==5以后,我们指针才能往下走,
     index = 0 // 当前对外提供服务的服务器地址,
     total需要重新置为零,但是已经达到过一个5次,我们的index = 1 */

    /* 总共被调用的次数,目前要求每台被调用5次 */
    private int total = 0;
    /* 当前提供服务的机器号 */
    private int currentIndex = 0;

    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) {
                return null;
            }

            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex >= upList.size()) {
                    currentIndex = 0;
                }
            }


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

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

            server = null;
            Thread.yield();
        }

        return server;

    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {}

}

3.在启动类上加上注解 @RibbonClient(name = "微服务名",configuration = XXX.class) 注解指定需要用到负载均衡的微服务名及自定义算法的class对象。

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@EnableEurekaClient
@RibbonClient(name="SPRINGCLOUDDEMO-PROVIDER-DEPT",configuration=MySelfRule.class)
public class DeptConsumer_9001_App {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_9001_App.class, args);
    }
}

4.启动测试就可以发现已经生效。



猜你喜欢

转载自blog.csdn.net/qq_33404395/article/details/80899375