Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 客户端组件提供一系列完善的配置项,如:连接超时,重试等。
简单的说,就是在配置文件中列出 Load Balancer 后面所有的机器,Ribbon 会自动的帮助你基于某种策略(例如:简单轮询,随即连接等等)去调用这些主机。而且,我们可以很容易使用 Ribbon 实现自定义的负载均衡算法,点击查看“Netflix Ribbon 教程”。
在 Netflix Feign 中,RibbonModule 模块覆盖了 Feign 客户端的 URL 解析,添加了由 Ribbon 提供的智能路由和弹性能力。
RibbonModule 模块包含了一个 Feign 的 Target(LoadBalancingTarget) 和 Client(RibbonClient) 适配器,以利用 Ribbon 负载均衡能力。
注意:Ribbon 集成依赖于 Feign 的 Target.url() 被编码为类似于“https://myAppProd”的形式,其中“myAppProd”是 Ribbon 客户端或负载均衡器名称,并且设置了“myAppProd.ribbon.listOfServers”配置。
添加 RibbonClient 会覆盖 Feign 客户端的 URL 解析,增加由 Ribbon 提供的智能路由和弹性能力。
使用下面代码:
MyService api = Feign.builder() .client(RibbonClient.create()) .target(MyService.class, "https://myAppProd");
代替
MyService api = Feign.builder() .target(MyService.class, "https://myAppProd-1234567890.us-east-1.elb.amazonaws.com");
使用或扩展 LoadBalancingTarget 将通过 Ribbon 实现动态 URL 发现,包括增加服务器请求计数。
使用下面代码:
MyService api = Feign.builder() .target(LoadBalancingTarget.create(MyService.class, "https://myAppProd"));
代替
MyService api = Feign.builder() .target(MyService.class, "https://myAppProd-1234567890.us-east-1.elb.amazonaws.com");
官网地址:https://github.com/OpenFeign/feign/tree/master/ribbon
下面将演示如何将 Netflix Feign 和 Ribbon 进行集成,假如我们启动了两个 ServiceDemoApplication 服务,分别位于 8090 和 8091 端口,如下图:

集成详细步骤如下:
(1)添加 Ribbon 的 Maven 依赖
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-ribbon</artifactId> <version>11.8</version> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-httpclient</artifactId> <version>2.7.18</version> </dependency>
(2)编写一个简单的 hello 服务,返回服务的名称和端口,如下:
package com.hxstrive.service_demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServiceDemoApplication {
@Value("${spring.application.name}")
private String appName;
@Value("${server.port}")
private String appPort;
@GetMapping("/hello")
public String hello() {
return "Hello World! appName=" + appName + ", appPort=" + appPort + "!";
}
}(3)添加 Ribbon 配置文件 ribbon.properties,配置 Ribbon 服务列表等信息,如下:
# 最大重试次数 user.ribbon.MaxAutoRetries=1 # (不包括第一个服务器)要重试的下一个服务器的最大数量 user.ribbon.MaxAutoRetriesNextServer=1 # 对于这个客户端,是否所有操作都可以重试 user.ribbon.OkToRetryOnAllOperations=true # 从源刷新服务器列表的时间间隔 user.ribbon.ServerListRefreshInterval=2000 # Apache HttpClient 使用的连接超时时间 user.ribbon.ConnectTimeout=3000 # Apache HttpClient 使用的读取超时时间 user.ribbon.ReadTimeout=3000 # 初始服务器列表,可在运行时通过 Archaius 动态属性进行更改 user.ribbon.listOfServers=http://localhost:8090,http://localhost:8091 user.ribbon.EnablePrimeConnections=true
(4)编写 Feign 客户端,初始化 Ribbon,如下图:
package com.hxstrive.demo_netflix_feign.feign;
import com.netflix.config.ConfigurationManager;
import feign.Contract;
import feign.Feign;
import feign.RequestLine;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.ribbon.RibbonClient;
public interface RibbonFeign {
// 定义获取用户信息的方法
@RequestLine("GET /hello")
String hello();
// 创建Feign客户端实例的静态方法
static RibbonFeign create() {
try {
ConfigurationManager.loadPropertiesFromResources("ribbon.properties");
System.out.println(ConfigurationManager.getConfigInstance().getProperty("user.ribbon.listOfServers"));
} catch (Exception e) {
e.printStackTrace();
}
return Feign.builder()
.client(RibbonClient.create())
.encoder(new Encoder.Default())
.decoder(new Decoder.Default())
.contract(new Contract.Default())
.target(RibbonFeign.class, "http://user");
}
}(5)访问接口,多刷新几次,你会发现以轮训的方式调用目标服务,如下图:

注意,除了使用 RibbonClient 实现 Ribbon,还可以使用 LoadBalancingTarget 实现相同的效果,如下:
package com.hxstrive.demo_netflix_feign.feign;
import com.netflix.config.ConfigurationManager;
import feign.Contract;
import feign.Feign;
import feign.RequestLine;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.ribbon.LoadBalancingTarget;
import feign.ribbon.RibbonClient;
public interface RibbonFeign {
// 定义获取用户信息的方法
@RequestLine("GET /hello")
String hello();
// 创建Feign客户端实例的静态方法
static RibbonFeign create() {
try {
ConfigurationManager.loadPropertiesFromResources("ribbon.properties");
System.out.println(ConfigurationManager.getConfigInstance().getProperty("user.ribbon.listOfServers"));
} catch (Exception e) {
e.printStackTrace();
}
return Feign.builder()
.encoder(new Encoder.Default())
.decoder(new Decoder.Default())
.contract(new Contract.Default())
// LoadBalancingTarget
.target(LoadBalancingTarget.create(RibbonFeign.class, "http://user"));
}
}注意,在生产环境中,可以将初始化 Ribbon 的代码放到 Spring Boot 的启动完成监听器,如下:
package com.hxstrive.demo_netflix_feign.listener;
import com.netflix.config.ConfigurationManager;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
/**
* APP 启动完成监听器
*/
public class AppReadyListener {
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
System.out.println("## 应用已经完全准备好,可以接收请求啦!");
// 可以在这里添加检查服务是否可用、预热缓存等逻辑
// ribbon 配置文件加载
try {
ConfigurationManager.loadPropertiesFromResources("ribbon.properties");
System.out.println(ConfigurationManager.getConfigInstance().getProperty("user.ribbon.listOfServers"));
} catch (Exception e) {
e.printStackTrace();
}
}
}添加 Spring Boot 配置文件,如下:
package com.hxstrive.demo_netflix_feign.config;
import com.hxstrive.demo_netflix_feign.listener.AppReadyListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* APP 配置
*/
@Configuration
public class AppConfig {
@Bean
public AppReadyListener appReadyListener() {
return new AppReadyListener();
}
}效果和上面一样。