SpringCloud系列(二)服务调用

这是我参与更文挑战的第 11 天,活动详情查看: 更文挑战

Ribbon

一、概述

  • 负载均衡就是将客户的请求平摊到其他服务器上,达到服务高可用。
  • 本地负载均衡和服务器负载均衡
    • Ribbon是本地负载均衡,调用微服务接口时,先把注册中心的服务缓存到本机JVM上,在本地实现RPC远程调用。
    • Nginx是服务器负载均衡,用户的请求都会交给Nginx,再由Nginx实现转发请求,由服务端实现负载均衡。

Ribbon就是负载均衡+ResultTemplate调用

二、负载均衡的规则

默认是轮寻,可以使用自定义配置。

1、Ribbon自带的负载均衡规则(IRule):

  • RoundRobinRule: 轮询
  • RandomRule: 随机
  • RetryRule: 先轮询,如果失败在指定时间重试
  • WeightedResponseTimeRule: 响应速度越快权重越大,越容易被选择。
  • BestAvailableRule: 过滤掉多次访问故障的服务,然后选择一个并发量最小的服务
  • AvailabilityFilteringRule\ZoneAvoidanceRule: 和BestAvailableRule相似

2、负载规则替换

注意:负载规则替换的规则类不能放在@ComponentScan的扫描范围内

规则配置类

@Configuration
public class MySelfRule {
    //配置负载规则随机
    @Bean
    public IRule myRule() {
        return new RandomRule();
    }
}
复制代码

主启动类加@RibbonClient

@EnableEurekaClient
@SpringBootApplication
//对CLOUD-PAYMENT-SERVICE服务进行负载均衡,使用的规则为MySelfRule
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderMain8080 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain8080.class, args);
    }
}
复制代码

三、负载均衡轮寻算法原理

负载均衡算法:rest接口的请求次数 % 服务器集群数量 = 实际调用服务器位置的下标,每次启动服务rest从1开始。

接口LoadBalancer

public interface LoadBalancer {
    ServiceInstance instance(List<ServiceInstance> serviceInstances);
}
复制代码

实现

@Component
public class LoadBalancerImpl implements LoadBalancer {
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public ServiceInstance instance(List<ServiceInstance> serviceInstances) {
        //获取当前服务的下标
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }


    /**
     * 使用CAS自旋锁获取服务访问次数
     *
     * @return
     */
    public final int getAndIncrement() {
        int current;
        int next;

        do {
            current = this.atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
        } while (!this.atomicInteger.compareAndSet(current, next));

        return next;
    }
}
复制代码

测试

@RestController
@RequestMapping("/consumer")
public class OrderController {
    private final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
    @Resource
    private LoadBalancer loadBalancer;
    @Resource
    private DiscoveryClient discoveryClient;
    
    @GetMapping("/getPort")
    public String getPortLB() {
        //根据服务名称查找服务列表
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if (instances == null || instances.size() <= 0) {
            return null;
        }
        ServiceInstance serviceInstance = loadBalancer.instance(instances);
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri + "/payment/getPort", String.class);
    }
}
复制代码

Open Feign

一、概述

Feign是一个声明式的Web服务客户端,让Web Service更加简单,定义一个服务接口然后在上面加上注解,即可完成服务提供方的接口绑定,简化了使用Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon,而Feign是以接口绑定的声明式方法调用的。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解的下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡和调用其他服务。

二、Open Feign 服务调用

导入依赖

 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
复制代码

在启动类上添加注解开启OpenFeign

@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderFeignMain80.class, args);
    }
}
复制代码

创建接口调用服务,标明提供服务的服务名称,并且指定对应的url

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    @GetMapping("/payment/getById/{id}")
    ResultDto<Payment> getPaymentById(@PathVariable("id") Long id);
}
复制代码

测试调用

@RestController
public class OrderFeignController {
    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping("/consumer/get/payment/{id}")
    public ResultDto<Payment> getPaymentById(@PathVariable("id") Long id){
        return paymentFeignService.getPaymentById(id);
    }
}
复制代码

三、Open Feign 超时控制

演示

    //设置服务提供方等待3秒
    @GetMapping("/getPort")
    public String getPort() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return port;
    }
复制代码

Open Feign 客户端默认等待时间为1秒钟,如果超过一秒钟还没有得到提供服务方的响应,就会抛出错误。
为了避免这种情况,需要手动设置超时时间。

配置文件添加

ribbon:
  #指建立连接所用时间
  ReadTimeout: 5000
  #指获取资源所有时间
  ConnectTimeout: 5000
复制代码

四、Open Feign 日志增强

Feign提供了日志打印功能,通过配置来调整日志级别,对Feign接口的调用情况进行监控和输出。
日志级别:

  • NONE:默认,不显示任何日志;
  • BASIC:尽记录请求方法、URL、响应状态及响应时间;
  • HEADERS:除了BASIC中记录的内容,还会记录请求和响应头的信息;
  • FULL:除了HEADERS中的信息,还会记录请求和响应的正文及元数据

使用配置类配置级别

@SpringBootConfiguration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
复制代码

在配置文件中开启日志

logging:
  level:
#    feign日志以哪个级别监控哪个接口
    cn.yylm.springcloud.service.PaymentFeignService: debug
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享