SpringCloud 学习(三)Ribbon 和 Feign

4. Netflix.Ribbon

4.1 简介

(1) 概念

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

(2) 负载均衡(LB:LoadBalance)和集群架构

在这里插入图片描述

  • 应用集群:将同一应用部署到多台机器上,组成处理集群,接收负载均衡设备分发的请求,进行处理,并返回相应数据。
  • 负载均衡设备:将用户访问的请求,根据负载均衡算法,分发到集群中的一台处理服务器。(一种把网络请求分散到一个服务器集群中的可用服务器上去的设备)。
  • 负载均衡的作用(解决的问题):
    • 解决并发压力,提高应用处理性能(增加吞吐量,加强网络处理能力);
    • 提供故障转移,实现高可用;
    • 通过添加或减少服务器数量,提供网站伸缩性(扩展性);
    • 安全防护;(负载均衡设备上做一些过滤,黑白名单等处理)

(3) 负载均衡分类

  • 集中式 LB
    • 在服务的消费方和提供方之间使用独立的 LB 设施,如 Nginx(反向代理服务器),由该设施把访问请求通过某种策略转发至服务的提供方。
  • 进程式 LB
    • 将 LB 逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后从这些地址中选用一个服务器。
    • Ribbon 属于进程式 LB,它是一个类库,集成于消费方进程,消费方通过它来获取提供方的地址。

4.2 集成 Ribbon

调整 springcloud-consumer-dept-80 服务

● 添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
● 为 RestTemplate 配置负载均衡
@Configuration  // spring applicationContext.xml
public class ConfigBean {

    // 注册 bean <bean></bean>
    @Bean
    // 配置负载均衡实现 RestTemplate
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
● 修改获取远程服务的地址
// DeptConsumerController
// Ribbon 实现负载均衡,此处的地址应是一个变量——服务名
// private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
● 添加 Eureka 配置
# eureka
eureka:
  client:
    # 不向 eureka 注册自己
    register-with-eureka: false
    # 列出可使用的服务地址供消费者服务选择
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
● 开启 Eureka 客户端服务
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }
}

4.3 模拟多服务访问

● 创建数据库

在这里插入图片描述

cloud01.dept.db_source = cloud01
cloud02.dept.db_source = cloud02
cloud03.dept.db_source = cloud03
● 创建两个 maven 模块作为服务提供者

springcloud-provider-dept-8001
springcloud-provider-dept-8002
springcloud-provider-dept-8003

在这里插入图片描述

  • 修改配置文件

    springcloud-provider-dept-8001 => cloud01
    springcloud-provider-dept-8002 => cloud02
    springcloud-provider-dept-8003 => cloud03
    
● 访问效果

在这里插入图片描述

在这里插入图片描述

4.4 自定义 Ribbon 规则

(1) 创建 Ribbon 配置类

  • 自定义配置类的组件会覆盖 RibbonClientConfiguration 中的组件来完成配置。

  • 自定义配置类的注解必须是 @Configuration,其不在主应用程序下的 @ComponentScan 中,否则将由所有 @RibbonClients 共享,若使用 @ComponentScan / @SpingBootApplication,则需要采取避免措施,,如将其放在一个单独的,不重叠的包中,或指定在 @ComponentScan。

  • 自定义配置类放在启动类所在的目录外

    在这里插入图片描述

    /**
     * 每个服务访问 5 次,选择下一个服务
     * @author why
     * @since 2021/9/7 21:02
     */
    public class RoundFiveRule extends AbstractLoadBalancerRule {
    
        // 被调用次数
        private int toltal = 0;
    
        // 当前提供服务的索引
        private int currentIndex = 0;
    
        // @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "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<Server> upList = lb.getReachableServers();
                // 获取所有服务
                List<Server> allList = lb.getAllServers();
    
                int serverCount = allList.size();
                if (serverCount == 0) {
                    return null;
                }
    
                // // 生成区间随机数
                // int index = chooseRandomInt(serverCount);
                // // 随机获取可用服务
                // server = upList.get(index);
    
                //===============================================================================
                if (toltal < 5) {
                    server = upList.get(currentIndex);
                    toltal++;
                } else {
                    toltal = 1;
                    currentIndex++;
                    if (currentIndex >= upList.size()) {
                        currentIndex = 0;
                    }
                    server = upList.get(currentIndex);
                }
                System.out.print(" " + currentIndex + " ");
                //================================================================================
    
                if (server == null) {
                    Thread.yield();
                    continue;
                }
    
                if (server.isAlive()) {
                    return (server);
                }
                server = null;
                Thread.yield();
            }
    
            return server;
    
        }
    
        protected int chooseRandomInt(int serverCount) {
            return ThreadLocalRandom.current().nextInt(serverCount);
        }
    
        @Override
        public Server choose(Object key) {
            return choose(getLoadBalancer(), key);
        }
    
        @Override
        public void initWithNiwsConfig(IClientConfig clientConfig) {
            // TODO Auto-generated method stub
        }
    
    }
    

(2) 将自定义配置类注册到 Spring 中

@Configuration
public class MyRule {
   	// 将自定义配置类注册到 Spring 中
    @Bean
    public IRule myRule() {
        return new RoundFiveRule();
    }
}

(3) 配置启动类自动加载自定义配置类

@SpringBootApplication
@EnableEurekaClient
/*
 * 微服务启动时,加载 Ribbon 配置类
 * @param name 服务名
 * @param configuration 自定义配置类的反射
 */
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = RoundFiveRule.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class, args);
    }
}

在这里插入图片描述

虽然 index 为轮询方式,但由于 index 并未与服务进行一对一绑定,所以服务的访问准确来说并不是每 5 次就更换下一个服务。

5. Netflix.Feign

5.1 简介

  • Feign 是声明式的 web service 客户端,它简化了微服务之间的调用。
  • Ribbon 使用微服务名字调用微服务,Feign 使用接口和注解调用微服务。
  • 创建一个接口,使用 Feign 注解进行配置,即可完成对服务提供方的接口绑定。
  • Feign 集成了 Ribbon,通过添加一层的方式增加了代码的可读性,但是性能有所降低

5.2 Feign 实现

调整 springcloud-consumer-dept-80 微服务

● 创建 maven moudle

在这里插入图片描述

● 添加依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-feign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

● 删除 Ribbon 配置

● 编写 Feign 服务层

在公共服务 springcloud-api 中添加 Feign 服务层

在这里插入图片描述

/**
 * Feign 实现服务的调用
 *
 * @author why
 * @since 2021/9/9 9:24
 */
// 将接口注册到 Spring,否则会报红,但是却不影响调用,原因不明
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {

    @GetMapping("/dept/getDept/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);
}

● 启动类开启 Feign 扫描

@SpringBootApplication
@EnableEurekaClient
/*
 * @EnableFeignClients(basePackages = {"com.why.springcloud"})  扫描 springcloud-api 
 * 务 com.why.springcloud 目录及以内目录下的 @FeignClient
 */
@EnableFeignClients(basePackages = {"com.why.springcloud"})
public class FeignDeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_80.class, args);
    }
}

● 远程调用

Feign 服务层也可以放在当前服务服务中,此时无需对注解 @EnableFeignClients 的属性赋值

@SpringBootApplication
@EnableEurekaClient
/*
 * @EnableFeignClients 扫描当前服务主类同级及以内目录下的 @FeignClient
 */
@EnableFeignClients
public class FeignDeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_80.class, args);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值