1. 程式人生 > >四、SpringCloud之Ribbon負載均衡

四、SpringCloud之Ribbon負載均衡

Ribbon是一個客戶端的負載均衡(Load Balance)工具,可以很好的控制HTTP和TCP的一些行為,通過基於多種負載均衡演算法達到系統的高可用(HA)

官方資料:

以下內容是基於上一節的工程,使用Ribbon+RestTemplate 實現服務間通訊。

1、在microservice-dept-consumer-80服務消費者中pom.xml增加Ribbon依賴

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

2、配置對應的application.yml配置

server:
  context-path: /
  port: 80

eureka:
  client:
    register-with-eureka: false   #false表示不向註冊中心註冊自己,因為本身應用就是註冊中心
    service-url:
      #叢集配置
      defaultZone: http://eureka-server-5001.com:5001/eureka/, http://eureka-server-5002.com:5002/eureka/,http://eureka-server-5003.com:5003/eureka/

3、使用@LoadBalanced開啟客戶端負載均衡

@Configuration
public class RestTemplateConfig {

    /**
     *  呼叫restful服務模版,客戶端模版工具
     * @return
     */
    @LoadBalanced   //開始客戶端負載均衡
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

4、修改controller類DeptConsumerController URL對應的主機名為微服務例項名,Euraka整合Ribbon配置OK後就可以使用服務例項名訪問,不需要提供IP和埠

@RequestMapping("/consumer")
@RestController
public class DeptConsumerController {

//  private final static String URL_PREFIX = "http://localhost:8001";
    //Euraka整合Ribbon配置OK後就可以使用服務例項名訪問,不需要提供IP和埠
    private final static String URL_PREFIX = "http://MICROSERVICE-DEPT";

5、負載均衡配置

為了模擬多個服務例項,複製3個服務提供者microservice-dept-provider-8001microservice-dept-provider-8002

microservice-dept-provider-8003

修改埠分別為8001,8002,8003

在controller中增加port輸出,用於辨別負載均衡是否生效。

@Value("${server.port}")
    private Integer port;

    @GetMapping("/depts")
    public List<Dept> depts() {
        //新增埠資訊
        List<Dept> list = deptService.selectList();
        return list.stream().map(dept->{
            dept.setPort(port);
            return dept;
        }).collect(Collectors.toList());
    }

6、分別啟動Eureka sever、服務提供者

會在Eureka註冊中心中分別註冊8001,8002,8003,3個服務例項

啟動80埠消費應用microservice-dept-consumer-80

由於restTemplate 啟用了ribbon 負載均衡,而Ribbon預設使用輪詢演算法,因此會輪流呼叫8001、8002、8003服務

這裡寫圖片描述

這裡寫圖片描述

7、自定義Ribbon的負載均衡策略

Ribbon提供了很多負載均衡策略的實現用於獲取服務,預設使用輪詢的策略,我們可以通過修改配置指定使用哪個策略,也可以自定義我們自己的策略。

這裡寫圖片描述

RestTemplateConfig.java配置類中增加我們需要的指定的負載均衡策略

    /**
     * 修改我們需要的負載均衡策略
     * @return
     */
    @Bean
    public IRule myRule(){
        return new RandomRule();   //修改預設的演算法為隨機演算法
    }

只針對某個服務例項客製化指定Ribbo負載均衡策略

使用@RibbonClient註解應用到主啟動類上,指定對應的配置類。

自定義的配置類不能在@ComponentScan的掃描範圍內,否則 會別所有的ribbon客戶端共享,就達不到客製化目地。

(1)在主啟動類外的包org.pu.rule下建立我們自己指定策略的配置類MyRuleConfig.java

@Configuration
public class MyRuleConfig {
    /**
     * 修改我們需要的負載均衡策略
     * @return
     */
    @Bean
    public IRule myRule(){
        return new RandomRule();   //修改預設的演算法為隨機演算法
    }
}

(2)在主啟動類DeptConsumerApplication.java上增加@RibbonClient註解

//啟動該微服務的時候會載入客製化策略的配置類,使其生效
@RibbonClient(name="MICROSERVICE-DEPT",configuration=MyRuleConfig.class)
@SpringBootApplication
public class DeptConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerApplication.class, args);
    }
}

自定義負載均衡策略:

可以模仿下面隨機策略(RandomRule.java)來實現我們自己的策略:

//隨機演算法
@SuppressWarnings({"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 upList = lb.getReachableServers();  //獲取線上的服務
            List allList = lb.getAllServers();    //獲取所有的服務

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            int index = this.rand.nextInt(serverCount);  //隨機獲取
            server = (Server) upList.get(index);

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

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

            server = null;
            Thread.yield();
        }

        return server;
    }