如何使用原生的Ribbon
什么是Ribbon
之前分析了如何使用原生的Feign,今天我们来研究 Netflix 团队开发的另外一个类库--Ribbon。
Ribbon 和 Feign 有很多相似的地方,首先,它们本质上都是 HTTP client,其次,它们都具备重试、集成断路器等功能。最大的区别在于,Ribbon 内置了一个负载均衡器,而 Feign 没有。
本文将介绍如何使用原生的 Ribbon,注意是原生的,而不是被 Spring 层层封装的 Ribbon。
为什么要使用Ribbon
这里我们需要回答两个问题:
- 为什么要使用 HTTP client?
- 为什么要在 HTTP client 里内置负载均衡器?
其中,第一个问题在如何使用原生的Feign中已经讲过,这里就不啰嗦了,我们直接看第二个问题。
我们知道,Apache HTTP client、Feign 并没有内置负载均衡器,也就是说,HTTP client 并不一定要内置负载均衡器,那为什么 Ribbon 要搞特殊呢?
其实,我们可以想想,Ribbon 更多地被用在内部调用,而这种场景有一个比较大的特点--目标服务为集群部署。通常情况下,在调用目标服务时,我们希望请求尽可能平均地分发到每个实例。通过内置的负载均衡器,Ribbon 可以很好地满足要求,而 Apache HTTP client、Feign 就无法做到。
所以,在 HTTP client 里内置负载均衡器是为了能够在目标服务为集群部署时提供负载均衡支持。
有的人可能会说,你单独部署一台负载均衡器就行了嘛,搞那么复杂干嘛。当然,你可以这么做。但是你要考虑很重要的一点,mid-tier services 的请求量要远大于 edge services,所以你需要一台性能极高的负载均衡器。从这个角度来说,Ribbon 的方案帮你省下了独立部署负载均衡器的开销。
如何使用Ribbon
项目中我用 RxNettty 写了一个简单的 HTTP 接口(见cn.zzs.ribbon.RxUserServer
)供后面的例子调用,这个接口运行在本机的 8080、8081、8082 接口,用来模拟三台不同的实例。所以,如果你想要测试项目中的例子,要先把这三台实例先启动好。
http://127.0.0.1:8080/user/getUserById?userId={userId}
request:userId=1
response:User [id=1, name=zzs001, age=18]
这里提醒一下,Ribbon 的 API 用到了很多 RxJava 代码,如果之前没接触过,最好先了解下。
项目环境
os:win 10
jdk:1.8.0_231
maven:3.6.3
IDE:Spring Tool Suite 4.6.1.RELEASE
Ribbon:2.7.17
作为HTTP client的用法
和 Feign 一样,Ribbon 支持使用注解方式定义 HTTP 接口,除此之外,Ribbon 还支持使用HttpRequestTemplate
、HttpClientRequest
等方式定义,这部分的例子我也提供了,感兴趣可以移步项目源码。
服务实例的列表通过ConfigurationManager
设置。当你看到ConfigurationManager
时,会不会觉得很熟悉呢?我们之前在Eureka详解系列(三)--探索Eureka强大的配置体系中详细介绍过,没错,Ribbon 用的还是这套配置体系。需要强调下,Netflix 团队开发的这套配置体系提供了动态配置支持(当然,你要会用才行),正是基于这一点,集成了 eureka 的应用才能够实现服务实例的动态调整。
// 使用注解定义HTTP API
@ClientProperties(properties = {
@Property(name="ReadTimeout", value="2000"),
@Property(name="ConnectTimeout", value="1000"),
@Property(name="MaxAutoRetries", value="1"),
@Property(name="MaxAutoRetriesNextServer", value="2")
}, exportToArchaius = true)
interface UserService {
@TemplateName("getUserById")
@Http(
method = HttpMethod.GET,
uri = "/user/getUserById?userId={userId}",
headers = {
@Header(name = "X-Platform-Version", value = "xyz"),
@Header(name = "X-Auth-Token", value = "abc")
})
RibbonRequest<ByteBuf> getUserById(@Var("userId") String userId);
}
public class RxUserProxyTest {
@Test
public void testBase() throws InterruptedException {
// 指定服务实例的地址
// key:服务+“.ribbon.”+配置项名称(见com.netflix.client.config.CommonClientConfigKey)
ConfigurationManager.getConfigInstance().setProperty(
"UserService.ribbon.listOfServers", "127.0.0.1:8080,127.0.0.1:8081,127.0.0.1:8082");
UserService userService = Ribbon.from(UserService.class);
userService.getUserById("1")
.toObservable()
.subscribe(new Subscriber<Object>() {
@Override
public void onCompleted() {
LOG.info("onCompleted");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onNext(Object t) {
LOG.info("onNext:{}", t);
if(t != null && t instanceof ByteBuf) {
LOG.info(ByteBuf.class.cast(t).toString(Charset.defaultCharset()));
}
}
});
// 因为请求HTTP接口是异步的,这里要让测试主线程先睡一会
Thread.sleep(10000);
}
}
默认的负载均衡规则
为了观察多次请求在三台实例的分配情况,现在我们更改下代码,试着发起 6 次请求。
@Test
public void test01() throws InterruptedException {
ConfigurationManager.getConfigInstance().setProperty(
"UserService.ribbon.listOfServers", "127.0.0.1:8080,127.0.0.1:8081,127.0.0.1:8082");
UserService userService = Ribbon.from(UserService.class);
// 发起多次请求
Observable<ByteBuf>[] requestList = new Observable[]{
userService.getUserById("1").toObservable(),
userService.getUserById("2").toObservable(),
userService.getUserById("3").toObservable(),
userService.getUserById("4").toObservable(),
userService.getUserById("5").toObservable(),
userService.getUserById("6").toObservable()
};
Observable.concat(Observable.from(requestList))
.subscribe(subscriber);
Thread.sleep(10000);
}
运行测试,可以看到,6 次请求被平均地分配到了 3 台实例。
在日志中,可以看到了默认的负载均衡规则。
通过源码可以看到,这个默认的规则本质上采用的是轮询策略RoundRobinRule
。除此之外,Ribbon 还定义了RandomRule
、RetryRule
等规则供我们选择。
public class AvailabilityFilteringRule {
RoundRobinRule roundRobinRule = new RoundRobinRule();
}
自定义负载均衡规则
自定义负载均衡规则需要继承com.netflix.loadbalancer.AbstractLoadBalancerRule
,并实现 choose 方法。这里我定义的规则是:不管有多少实例,默认访问第一台。
public class MyLoadBalancerRule extends AbstractLoadBalancerRule {
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
List<Server> allServers = lb.getAllServers();
return allServers.stream().findFirst().orElse(null);
}
}
接着,只需要通过ConfigurationManager
配置自定义规则就行。
@Test
public void test01() throws InterruptedException {
ConfigurationManager.getConfigInstance().setProperty(
"UserService.ribbon.listOfServers", "127.0.0.1:8080,127.0.0.1:8081,127.0.0.1:8082");
// 配置自定义规则
ConfigurationManager.getConfigInstance().setProperty(
"UserService.ribbon.NFLoadBalancerRuleClassName", "cn.zzs.ribbon.MyLoadBalancerRule");
UserService userService = Ribbon.from(UserService.class);
Observable<ByteBuf>[] requestList = new Observable[]{
userService.getUserById("1").toObservable(),
userService.getUserById("2").toObservable(),
userService.getUserById("3").toObservable(),
userService.getUserById("1").toObservable(),
userService.getUserById("2").toObservable(),
userService.getUserById("3").toObservable()
};
Observable.concat(Observable.from(requestList))
.subscribe(subscriber);
Thread.sleep(10000);
}
运行测试,可以看到,所有请求都被分配到了第一台实例。自定义负载均衡规则生效。
结语
以上,基本讲完 Ribbon 的使用方法,其实 Ribbon 还有其他可以扩展的东西,例如,断路器、重试等等。感兴趣的话,可以自行分析。
最后,感谢阅读。
参考资料
本文为原创文章,转载请附上原文出处链接:https://www.cnblogs.com/ZhangZiSheng001/p/15484505.html
如何使用原生的Ribbon的更多相关文章
- 白话SpringCloud | 第四章:服务消费者(RestTemple+Ribbon+Feign)
前言 上两章节,介绍了下关于注册中心-Eureka的使用及高可用的配置示例,本章节开始,来介绍下服务和服务之间如何进行服务调用的,同时会讲解下几种不同方式的服务调用. 一点知识 何为负载均衡 实现的方 ...
- windows原生开发之界面疑云
windows桌面开发,界面始终是最大的困惑.我们对前端工具的要求,其实只有窗体设计器.消息映射,过分点的话自适应屏幕.模型绑定.能够免于手工书写,其实这个问题并不复杂,但VS不实现.QT语法 ...
- [GUI]界面开发类库-Ribbon风格 [转]
[GUI]界面开发类库 如果我们不十分清楚需要什么样的界面风格及如何实现,请按以下两个步骤操作: (1) 搞清楚这种风格叫什么名字 (2) 查现有的比较著名的GUI库是否已有相 ...
- Spring Cloud官方文档中文版-客户端负载均衡:Ribbon
官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_spring_cloud_netflix 文中例子我做了一些测试在:h ...
- spring-cloud-Zuul学习(三)【中级篇】--Filter链 工作原理与Zuul原生Filter【重新定义spring cloud实践】
这里开始记录zuul中级进阶内容.前面说过了,zuul主要是一层一层的Filter过滤器组成,并且Zuul的逻辑引擎与Filter可用其他基于JVM的语言编写,比如:Groovy. 工作原理 Zuul ...
- spring cloud 自定义ribbon客户端
一.自定义Ribbon客户端-[方式一]配置类 1.1.自定义负载规则 增加RibbonConfiguration.java配置类 public class RibbonConfiguration { ...
- 客户端负载均衡Ribbon之一:Spring Cloud Netflix负载均衡组件Ribbon介绍
Netflix:['netfliːks] ribbon:英[ˈrɪbən]美[ˈrɪbən]n. 带; 绶带; (打印机的) 色带; 带状物;v. 把…撕成条带; 用缎带装饰; 形成带状; L ...
- Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制
上一篇文章单独介绍了Ribbon框架的使用,及其如何实现客户端对服务访问的负载均衡,但只是单独从Ribbon框架实现,没有涉及spring cloud.本文着力介绍Ribbon的负载均衡机制,下一篇文 ...
- zuul源码分析-探究原生zuul的工作原理
前提 最近在项目中使用了SpringCloud,基于zuul搭建了一个提供加解密.鉴权等功能的网关服务.鉴于之前没怎么使用过Zuul,于是顺便仔细阅读了它的源码.实际上,zuul原来提供的功能是很单一 ...
随机推荐
- selenium-ide-2.3.0 组件在foxfire45.0无法安装的问题
楼主在安装selenium-ide组件时,尝试了下面两种方式都无法安装: 1.在forfire浏览器进行拖拽安装,页面无任何跳转.拖拽后回车安装,也没任何效果 2.附件组件-从文件安装添加组件,添加了 ...
- 详解Java中==和equals()的区别
众所周知,在 Java 编程中,程序员通常会使用==或equals()来简单的比较地址,内容是否相等.而这两者之间的使用区别,对于初学 Java 的同学来说可能会比较迷糊.我将根据下面的几段示例程序, ...
- 深入xLua实现原理之Lua如何调用C#
xLua是腾讯的一个开源项目,为Unity. .Net. Mono等C#环境增加Lua脚本编程的能力.本文主要是探讨xLua下Lua调用C#的实现原理. Lua与C#数据通信机制 无论是Lua调用C# ...
- HDU - 3790 最短路径问题 (dijkstra算法)
HDU - 3790 最短路径问题 Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费 ...
- CodeForce-702C Cellular Network(查找)
Cellular Network CodeForces - 702C 给定 n (城市数量) 和 m (灯塔数量): 给定 a1~an 城市坐标: 给定 b1~bm 灯塔坐标: 求出灯塔照亮的最小半径 ...
- Jmeter扩展组件开发(8) - 函数助手扩展开发demo
前提条件 1.pom文件引用ApacheJMeter_functions包 <dependency> <groupId>org.apache.jmeter</groupI ...
- qt5 打包exe执行文件
1.pyinstaller 安装 :pip install pyinstaller 执行:pyinstaller -F -w --icon=logo.ico xx.py 打包后的文件 在 dist 下 ...
- P4428-[BJOI2018]二进制【树状数组,set】
正题 题目链接:https://www.luogu.com.cn/problem/P4428 题目大意 长度为\(n\)的\(0/1\)串要求支持 修改一个位置 求区间\([l,r]\)有多少个子区间 ...
- 深入浅出WPF-06.Binding(绑定)03
MultiBinding(多路Binding) 当UI中的显示信息是由源Source中的多个数据来决定时,使用MultiBinding.他和Binding的区别是需要传递多个元数据,针对多个数据源需要 ...
- Kubernetes-Service介绍(一)-基本概念
前言 本篇是Kubernetes第八篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战.Pod篇暂时应该还缺少两篇,等Service和存储相关内容介绍以后,补充剩下的两篇,有状态的Pod会涉及 ...