SpringCloud-负载均衡(Ribbon)_服务调用_负载均衡(OpenFeign)

 

Ribbon

what

https://github.com/netflix/ribbon

SpringCloud Ribbon 是基于Netflix Ribbon实现的一套 客户端 负载均衡的工具;

主要功能

  提供 客户端软件 负载均衡算法服务调用

  Ribbon客户端组件 提供一系列的配置项(连接超时、重试等);

    {简单来讲,就是在配置文件中列出负载均衡的所有机器,Ribbon会基于某种规则(简单轮询、随机连接等)去连接配置的机器}

Ribbon处于维护状态,替代方案

 

Ribbon负载均衡LoadBalance 

what

将用户的请求 平均分配到 多个服务上,从而达到系统的高可用;

常见的负载均衡软件:Nginx、LVS、硬件F5等;

Ribbon负载均衡与Nginx负载均衡的差异

Nginx是服务器负载均衡,客户端所有的请求都会交给Nginx,由Nginx负责请求转发(服务端实现);

Ribbon是本地负载均衡,在调用服务时,在注册中心获取注册的服务列表缓存到本地,从而在本地实现RPC调用(客户端实现);

集中式LB

在 服务的提供方与消费方之间 使用独立的LB设施(可以是软件Nginx、LVS、硬件F5等),由设施 将请求根据某种规则转发至服务提供方;

进程内LB

将LB逻辑 集成到服务消费方,消费方从注册中心获取可用的服务,然后根据某种规则选择一个服务提供方进行调用;

Ribbon架构说明

 

Ribbon pom
org.springframework.cloud#spring-cloud-dependencies  Hoxton.SR1版本的 org.springframework.cloud#spring-cloud-netflix-dependencies的

org.springframework.cloud#spring-cloud-starter-netflix-eureka-client 已经集成了org.springframework.cloud#spring-cloud-starter-netflix-ribbon

  

Ribbon核心组件IRule

what

根据特定算法 从服务列表中 选择一个要访问的服务;

com.netflix.loadbalancer.IRule


// Interface that defines a "Rule" for a LoadBalancer.  负载均衡的规则
// A Rule can be thought of as a Strategy for loadbalacing. 
// Well known loadbalancing strategies include Round Robin, Response Time based etc. 
public interface IRule{
    /*
     * choose one alive server from lb.allServers or
     * lb.upServers according to key
     * 
     * @return choosen Server object. NULL is returned if none
     *  server is available 
     */

    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

 

Ribbon预定义实现IRule  

com.netflix.loadbalancer.RoundRobinRule

轮询

com.netflix.loadbalancer.RandomRule

随机

com.netflix.loadbalancer.RetryRule

先按照 轮询策略 获取服务,如果获取服务失败,则在指定时间内进行重试;

com.netflix.loadbalancer.WeightedResponseTimeRule

对 轮询策略 的扩展,响应越快的服务获得的权重越大,越容易被选择;

com.netflix.loadbalancer.BestAvailableRule

先过滤掉由于多次访问故障 而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;

com.netflix.loadbalancer.AvailabilityFilteringRule

先过滤故障服务,再选择并发量较小的服务;

com.netflix.loadbalancer.ZoneAvoidanceRule

默认规则,复合判断 server所在区域的性能、server的可用性 来选择服务;

Ribbon自定义IRule

前言

自定义IRule不能被@ComponentScan扫描;

How
1、自定义IRule
@Configuration
public class MyIRule {

    @Bean
    public IRule iRule(){
        return new RandomRule();
    }
}


2、启动类增加@RibbonClient指向自定义IRule
@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "payment-service", configuration = MyIRule.class)
public class OrderStarter80 {

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

}

  

Ribbon负载均衡算法

轮询算法原理

rest接口第几次请求 % 服务总数 = 实际调用服务的下标;

 

轮询源码

public class RoundRobinRule extends AbstractLoadBalancerRule {

private AtomicInteger nextServerCyclicCounter;

public RoundRobinRule() {
        nextServerCyclicCounter = new AtomicInteger(0);
    }


public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();
            List<Server> allServers = lb.getAllServers();
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount);
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

    /**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo The modulo to bound the value of the counter.
     * @return The next value.
     */
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next))
                return next;
        }
    }

}

  

 OpenFeign

https://docs.spring.io/spring-cloud-openfeign/docs/3.1.3/reference/html/

https://github.com/spring-cloud/spring-cloud-openfeign

what

Feign is a declarative web service client.It makes writing web service clients easier.  

声明式的web服务client,OpenFeign使得写web服务更容易;

To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations.  

使用OpenFeign需要定义一个接口,然后添加注解;Feign注解支持Feign注解和JAX-RS注解;

Feign also supports pluggable encoders and decoders.

Feign支持可插拔的 编码器、解码器;

Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. 

SpringCloud 提供了SpringMVC注解支持,默认使用HttpMessageConverters;

Spring Cloud integrates Eureka, Spring Cloud CircuitBreaker, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign.

SpringCloud集成Eureka、CircuitBreaker、LoadBalancer 提供负载均衡;

已经有Ribbon,whyFeign?

Feign旨在让编写http client更简单;

使用Ribbon时,需要Ribbon+RestTemplate,利用RestTemplate对http请求做处理;

但实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多个地方调用,通常会自定义一些client包装这些依赖服务的调用;

所以,Feign在Ribbon基础上做了封装,有Feign来定义和实现依赖服务接口;

在Feign的实现下,只需要创建一个接口 然后注解接口,即可完成对服务提供方的接口绑定,简化了使用Ribbon时,自定义client的开发;

 

Feign与OpenFeign区别

 

工程

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


2、开启Feign支持
@EnableFeignClients // 开启Feign支持
@SpringBootApplication
public class OpenFeignOrderStarter80 {

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

}


3、新增FeignClient
@Component
@FeignClient(value = "eureka-payment-service")
public interface PaymentService {

    @GetMapping(value = "/get/{id}")
    CommonResult<Payment> getById(@PathVariable("id") Integer id);

}


4、test
@RestController
public class OrderController {

    @Autowired
    private PaymentService paymentService;

    @GetMapping(value = "/order/getById/{id}")
    public CommonResult<Payment> getById(@PathVariable("id") Integer id){
        return paymentService.getById(id);
    }

}

  

 OpenFeign超时

what

OpenFeign默认超时1s,如果服务提供方 超过1s,需要设置超时时间;

OpenFeign的超时实际由Ribbon实现(OpenFeign集成了Ribbon);

How

#设置Feign客户端超时
ribbon:
  ReadTimeout: 5000 #建立连接所用的时间
  ConnectTimeout: 5000  #建立连接后,响应结束所用的时间

  

OpenFeign日志打印

what

OpenFeign提供了日志打印功能,可以通过调整日志级别 了解Feign的HTTP请求的细节;

日志级别

NONE:

  默认的,不显示日志;

BASIC:

  记录 请求方式、URL、响应状态码、执行时间;

HEADERS:

  在BASIC的基础上,增加 请求头、响应头;

FULL:

  在HEADERS的基础上,增加了 请求和响应的正文、元数据;

How

@Configuration
public class FeignConfig {

    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}



#feign日志
logging:
  level: #feign日志以什么级别、作用在哪些接口
    com.an.service.PaymentService: debug

  

 

 





 

posted on 2022-08-02 16:47  anpeiyong  阅读(90)  评论(0编辑  收藏  举报

导航