Spring Cloud - 02 (Ribbon、Feign)

时间:2021-09-24 17:45:17   收藏:0   阅读:30

负载均衡-Ribbon

客户端负载均衡

相比较于Nginx的服务端负载均衡,Ribbon属于客户端的负载均衡。客户端负载均衡和服务器负载均衡的核心差异在服务列表本身,客户端负载均衡服务列表是通过客户端自己维护的,而服务端负载均衡服务列表是由中间服务(例如Nginx)单独维护。Ribbon通过Eureka拿到所有服务列表,然后通过自身的负载均衡策略,选择一个服务去处理请求。

负载均衡策略

IRule:Ribbon所有的负载均衡策略类都需实现该接口。

策略类 命名 说明
RandomRule 随机策略 随机选择 Server
RoundRobinRule 轮训策略 按顺序循环选择 Server
RetryRule 重试策略 在一个配置时问段内当选择 Server 不成功,则一直尝试选择一个可用的 Server,超过时间则返回null
BestAvailableRule 最低并发策略 先过滤掉故障服务,然后它会基于过去30分钟的统计结果选取当前并发量最小的服务节点,也就是最“闲”的节点作为目标地址。如果统计结果尚未生成,则采用轮询的方式选定节点。
AvailabilityFilteringRule 可用过滤策略 过滤掉一直连接失败并被标记为 circuit tripped 的 Server,过滤掉那些高并发连接的 Server(active connections 超过配置的网值)
ResponseTimeWeightedRule 响应时间加权策略 根据 Server 的响应时间分配权重。响应时间越长,权重越低,被选择到的概率就越低;响应时间越短,权重越高,被选择到的概率就越高。这个策略很贴切,综合了各种因素,如:网络、磁盘、IO等,这些因素直接影响着响应时间
ZoneAvoidanceRule 区域权衡策略 综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并且判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server

在代码中使用 Ribbon

配置负载均衡策略

@LoadBalanced 注解的使用

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class RibbonConsumerApplication {

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

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

代码中使用RestTemplate发送请求,则可以在RestTemplate的配置方法上加上@LoadBalanced注解,这样当RestTemplate发送请求时将会使用Ribbon的负载均衡。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class Controller {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("sayHi")
    public String sayHi() {
		// 注意这里的请求地址不需要指明服务地址,只需要指明服务名称即可
		// 这里就是负载均衡eureka-client服务,调用sayHi接口
        return restTemplate.getForObject("http://eureka-client/sayHi", String.class);
    }
}

IPing

IPing是Ribbon的一套healthcheck机制,故名思议,就是要Ping一下目标机器看是否还在线,一般情况下IPing并不会主动向服务节点发起healthcheck请求,Ribbon后台通过静默处理返回true默认表示所有服务节点都处于存活状态(和Eureka集成的时候会检查服节点UP状态)。


Ribbon的懒加载和饥饿加载

Ribbon默认是懒加载模式,首次加载发生在第一次调用的时候。
Ribbon还有一种加载模式是饥饿加载,会在项目启动时加载,需要添加配置:

# 开启Ribbon的饥饿加载模式,默认是懒加载(调用时才会初始化LoadBalancer)
ribbon.eager-load.enabled=true
# 指定需要应用饥饿加载的服务名称
ribbon.eager-load.clients=ribbon-consumer

服务间的通讯与调用-Feign

spring cloud服务之间的调用是基于HTTP的,然而对于原生的HTTP调用来说是件非常麻烦的事。Feign的出现就是为了解决这个问题,我们可以借助Feign的代理机制,像调用一个接口方法一样发起远程HTTP调用。

老的服务间调用方式:

@RestController
public class Controller {

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/hello")
    public String hello() {
        // 获取eureka-client服务实例
        ServiceInstance instance = loadBalancerClient.choose("eureka-client");
        //调用eureka-client服务的sayHi接口
        String target = String.format("http://%s:%s/sayHi", instance.getHost(), instance.getPort());
        return restTemplate.getForObject(target, String.class);
    }
}

使用feign后的调用方式:

@RestController
public class Controller {

    @Autowired
    private IService iService;

    @GetMapping("hello")
    public String hello() {
        return iService.sayHi();
    }
}

feign代码实践

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-demo</artifactId>
        <groupId>com.jinsh</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>feign-consumer</artifactId>
    <packaging>jar</packaging>
    <name>feign-consumer</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

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

启动类加@EnableFeignClients注解,配置文件还和普通服务注册配置文件一样

package com.jinsh.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {

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

IService 接口,添加@FeignClient("eureka-client")注解,eureka-client是想要调用的服务名称

package com.jinsh.springcloud;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient("eureka-client")
public interface IService {

    @GetMapping("sayHi")
    String sayHi();
}

controller中调用eureka-client服务的sayHi接口:

package com.jinsh.springcloud;

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

@RestController
public class Controller {

    @Autowired
    private IService iService;

    @GetMapping("sayHi")
    public String sayHi() {
        return iService.sayHi();
    }
}

feign使用讲解

引用

feign 中是包含ribbon和hystrix的,所以引用了feign后就不需要单独引用ribbon和hystrix了。

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

注解

1、@EnableFeignClients
需要在消费者的服务启动类上使用@EnableFeignClients注解,消费者服务才能以feign方式调用其他服务接口,
如果被调用的服务接口包名与消费者服务包名不同,例如消费者服务的包名为com.jinsh.consumer,被调用方的服务包名为com.jinsh.client,那么EnableFeignClients注解上还需要添加被调用服务的包名@EnableFeignClients(basePackages = {"com.jinsh.client"})

2、@FeignClient
FeignClient注解添加在接口类上,注解上还需要声明被调用的服务名@FeignClient("feign-client"),接口内则定义被调用服务的方法。

feign 的超时重试机制

feign 的超时重试机制底层是通过ribbon实现的。下面是配置超时重试的参数:

# feign-service-provider是服务提供者的服务名
feign-service-provider.ribbon.OkToRetryOnAllOperations=true
feign-service-provider.ribbon.ConnectTimeout=1000
feign-service-provider.ribbon.ReadTimeout=2000
feign-service-provider.ribbon.MaxAutoRetries=2
feign-service-provider.ribbon.MaxAutoRetriesNextServer=2

根据上面的配置,我们可以计算一次请求的最大超时时间

(2000 + 1000)*(2 + 1)*(2 + 1)= 27000ms

原文:https://www.cnblogs.com/jinshengnianhua/p/15310220.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!