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
*/

java 复制代码
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<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;

java 复制代码
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、指定负载均衡策略

java 复制代码
        @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_common

复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>com.hg</groupId>
    <artifactId>springcloud_common</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

2)feign接口

package com.hg.feign;

java 复制代码
            @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 复制代码
<?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>com.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>com.hg</groupId>
            <artifactId>springcloud_common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign接口-->
        <dependency>
            <groupId>com.hg</groupId>
            <artifactId>feign_interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

3)controller

java 复制代码
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

java 复制代码
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 策略优化服务选择逻辑(如按响应时间加权、重试等)。

java 复制代码
        @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 # 请求处理的超时时间

相关推荐
青鱼入云8 小时前
如何使用Spring Cloud Gateway实现动态路由?
spring cloud·微服务
说话的鲸鱼12 小时前
‌Whisper模型在RTranslator中的实时语音识别优化:动态资源分配与负载均衡
whisper·负载均衡·语音识别
阿琦学代码12 小时前
Spring Cloud(微服务) 概述
后端·spring·spring cloud
.柒宇.13 小时前
《云岚到家》第一章个人总结
spring boot·spring·spring cloud
bxlj_jcj1 天前
Nacos注册中心:从服务注册到负载均衡
spring cloud·nacos
qq_5470261791 天前
SpringCloud--Sleuth 分布式链路追踪
后端·spring·spring cloud
掘金安东尼1 天前
AWS × Caddy:一键部署多站点反向代理 + 负载均衡网关(Terraform + ECS Fargate)
负载均衡·aws·terraform
技术杠精1 天前
Docker Swarm 的负载均衡和平滑切换原理
docker·容器·负载均衡·1024程序员节
咕噜企业签名分发-淼淼1 天前
app分发平台哪个好点?手机app应用内测分发平台支持负载均衡的重要性
运维·智能手机·负载均衡