上文介绍了服务如何通过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
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class TestConfiguration { }

这样,客户端将由RibbonClientConfiguration 与 CustomConfiguration中定义的组件一起组成,且CustomConfiguration 中的组件会覆盖前者。

注意CustomConfiguration 必须是@Configuration 修饰的类,且不能被main application context的 @ComponentScan 扫描,否则会被所有@RibbonClients 共享

如果要为所有Ribbon Clients定制默认配置,则可使用@RibbonClients 注解

@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig { }

也可以通过配置属性来定制Ribbon Client,支持的配置属性

<clientName>.ribbon.NFLoadBalancerClassName: ILoadBalancer接口实现类
<clientName>.ribbon.NFLoadBalancerRuleClassName: IRule接口实现类
<clientName>.ribbon.NFLoadBalancerPingClassName: IPing接口实现类
<clientName>.ribbon.NIWSServerListClassName: ServerList接口实现类
<clientName>.ribbon.NIWSServerListFilterClassName: ServerListFilter接口实现类

比如对于一个服务名称为users的配置

users:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

配置属性的优先级 > 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:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

案例演示

本文案例演示基于上文搭建的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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

编写测试接口, LoadBalanceClient 是Ribbon的API

@RestController
public class RibbonTestController { @Autowired
private LoadBalancerClient loadBalancer; @GetMapping("ribbon")
public String testRibbon(){
ServiceInstance instance = loadBalancer.choose("hello-service");
return String.format("http://%s:%s", instance.getHost(),
instance.getPort());
}
}

启动springcloud-ribbon, 调用测试接口 http://localhost:8082/ribbon, 可以看到返回结果交替显示 http://CN-201911061714:8080, http://CN-201911061714:8081 (CN-201911061714是我电脑的hostname,你的可能不一样),可见Ribbon实现了客户端的负载均衡。

一些知识点

  1. Ribbon如果对所有请求进行重试,则需要保证接口的幂等性(多次调用产生的结果是一致的)

  2. 每一个命名的Ribbon客户端都有一个相应的由Spring cloud维护的子应用上下文,默认是lazy load的(第一次请求客户端时才load),可以通过如下配置更改为启动立即加载

    ribbon:
    eager-load:
    enabled: true
    clients: client1, client2, client3
  3. client.ribbon.* 针对单个客户端进行配置,针对所有客户端默认配置,则使用ribbon.*

  4. 当结合断路器使用时, 断路器的超时时间要大于Ribbon的超时时间,不然不会触发重试(还没重试就触发断路器打开了)

  5. 除了Ribbon,能做负载均衡访问的Web客户端还有@LoadBalance 注解的RestTemplate, 与Feign

本文示例代码


认真生活,快乐分享
欢迎关注微信公众号:空山新雨的技术空间

Spring Cloud(二):Web服务客户端之Ribbon的更多相关文章

  1. Spring Cloud(二):服务消费者

    创建“服务消费者” 创建一个基础的Spring Boot工程,命名为springboot-consumer,并在pom.xml中引入需要的依赖内容: <dependency> <gr ...

  2. Spring Cloud(三):Web服务客户端之Feign

    前文介绍了实现客户端负载均衡的Ribbon,但直接使用Ribbon的API来实现服务间的调用相对较为繁琐,服务间的调用能否像本地接口调用一样便捷.透明,更符合编程习惯呢?Feign就是用来干这事的. ...

  3. Spring Cloud gateway 网关服务二 断言、过滤器

    微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...

  4. spring cloud 声明式rest客户端feign调用远程http服务

    在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.Feign就是Spring Cloud提供的一种声明式R ...

  5. Spring Cloud构建微服务架构(二)服务消费者

    Netflix Ribbon is an Inter Process Communication (IPC) cloud library. Ribbon primarily provides clie ...

  6. spring cloud(二)服务(注册)中心Eureka

    Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现.也是springcloud体系中最重要最核心的组 ...

  7. Spring Cloud构建微服务架构(二)分布式配置中心

     注:此文不适合0基础学习者直接阅读,请先完整的将作者关于微服务的博文全部阅读一遍,如果还有疑问,可以再来阅读此文,地址:http://blog.csdn.net/sosfnima/article/d ...

  8. Spring Cloud 声明式服务调用 Feign

    一.简介 在上一篇中,我们介绍注册中心Eureka,但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和Feign一起讲比较好,因为在实际项目中,都是使用声 ...

  9. 第1章 Spring Cloud 构建微服务架构(一)服务注册与发现

      一.Spring Cloud 简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总 ...

随机推荐

  1. WOE:信用评分卡模型中的变量离散化方法(生存分析)

    WOE:信用评分卡模型中的变量离散化方法 2016-03-21 生存分析 在做回归模型时,因临床需要常常需要对连续性的变量离散化,诸如年龄,分为老.中.青三组,一般的做法是ROC或者X-tile等等. ...

  2. Flex AIR使用ADT命令打包 ipa

    1. 配置环境变量. 2. 测试adt命令 3. 将ShepherdPhone0815.mobileprovision和 my.p12文件都放入编译好的工程目录下,如下图: 4.切换到上述编译好的目录 ...

  3. LA 5031 Graph and Queries —— Treap名次树

    离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...

  4. CodeForces 242E "XOR on Segment"(线段树)

    传送门 •题意 给你一个包含 n 个数的序列 a,定义序列上的两个操作: (1)$1,l,r\ :\ ans=\sum_{i=l}^{r}a_i$; (2)$2,l,r,x\ :\ \forall\ ...

  5. 154th LeetCode Weekly Contest

    A B D均比较简单.先说C题 K-Concatenation Maximum Sum Given an integer array arr and an integer k, modify the ...

  6. P1089 过独木桥

    题目描述 今年的 CSP-J/S 比赛马上就要开始了,代码决定的 N 位女学生排队去参加比赛. 期间他们遇到了代码决定的 M 位男生组成的男生队伍. 他们堵在了一座独木桥前.但是独木桥每次只能过一个人 ...

  7. P1073 奇数还是偶数

    题目描述 给你 \(N(1 \le N \le 1000)\) 个数,你需要判断每个数是奇数还是偶数. 输入格式 输入的第一行包含一个整数 \(N(1 \le N \le 1000)\) . 接下来 ...

  8. linux 系统挂起

    尽管内核代码的大部分 bug 以 oops 消息结束, 有时候它们可能完全挂起系统. 如果系 统挂起, 没有消息打印. 例如, 如果代码进入一个无限循环, 内核停止调度,[15]15 并且系 统不会响 ...

  9. H3C 三种生成树协议的端口状态对比

  10. dotnet core 发布只带必要的依赖文件

    在使用 dotnet core 发布独立项目的时候,会带上大量依赖的库,但是通过微软提供的工具可以去掉一些在代码没有用到的库. 本文介绍的工具是 Microsoft.Packaging.Tools.T ...