四、服务消费(Ribbon)

1、Spring Cloud Ribbon

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。

当Ribbon与Eureka联合使用时,ribbonServerList会被DiscoveryEnabledNIWSServerList重写,扩展成从Eureka注册中心中获取服务实例列表。同时它也会用NIWSDiscoveryPing来取代IPing,它将职责委托给Eureka来确定服务端是否已经启动。

2、代码演示

创建子模块,命名为microservice-consumer-movie-ribbon,并且在pom.xml文件中添加相关依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

在eureka的坐标中,已经包含了ribbon的坐标。

application.yml

spring:
  application:
    name: microservice-consumer-movie
server:
  port: 3001
eureka:
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://admin:admin123@localhost:1001/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}

应用主类

@SpringBootApplication
@EnableEurekaClient
public class MainAppConsumer {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

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

可以看到,我们在RestTemplate上面添加了一个注解@LoadBalanced,它可以让这个RestTemplate在请求的时候拥有负载均衡的能力。

User实体类

public class User implements Serializable {
    private Long id;

    private String username;

    private String name;

    private short age;

    private BigDecimal balance;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public short getAge() {
        return age;
    }

    public void setAge(short age) {
        this.age = age;
    }

    public BigDecimal getBalance() {
        return balance;
    }

    public void setBalance(BigDecimal balance) {
        this.balance = balance;
    }
}

创建接口

@RestController
public class MovieController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @GetMapping("/movie/{id}")
    public User getById(@PathVariable("id") Long id){
        return this.restTemplate.getForObject("http://microservice-provider-user/getUser/"+id,User.class);
    }

    @GetMapping("/test")
    public void test(){
        ServiceInstance instance = loadBalancerClient.choose("microservice-provider-user");
        System.out.println(instance.getServiceId() + "===" + instance.getHost() + "===" + instance.getPort());

    }

}

可以看到这里,我们注入了LoadBalancerClientRestTemplate,并在/test接口中,先通过loadBalancerClientchoose函数来负载均衡的选出一个microservice-provider-user的服务实例,这个服务实例的基本信息存储在ServiceInstance中,我们打印其中的Host和Port,最后再利用RestTemplate对象实现对服务提供者接口的调用。

我们启动microservice-discovery-eureka,然后再分别用2001,2002这两个端口启动microservice-provider-user,最后启动microservice-consumer-movie-ribbon这个模块,访问http://localhost:3001/movie/1接口进行测试,页面响应:

{"id":1,"username":"user1","name":"张三","age":18,"balance":100.00}

多次访问http://localhost:3001/test,控制台打印

microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2002
microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2002
microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2002

因为我们的服务提供者通过两个端口,启动了两次,所以,当我们多次访问/test接口的时候,ribbon会基于轮询的负载均衡算法,依次调用这两个服务,所以看到2001调用一次之后,接着会调用2002端口。

ribbon中除了轮询的负载均衡算法,还存在随机负载均衡(Random),加权响应时间负载均衡(WeightedResponseTime)等,可以参考https://yq.aliyun.com/articles/61823

我们通过自定义配置,来修改ribbon默认的轮询负载均衡。

在src目录下创建一个包,命名为config(避免与应用主类同包或在其子包下面),然后创建一个类,命名为TestConfiguration,代码如下所示:

@Configuration
public class TestConfiguration {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }
}
@Configuration是spring中的一个注解,用于定义配置类,可以替换掉xml文件。@Bean注解定义在方法上,可以将方法的返回值作为一个对象注入IOC容器中,以供使用。
之后,修改应用启动主类,在类上添加:
@RibbonClient(name = "microservice-provider-user", configuration = TestConfiguration.class)

来引入我们创建的这个配合类。

上述完成后,我们还是按照之前的启动顺序,依次启动eureka,user提供者(2001,2002),movie消费者,然后访问消费者中的两个接口进行测试。

访问/movie/1接口,页面响应

{"id":1,"username":"user1","name":"张三","age":18,"balance":100.00}

多次访问/test接口,控制台打印

microservice-provider-user===192.168.1.7===2002
microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2002
microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2001
microservice-provider-user===192.168.1.7===2002
microservice-provider-user===192.168.1.7===2002

可以看到它们使用哪个端口进行响应是随机的,这就是ribbon中的随机负载均衡。

我们还可以使用配置文件进行配置ribbon的负载均衡算法。

只需要在application.yml中添加如下内容:

microservice-provider-user:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

当然要将之前配置类的方式去掉。

 

猜你喜欢

转载自www.cnblogs.com/beanbag/p/9943487.html