Spring Cloud(二):Web服务客户端之Ribbon
上文介绍了服务如何通过Eureka实现注册,以及如何从Eureka获取已经注册的服务列表。那么拿到注册服务列表后, 如何进行服务调用?一个简单的实现是可以从被调用服务的实例列表中选择一个服务实例,通过其hostname(或IP),端口,及API的路径拼接成完整的url,通过http client来完成调用。但生产环境中,为了高性能、高可用等要素,服务的调用一般涉及负载均衡、故障转移、失败重试等实现,因此引入实现这些功能的客户端组件也成为了微服务架构中的必备要素。Spring Cloud中可通过Ribbon与Feign来实现服务间的调用。
本系列文章与示例均基于最新的Spring Cloud Hoxton版编写。
Ribbon
Ribbon是一个可实现负载均衡的Web客户端。我们一般理解的负载均衡是在服务端实现的,如Nginx(但这都是相对的,如果相对后端服务来说,也可以把Nginx当做一个实现了负载均衡的客户端), 而Ribbon是客户端的负载均衡实现。
Ribbon的核心概念是命名的客户端(named client),Spring Cloud会为每个命名客户端创建一个子应用上下文(ApplicationContext),在该上下文中,通过RibbonClientConfiguration创建ILoadBalancer,RestClient,ServerListFilter等Bean。
Spring Cloud Netflix提供的默认的Ribbon bean及说明
| Bean类型 | 默认实现类 | 说明 |
|---|---|---|
| IClientConfig | DefaultClientConfigImpl | Ribbon客户端配置加载实现,加载各实现bean及客户端连接超时、通讯超时等配置 |
| IRule | ZoneAvoidanceRule | 基于zone与可用性来过滤服务器的规则实现 |
| IPing | DummyPing | 判断服务器是否存活的实现,默认总是返回true |
| ServerList | ConfigurationBasedServerList | 获取服务器列表的实现,默认基于配置 |
| ServerListFilter | ZonePreferenceServerListFilter | 服务器过滤实现,默认过滤出与客户端在同一个zone中的服务器列表 |
| ILoadBalancer | ZoneAwareLoadBalancer | 负载均衡实现,默认根据zone的请求负载量排除掉负载最高的zone,从剩下的zone中选择一个根据给定的Rule选择其中一个服务器 |
| ServerListUpdater | PollingServerListUpdater | 动态的服务器列表更新器 |
Spring Cloud允许我们通过声明一个configuration来对客户端进行自定义,来调整或覆盖上述默认实现,如
@Configuration |
这样,客户端将由RibbonClientConfiguration 与 CustomConfiguration中定义的组件一起组成,且CustomConfiguration 中的组件会覆盖前者。
注意CustomConfiguration 必须是@Configuration 修饰的类,且不能被main application context的 @ComponentScan 扫描,否则会被所有@RibbonClients 共享
如果要为所有Ribbon Clients定制默认配置,则可使用@RibbonClients 注解
@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class) |
也可以通过配置属性来定制Ribbon Client,支持的配置属性
<clientName>.ribbon.NFLoadBalancerClassName: ILoadBalancer接口实现类 |
比如对于一个服务名称为users的配置
users: |
配置属性的优先级 > configuration指定配置类的优先级 > 默认RibbonClientConfiguration的优先级, 即同样的实现,前者覆盖后者。
当Eureka与Ribbon同时存在时,ribbonServerList会被 DiscoveryEnabledNIWSServerList覆盖,从Eureka来获取server list,同时 NIWSDiscoveryPing也会替换IPing接口,代理Eureka来确定服务器是否处于运行状态。
Ribbon的超时与重试配置
- <clientName>.ribbon.ConnectTimeout: 请求连接超时时间,默认2000
- <clientName>.ribbon.ReadTimeout: 请求处理超时时间,默认5000
- <clientName>.ribbon.MaxAutoRetries: 在同一台服务器上的重试次数,排除第一次调用,默认0
- <clientName>.ribbon.MaxAutoRetriesNextServer: 切换服务器的重试次数,默认1
- <clientName>.ribbon.OkToRetryOnAllOperations: 对所有请求都进行重试,默认false
当项目中添加了Spring Retry的依赖,则会启用重试机制。当请求失败时,会再尝试访问当前服务器(次数由MaxAutoRetries配置),如果不行,就换一个服务器进行访问,如果还是不行,再换服务器访问(更换次数由MaxAutoRetriesNextServer配置),如果还是不行,则返回请求失败。
Ribbon的负载均衡策略
前文提到Ribbon的负载均衡默认实现为ZoneAwareLoadBalancer,那么Ribbon提供的负载均衡策略还有哪些? 罗列如下
- BestAvailableRule: 排除掉断路器打开的服务器,选取并发请求最小的服务器
- AvailabilityFilteringRule: 过滤掉断路器打开或活跃连接数超过限制(通过<clientName>.<nameSpace>.ActiveConnectionsLimit配置,默认为Integer.MAX_VALUE)的服务器
- WeightedResponseTimeRule: 根据平均响应时间来动态为服务器赋予权值,实现基于权重的轮询
- RetryRule: 对选择负载均衡策略添加重试机制
- RoundRobinRule: 简单轮询
- RandomRule: 随机轮询
- ZoneAvoidanceRule: 结合区域与可用性来选择服务器,也是默认实现
可通过如下配置修改Ribbon的负载均衡策略
client-name: |
案例演示
本文案例演示基于上文搭建的springcloud-eureka 与 springcloud-eureka-client 两个示例项目 (源码),依次启动两个项目,然后将springcloud-eureka-client项目的端口 server.port改为8081,新开一个springboot运行配置,如图

