如何使用原生的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原来提供的功能是很单一 ...
随机推荐
- Xshell 为什么会出现中文乱码?
在网上下载xshell并成功安装了,但是当登录服务器查看中文时却出现了乱码的现象呢?这是怎么回事呢?本集小编就同大家详细讲讲. 图1:使用中文命名文档 现象: 登录服务器查看中文却出现乱码 原因分析: ...
- Django边学边记—模型查询
查询集 两大特性 惰性执行:创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代.序列化.与if合用 缓存:查询集的结果被存下来之后,再次查询时会使用之前缓存的数据 返回列 ...
- Python中“if __name__=='__main__':”
在Python当中,如果代码写得规范一些,通常会写上一句"if name=='main:"作为程序的入口,但似乎没有这么一句代码,程序也能正常运行.这句代码多余吗?原理又在哪里? ...
- opencv官宣
opencv官方文档地址 https://docs.opencv.org/master/ 安装opencv(cv2)官方地址 https://pypi.org/project/opencv-pytho ...
- 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 祝新的一年牛气冲天 ! | v32.02
百篇博客系列篇.本篇为: v32.xx 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- span标签的巧用
前言: 用struts的标签结合<td>标签将后台数据在表格里渲染了出来,目前需求是需要将两个状态组合在一起显示 解决:通过span标签在td里的套用可以实现 <logic:notE ...
- 深入浅出WPF-08.Event( 事件)01
事件(Event) 首先我们来继续说一下UI组件树,因为WPF事件 的路由环境就是组件树.WPF中的树有两种,一种是逻辑树(Logical Tree),一种是可视元素树(Visual Tree).逻辑 ...
- 小记SpringMVC与SpringBoot 的controller的返回json数据的不同
近期由于项目的改动变更,在使用springmvc和springboot测试的时候发现一个有趣的现象 1.springmvc的controller使用@ResponseBody返回的仅仅是json格式的 ...
- netty 处理客户端连接
Netty如何处理连接事件 上文讲了Netty如何绑定端口,现在我们来阅读下netty如何处理connect事件.上文我们说了NioEventLoop启动后不断去调用select的事件,当客户端连接时 ...
- 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)
1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...