一、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 # 请求处理的超时时间