以8081端口再起一个springcloud-eureka-client的服务实例。这是查看Eureka页面 http://localhost:8761/, 可以看到hello-service服务注册了两个实例

新建springcloud-ribbon项目 (源码)
pom.xml中引入依赖
<dependency> |
编写测试接口, LoadBalanceClient 是Ribbon的API
@RestController |
启动springcloud-ribbon, 调用测试接口 http://localhost:8082/ribbon, 可以看到返回结果交替显示 http://CN-201911061714:8080, http://CN-201911061714:8081 (CN-201911061714是我电脑的hostname,你的可能不一样),可见Ribbon实现了客户端的负载均衡。
一些知识点
Ribbon如果对所有请求进行重试,则需要保证接口的幂等性(多次调用产生的结果是一致的)
每一个命名的Ribbon客户端都有一个相应的由Spring cloud维护的子应用上下文,默认是lazy load的(第一次请求客户端时才load),可以通过如下配置更改为启动立即加载
ribbon:
eager-load:
enabled: true
clients: client1, client2, client3client.ribbon.* 针对单个客户端进行配置,针对所有客户端默认配置,则使用ribbon.*
当结合断路器使用时, 断路器的超时时间要大于Ribbon的超时时间,不然不会触发重试(还没重试就触发断路器打开了)
除了Ribbon,能做负载均衡访问的Web客户端还有@LoadBalance 注解的RestTemplate, 与Feign
认真生活,快乐分享
欢迎关注微信公众号:空山新雨的技术空间
Spring Cloud(二):Web服务客户端之Ribbon的更多相关文章
- Spring Cloud(二):服务消费者
创建“服务消费者” 创建一个基础的Spring Boot工程,命名为springboot-consumer,并在pom.xml中引入需要的依赖内容: <dependency> <gr ...
- Spring Cloud(三):Web服务客户端之Feign
前文介绍了实现客户端负载均衡的Ribbon,但直接使用Ribbon的API来实现服务间的调用相对较为繁琐,服务间的调用能否像本地接口调用一样便捷.透明,更符合编程习惯呢?Feign就是用来干这事的. ...
- Spring Cloud gateway 网关服务二 断言、过滤器
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- spring cloud 声明式rest客户端feign调用远程http服务
在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.Feign就是Spring Cloud提供的一种声明式R ...
- Spring Cloud构建微服务架构(二)服务消费者
Netflix Ribbon is an Inter Process Communication (IPC) cloud library. Ribbon primarily provides clie ...
- spring cloud(二)服务(注册)中心Eureka
Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现.也是springcloud体系中最重要最核心的组 ...
- Spring Cloud构建微服务架构(二)分布式配置中心
注:此文不适合0基础学习者直接阅读,请先完整的将作者关于微服务的博文全部阅读一遍,如果还有疑问,可以再来阅读此文,地址:http://blog.csdn.net/sosfnima/article/d ...
- Spring Cloud 声明式服务调用 Feign
一.简介 在上一篇中,我们介绍注册中心Eureka,但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和Feign一起讲比较好,因为在实际项目中,都是使用声 ...
- 第1章 Spring Cloud 构建微服务架构(一)服务注册与发现
一.Spring Cloud 简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总 ...
随机推荐
- excel中如何筛选功能的使用
excel中如何筛选功能的使用 excel是一款数据处理工具,可以在众多的数据中找到想要的经过处理之后的数据,而最直接方便的功能就是筛选.请阅读下文,了解如何对数据进行筛选. 如下图所示的学生成绩中, ...
- 洛谷P1809 过河问题 经典贪心问题
作者:zifeiy 标签:贪心 题目链接:https://www.luogu.org/problem/P1809 我们假设第 \(i\) 个人过河的耗时是 \(t[i]\) ,并且 \(t[i]\) ...
- PHP+MySQL实现对一段时间内每天数据统计优化操作实例
http://www.jb51.net/article/136685.htm 这篇文章主要介绍了PHP+MySQL实现对一段时间内每天数据统计优化操作,结合具体实例形式分析了php针对mysql查询统 ...
- Mysql5.7在忘记密码的情况下如何修改密码?
1.停止服务 2.mysqld --skip-grant-tables 3.回车之后就不要动了,再新打开一个命令提示符窗口,同样进入mysql的安装目录下, 输入:mysql -u root -p 密 ...
- H3C 因特网域名结构树
- linux seqlock 锁
内核包含了一对新机制打算来提供快速地, 无锁地存取一个共享资源. seqlock 在这 种情况下工作, 要保护的资源小, 简单, 并且常常被存取, 并且很少写存取但是必须要快. 基本上, 它们通过允许 ...
- 2019-1-20-VisualStudio-安装-Python-开发
title author date CreateTime categories VisualStudio 安装 Python 开发 lindexi 2019-01-20 10:51:15 +0800 ...
- 阿里云 CentOS8 Repo
# CentOS-Base.repo # # The mirror system uses the connecting IP address of the client and the # upda ...
- vue动态组件-根据数据展示特定组件
vue中有个内置组件component,利用它可以实现动态组件,在某些业务场景下可以替换路由 假设有以下三个组件: com1.com2.com3 有一个外层路/coms中代码如下 <templa ...
- jsp页面获取当前系统时间
value="<% out.print(new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(n ...