什么是Ribbon

之前分析了如何使用原生的Feign,今天我们来研究 Netflix 团队开发的另外一个类库--Ribbon。

Ribbon 和 Feign 有很多相似的地方,首先,它们本质上都是 HTTP client,其次,它们都具备重试、集成断路器等功能。最大的区别在于,Ribbon 内置了一个负载均衡器,而 Feign 没有。

本文将介绍如何使用原生的 Ribbon,注意是原生的,而不是被 Spring 层层封装的 Ribbon。

为什么要使用Ribbon

这里我们需要回答两个问题:

  1. 为什么要使用 HTTP client?
  2. 为什么要在 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 还支持使用HttpRequestTemplateHttpClientRequest等方式定义,这部分的例子我也提供了,感兴趣可以移步项目源码。

服务实例的列表通过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 还定义了RandomRuleRetryRule等规则供我们选择。

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 还有其他可以扩展的东西,例如,断路器、重试等等。感兴趣的话,可以自行分析。

最后,感谢阅读。

参考资料

ribbon github

相关源码请移步:https://github.com/ZhangZiSheng001/ribbon-demo

本文为原创文章,转载请附上原文出处链接:https://www.cnblogs.com/ZhangZiSheng001/p/15484505.html

如何使用原生的Ribbon的更多相关文章

  1. 白话SpringCloud | 第四章:服务消费者(RestTemple+Ribbon+Feign)

    前言 上两章节,介绍了下关于注册中心-Eureka的使用及高可用的配置示例,本章节开始,来介绍下服务和服务之间如何进行服务调用的,同时会讲解下几种不同方式的服务调用. 一点知识 何为负载均衡 实现的方 ...

  2. windows原生开发之界面疑云

        windows桌面开发,界面始终是最大的困惑.我们对前端工具的要求,其实只有窗体设计器.消息映射,过分点的话自适应屏幕.模型绑定.能够免于手工书写,其实这个问题并不复杂,但VS不实现.QT语法 ...

  3. [GUI]界面开发类库-Ribbon风格 [转]

    [GUI]界面开发类库 如果我们不十分清楚需要什么样的界面风格及如何实现,请按以下两个步骤操作: (1)       搞清楚这种风格叫什么名字 (2)       查现有的比较著名的GUI库是否已有相 ...

  4. Spring Cloud官方文档中文版-客户端负载均衡:Ribbon

    官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_spring_cloud_netflix 文中例子我做了一些测试在:h ...

  5. spring-cloud-Zuul学习(三)【中级篇】--Filter链 工作原理与Zuul原生Filter【重新定义spring cloud实践】

    这里开始记录zuul中级进阶内容.前面说过了,zuul主要是一层一层的Filter过滤器组成,并且Zuul的逻辑引擎与Filter可用其他基于JVM的语言编写,比如:Groovy. 工作原理 Zuul ...

  6. spring cloud 自定义ribbon客户端

    一.自定义Ribbon客户端-[方式一]配置类 1.1.自定义负载规则 增加RibbonConfiguration.java配置类 public class RibbonConfiguration { ...

  7. 客户端负载均衡Ribbon之一:Spring Cloud Netflix负载均衡组件Ribbon介绍

    Netflix:['netfliːks] ribbon:英[ˈrɪbən]美[ˈrɪbən]n. 带; 绶带; (打印机的) 色带; 带状物;v. 把…撕成条带; 用缎带装饰; 形成带状;     L ...

  8. Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制

    上一篇文章单独介绍了Ribbon框架的使用,及其如何实现客户端对服务访问的负载均衡,但只是单独从Ribbon框架实现,没有涉及spring cloud.本文着力介绍Ribbon的负载均衡机制,下一篇文 ...

  9. zuul源码分析-探究原生zuul的工作原理

    前提 最近在项目中使用了SpringCloud,基于zuul搭建了一个提供加解密.鉴权等功能的网关服务.鉴于之前没怎么使用过Zuul,于是顺便仔细阅读了它的源码.实际上,zuul原来提供的功能是很单一 ...

随机推荐

  1. 【第十九篇】- Maven NetBeans之Spring Cloud直播商城 b2b2c电子商务技术总结

    Maven NetBeans NetBeans 6.7 及更新的版本已经内置了 Maven.对于以前的版本,可在插件管理中心获取 Maven 插件.此例中我们使用的是 NetBeans 6.9. 关于 ...

  2. mybatis if else if 条件判断SQL片段表达式取值和拼接

    前言 最近在开发项目的时候涉及到复杂的动态条件查询,但是mybaits本身不支持if elseif类似的判断但是我们可以间接通过 chose when otherwise 去实现其中choose为一个 ...

  3. 使用Jmeter做接口测试(学生信息的6个接口)

    使用Jmeter做接口测试,案例中涉及到接口有:获取学生信息.登录.添加学生信息.学生金币充值.获取所有学生信息.文件上传. 一.获取学生信息(get请求) 服务器名称或IP:输入被请求服务器的名称或 ...

  4. thinkphp5.0框架运行机制分享小结

    1 访问index.php 入口文件,定义应用目录,加载框架引导文件 <?php // [ 应用入口文件 ] // 定义应用目录 define('APP_PATH', __DIR__ . '/. ...

  5. re.findall用法

    其中,re.findall() 函数可以遍历匹配,可以获取字符串中所有匹配的字符串,返回一个列表. 在python源代码中,展示如下: 搜索string,返回一个顺序访问每一个匹配结果(Match对象 ...

  6. 没想到 TCP 协议,还有这样的骚操作。。。

    大家好,我是小林. 昨晚有位读者问了我这么个问题: 大概意思是,一个已经建立的 TCP 连接,客户端中途宕机了,而服务端此时也没有数据要发送,一直处于 establish 状态,客户端恢复后,向服务端 ...

  7. AT4120-[ARC096D]Sweet Alchemy【贪心,背包】

    正题 题目链接:https://www.luogu.com.cn/problem/AT4120 题目大意 给出\(n\)个物品和一个容量\(m\),第\(i\)个物品体积为\(c_i\).除了第一个物 ...

  8. Filter和Interceptor

    Filter的使用 拦截user下的所有请求 @WebFilter("/user/*") public class UserFilter implements Filter { @ ...

  9. ElasticSearch搜索引擎

    官网:Elasticsearch:官方分布式搜索和分析引擎 | Elastic Elaticsearch,简称为es,es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储.检索数据;本身扩 ...

  10. 【理解OS】1.保护模式概述

    这个系列文章主要目的是为了记录我个人学习保护模式后的总结与一点点的思考.我也是一个学习者,其中由错误在所难免,若各位朋友指出将不胜感激. 1. Intel CPU的运行模式概述 这里我将粗略介绍Int ...