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

一、ribbon的介绍

    1、什么是ribbon?

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

1.1 随机策略

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

1.2轮询策略

com.netflix.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 com.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
     *  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 com.hg.controller;
import com.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


    org.springframework.cloud
    spring-cloud-starter-openfeign

二、Feign的入门案例

    1、创建feign_provider

 拷贝ribbon_provider_1

2、创建feign_interface

        1)pom.xml

            spring-cloud-starter-openfeign
            springcloud_common


    org.springframework.cloud
    spring-cloud-starter-openfeign


    com.hg
    springcloud_common
    1.0-SNAPSHOT

        2)feign接口

           package com.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



    
        springcloud_parent
        com.hg
        1.0-SNAPSHOT
    
    4.0.0
    ribbon_consumer
    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.hg
            springcloud_common
            1.0-SNAPSHOT
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
        
            com.hg
            feign_interface
            1.0-SNAPSHOT
        
    

        3)controller

package com.hg.controller;
import com.hg.feign.UserFeign;
import com.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 com.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 = "com.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:
            com.hg.feign: debug #log4j的日志级别,“com.hg.feign”feign的包名
        feign:
          client:
            config:
              default:
              #feign-provider:
                loggerLevel: full #开启feign的日志

  2、GZIP压缩

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

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

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

        ②开启consumer和provider之间的压缩

            feign:
              compression:
                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更细腻

posted @ 2025-11-28 13:46  gccbuaa  阅读(0)  评论(0)    收藏  举报