SpringCloud 为服务消费者整合Ribbon

1 简介

本文主要实现有:

  1. 配合Eureka使用Ribbon实现负载均衡
  2. 自定义Ribbon配置整合(java代码和属性配置两种实现)
  3. Ribbon独立使用配置整合

2 整合Ribbon实现负载均衡

通过上一篇文章《多节点高可用Eureka集群与服务注册》我们搭建了一个Eureka的集群,本文为了测试搭建后的效果稍作修改。
首先复制上文中artifactId为microservice-provider-user的项目,修改端口为8001,这样我们就有了两个微服务的提供者,端口分别为8000和8001

2.1 为消费者整合Ribbon

首先给消费者添加依赖:

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

注:由于我们的项目配合Eureka使用,spring-cloud-starter-eureka包含了spring-cloud-starter-ribbon,所以无需再次引入依赖。

在上文中我们通过RestTemplate来实现请求,那我们在RestTemplate上面添加@LoadBalanced注解

/**
 * ConsumerMovieApplication class
 *
 * @author TransientBa
 * @date 2018/5/5
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerMovieApplication {

    //添加LoadBalanced注解来整合Ribbon使其具有负载均衡的能力
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ConsumerMovieApplication.class,args);
    }
}
2.2 修改Controller以便使用测试
package com.TransientBa.cloud.controller;

import com.TransientBa.cloud.pojo.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;

/**
 * MovieController class
 *
 * @author TransientBa
 * @date 2018/5/5
 */
@RestController
public class MovieController {

    private static Logger LOGGER = LoggerFactory.getLogger(MovieController.class);

    //使用restTemplate请求User服务
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    //读取配置文件Url路径  
    @Value("${user.userServiceUrl}")
    private String userServiceUrl;


    @GetMapping(value = "/user/{id}")
//    @GetMapping(value = "/user/{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public User findById(@PathVariable Long id){
   		 //下面这个userServiceUrl 为配置文件中读取的http://microservice-provider-user/地址  该地址为服务提供者的虚拟主机名 配合Eureka使用会自动将其映射成微服务的网络地址  即前面提到的8001 8000
        return this.restTemplate.getForObject(userServiceUrl + id,User.class);

    }

    /***
     * 查询microservice-provider-user服务的信息并返回
     * @return microservice-provider-user服务的信息
     *
     * 使用DiscoveryClient.getInstances(serviceId),可查询指定微服务在Eureka上的实例列表
     */
    @GetMapping(value = "/user-instance", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
//    @GetMapping(value = "/user-instance", produces = MediaType.APPLICATION_XML_VALUE)
    public List<ServiceInstance> showInfo(){
        return this.discoveryClient.getInstances("microservice-provider-user");
//        return this.discoveryClient.getInstances("MICROSERVIECE-CONSUMER-MOVIE");
    }


    /**=
     * 打印当前选择的是哪个节点
     */
    @GetMapping("/log-instance")
    public void logUserInstance(){
        ServiceInstance serviceInstance = this.loadBalancerClient.choose("microservice-provider-user");
        MovieController.LOGGER.info("{}:{}:{}",serviceInstance.getServiceId(),serviceInstance.getHost(),serviceInstance.getPort());
    }
}

注:此处有一点需要注意,restTemplate.getForObject和loadBalancerClient.choose不能同时在一个方法中使用,因为restTemplate上的@LoadBalanced注解使其在这里成为了一个Ribbon客户端,本身已经包含了choose的行为,放在一起会产生冲突。

2.3 测试

启动四个服务,访问检查页面
启动后的Server检查页面
可以看到Server分别发现了两个叫MICROSERVICE-PROVIDER-USER的服务提供者,一个叫MICROSERVIECE-CONSUMER-MOVIE的消费者,下面我们通过多次请求/user/{id}接口来观察下两个服务提供者打印的日志。

多次访问http://localhost:8010/user/1接口
在这里插入图片描述
多次请求后,两个微服务提供者的控制台都输出了查询语句

在这里插入图片描述

为了更直观的看到访问的情况 ,我们再多次访问上面2.2中的/log-instance接口

在这里插入图片描述
请求均匀的分布到了两个微服务节点上。

3 自定义Ribbon配置整合

上面配置了一个简单的负载均衡,那如何自定义负载均衡的规则呢?
要实现有两种方式

  1. 通过Java代码配置
  2. 通过配置文件中的属性去配置

在SpringCloud中,Ribbon默认的配置类是RibbonClientConfiguration。也可使用一个POJO自定义Ribbon的配置(自定义配置会覆盖默认配置)。这种配置是细粒度的,不同的Ribbon客户端可以使用不同的配置。

3.1 通过Java代码配置

创建一个Ribbon的配置类

package com.TransientBa.cloud.config;

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

/**
 * RibbonConfiguration class
 * 该类不应该在主程序上下文的@ComponentScan中
 * @author TransientBa
 * @date 2019/1/28
 */
@Configuration
public class RibbonConfiguration {
    @Bean
    public IRule ribbonRule(){
        return new RandomRule();
    }
}

在创建一个空类用来选择应用指定的Ribbon配置类。

package com.TransientBa.cloud.config;

import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;

/**
 * TestConfiguration class
 * 使用RibbonClient注解来为特定name的Ribbon client定义配置
 * configuration属性指向了刚刚我们自定义的RibbonConfiguration配置类
 * @author TransientBa
 * @date 2019/1/28
 */
@Configuration
@RibbonClient(name="microservice-provider-user",configuration = RibbonConfiguration.class)
public class TestConfiguration {
}

启动服务测试一下请求分布情况,依然访问http://localhost:8010/log-instance接口

在这里插入图片描述
可以看到【1】中日志显示请求被随机分发了。但这里需要注意的是:

RibbonConfiguration类不能包含在主应用程序上下文的@ComponentScan中,否则该类中的配置信息就被所有的@RibbonClient共享。

所以可以看到在红框【2】中目录的结构,SpringBoot默认扫描的位置在Application启动类的同级及下属子目录,我们将RibbonConfiguration类拿到了外面。

3.2 通过配置文件中的属性去自定义配置

上面通过Java代码进行了配置,这种方式要产生两个类,那有没有办法简化配置?
下面我们通过属性配置来达到同样的效果。

删除上面两个添加的配置类,只需要在yml配置文件中添加:

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

启动服务测试后效果同Java配置。到这里我们可以看出使用属性配置明显比Java配置简化的多。

4 Ribbon独立使用配置整合

很多旧项目并不是配合Eureka使用,可能也不是SpringCloud开发的,这种情况下就需要单独的集成Ribbon。想要达到的架构效果如下:
在这里插入图片描述

4.1 配置使用

首先引用Ribbon的依赖spring-cloud-starter-ribbon,在POM中添加:

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

引入好依赖后在yml文件中添加listOfServers,例如下图:
在这里插入图片描述
此处listOfServers为名字叫microservice-provider-user的Ribbon客户端设置请求的地址列表,即服务提供方的地址列表。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值