《SpringCloud篇:002Ribbon服务之间的负载均衡》

2020-11-13 14:37:32 浏览数 (1)

一、概述

Ribbon是为了实现服务与服务之间调用的负载均衡,是客户端负载均衡,并且默认采用轮询的策略。(类似于Nginx,但是Ribbon是用于服务端的,Nginx是客户端的)

找官方文档

根据文档配置pom依赖

代码语言:javascript复制
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

启动类上加LoadBalance注解

代码语言:javascript复制
package com.qf.springcloud.consumer;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
@ServletComponentScan(basePackages = "com.qf.springcloud.consumer")
public class ConsumerStarterApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerStarterApp.class,args);
    }


    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }


//    @Bean
//    public IRule randomRule(){
//        return new RandomRule();
//    }
}

修改controller,改成直接访问就可以

代码语言:javascript复制
package com.qf.springcloud.consumer.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.qf.springcloud.consumer.client.ProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@RestController
public class ConsumerController {

    /*@Autowired
    private EurekaClient eurekaClient;*/

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ProviderClient providerClient;

    @GetMapping("/consumer/test")
    public String test() throws InterruptedException {
        /*//1. 通过Eureka获取PROVIDER服务的ip和port
        InstanceInfo provider = eurekaClient.getNextServerFromEureka("PROVIDER", false);
        String ip = provider.getIPAddr();
        int port = provider.getPort();

        //2. 通过RestTemplate调用provider的/provider/test
        String result = restTemplate.getForObject("http://"   ip   ":"   port   "/provider/test", String.class);*/

        /*
        //1. 访问目标服务
        String result = restTemplate.getForObject("http://PROVIDER/provider/test", String.class);
        */
        Thread.sleep(2000);
        System.out.println("test:"   Thread.currentThread().getName());
        String result = providerClient.test();
        //3. 返回结果
        return result;
    }


    @GetMapping("/param/test/{type}")
    /*
    @HystrixCommand(fallbackMethod = "paramTestFallback",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "30000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "10")

    })
    */
    public Map paramTest(@PathVariable Integer type) throws InterruptedException {
        System.out.println("paramTest:"   Thread.currentThread().getName());
        if (type == 1){
            // path
            return providerClient.path(123);
        }else if (type == 2){
            int i = 1 / 0;
            // param
            return providerClient.param("张老三",233);
        }else{
            // body
            Map map = new HashMap();
            map.put("abcdefg","hijklmn");
            return providerClient.body(map);
        }
    }


    public Map paramTestFallback(Integer type){
        System.out.println("paramTestFallback:"   Thread.currentThread().getName());
        Map map = new HashMap();
        map.put("msg","我的Consumer自己出现了问题");
        return map;
    }
}

为了掩饰负载均衡,所以我们创建多个provider,复制原来的provider,在application.yml中修改它的端口号

代码语言:javascript复制
spring:
  application:
    # 指定服务名称
    name: provider



eureka:
  client:
    service-url:
      # 指定注册到的eureka的地址信息
      defaultZone: http://admin:admin@localhost:8761/eureka/,http://admin:admin@localhost:8762/eureka/



server:
  port: 8081

在controller也修改一下它的内容让它们有所区分

代码语言:javascript复制
package com.qf.springcloud.provider.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProviderController {

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

    @GetMapping("/provider/test")
    public String test(){
        return "Hello Eureka!!!"   port;
    }

}

重启consumer,实现负载均衡(默认轮询)

使用注解或者yml来修改复杂均衡策略 修改consumer中的启动类,注解中的(随机效果)

代码语言:javascript复制
package com.qf.springcloud.consumer;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrixDashboard
@ServletComponentScan(basePackages = "com.qf.springcloud.consumer")
public class ConsumerStarterApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerStarterApp.class,args);
    }


    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }


//    @Bean
//    public IRule randomRule(){
//        return new RandomRule();
//    }
}

使用yml配置响应时间权重的负载均衡

代码语言:javascript复制
PROVIDER:
 ribbon:
   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightResponseTimeRule

重启,先以轮训开始,然后根据响应时间分配权重

0 人点赞