SpringCloud 负载均衡Ribbon 和 声明式服务调用Feign

SpringCloud 负载均衡Ribbon 和 声明式服务调用Feign

一、ribbon的介绍

    1、什么是ribbon?

ribbon是基于***flix ribbon实现的一个工作在consumer端的负载均衡工具,提供了很多负载均衡策略:轮询、随机、权重、区域

1.1 随机策略

***.***flix.loadbalancer.RandomRule:该策略实现了从服务清单中随机选择一个服务实例的功能。

1.2轮询策略

***.***flix.loadbalancer.RoundRobinRule该策略实现按照线性轮询的方式依次选择实例的功能。具体实现如下,在循环中增加了一个count计数变量,该变量会在每次轮询之后累加并求余服务总数

2、ribbon的启动器

nacos已经集成了ribbon,故无启动器

二、ribbon的入门案例

1、开启ribbon

@Bean
        /**
         * 原理:
         *  ①拦截器---------"ribbon-provider"----------->List<Service> serviceList
         *  ②使用ribbon的负载均衡算法-------------serviceList-------------->Service.
         *  ③把url中的map的key替换为ip、port
         */

package ***.hg.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {

	@Bean
	/**
	 *  LoadBalanced工作原理:
	 *  1、ribbon会给RestTemplate添加拦截器,在拦截器中使用“ribbon-provider”获得
     *  List<ServiceInstance>
     *  2、再使用负载均衡算法获得一个ServiceInstance
     *  3、最后通过ServiceInstance把url中的“ribbon-provider”替换成ip和port
	 */
	//@LoadBalanced //开启负载均衡
	public RestTemplate getRestTemplate(){
		return new RestTemplate();
	}

	//随机策略
	@Bean
	public IRule iRule() {
		return new RandomRule();
	}
}

    2、调用provider

        //把ip和port换成map的key
        String url = "http://ribbon-provider/provider/getUserById/"+id;

package ***.hg.controller;

import ***.hg.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

@RestController
@RequestMapping(value = "/consumer")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/getUserById/{id}")
    public User getUserById(@PathVariable Integer id) {
        //不使用ribbon:ip:port
        //String serviceUrl = "127.0.0.1:9090";
        //使用ribbon:不再使用ip:port的方式,而是改成了serviceId(即Nacos中注册的服务名称)
        String serviceUrl = "ribbon-provider";
        return restTemplate.getForObject("http://" + serviceUrl + 
                                         "/provider/getUserById/" + id, User.class);
    }
}

3、指定负载均衡策略

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

三、ribbon的问题

  手动拼接url和参数显得好傻

---------------------------声明式服务调用Feign---------------------------

一、Feign的介绍

1、什么是Feign?

        feign是springcloud提供的声明式模板化(接口)的http客户端(工作在consumer端口)

        feign支持springmvc注解

        feign集成了ribbon也支持负载均衡

      feign = RestTemplate + ribbon

    2、feign的启动器

        spring-cloud-starter-openfeign

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

二、Feign的入门案例

    1、创建feign_provider

 拷贝ribbon_provider_1

2、创建feign_interface

        1)pom.xml

            spring-cloud-starter-openfeign
            springcloud_***mon

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>***.hg</groupId>
    <artifactId>springcloud_***mon</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

        2)feign接口

           package ***.hg.feign;

            @FeignClient("map的key")
            @RequestMapping("/provider")
            public interface UserFeign{

                @RequestMapping("/getUserById/{id}")
                public User getUserById(@PathVariable("id") Integer id);
            }

    3、创建feign_consumer

1)拷贝ribbon_consumer

     2)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>springcloud_parent</artifactId>
        <groupId>***.hg</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ribbon_consumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>***.hg</groupId>
            <artifactId>springcloud_***mon</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>***.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign接口-->
        <dependency>
            <groupId>***.hg</groupId>
            <artifactId>feign_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

        3)controller

package ***.hg.controller;

import ***.hg.feign.UserFeign;
import ***.hg.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Random;

@RestController
@RequestMapping(value = "/consumer")
public class ConsumerController {

    @Autowired
    private UserFeign userFeign;

    @RequestMapping(value = "/getUserById/{id}")
    public User getUserById(@PathVariable Integer id) {
        return userFeign.getUserById(id);
    }
}

        4)app

package ***.hg;

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(basePackages = "***.hg.feign")
@EnableFeignClients//开启feign接口扫描
public class ConsumerApp {

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

三、feign的工作原理

    1、扫描feign接口

        @EnableFeignClients开启feign注解的支持:FeignClientsRegistrar.registerFeignClients()扫描添加了@FeignClient注解 的接口,并生成代理类交给spring的ioc容器去管理

    2、代理类做的事

        SynchronousMethodHandler.invoke():创建RequestTemplate(HttpMethod、UriTemplate、Body)

四、feign的传参方式

1、restful参数

        @PathVariable("id")   //例如:/getUserById/520

 2、?传参

        @RequestParam("id")   //例如:/updateUserById?id=520

3、pojo

        @RequestBody   //例如:{id:250, name:"刘亦菲", age:18}

五、feign优化

    1、开启feign的日志

Feign 默认不输出日志,开启后可查看请求细节(如 URL、参数、响应等),便于调试

        logging:
          level:
            ***.hg.feign: debug #log4j的日志级别,“***.hg.feign”feign的包名
        feign:
          client:
            config:
              default:
              #feign-provider:
                loggerLevel: full #开启feign的日志

  2、GZIP压缩

通过压缩请求 / 响应数据,减少网络传输量,提高效率。

        ①开启浏览器和consumer之间的压缩

            server:
              ***pression:
                enabled: true #开启浏览器--->consumer的gzip压缩

        ②开启consumer和provider之间的压缩

            feign:
              ***pression:
                request:
                  enabled: true #开启consumer--->provider的gzip压缩
                response:
                  enabled: true

    3、http连接池

Feign 默认使用 JDK 的HttpURLConnection(无连接池,每次请求创建新连接),效率低。通过配置 HttpClient 或 OkHttp 连接池,复用连接,减少连接建立 / 关闭开销

        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

    4、负载均衡

Feign 默认集成 Ribbon 实现负载均衡,可通过自定义 Ribbon 策略优化服务选择逻辑(如按响应时间加权、重试等)。

默认是轮询

当一个请求快一个请求慢时,轮询就不再合适

        @Configuration
        public class FeignConfig {

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

    5、feign超时

Feign 调用默认超时时间较短(Ribbon 默认连接超时 1 秒,读取超时 1 秒),需根据业务场景调整,避免正常请求被中断。

        方式一:

            ribbon:
              ReadTimeout: 5000 # 请求连接的超时时间
              ConnectionTimeout: 5000 # 请求处理的超时时间

        方式二:

            feign:
              client:
                config:
                  #default:
                  feign-provider:
                    ConnectTimeout: 5000 # 请求连接的超时时间
                    ReadTimeout: 5000 # 请求处理的超时时间

feign更细腻

转载请说明出处内容投诉
CSS教程网 » SpringCloud 负载均衡Ribbon 和 声明式服务调用Feign

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买