上文介绍了服务如何通过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. index() 方法返回指定元素相对于其他指定元素的 index 位置。

  2. springboot + redis + 注解 + 拦截器 实现接口幂等性校验

    一.概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如: 订单接口, 不能多次创建订单 支付接口, 重复支付同一笔订单只能扣一次钱 支付宝回调接口, 可能会多 ...

  3. 模板——BigInteger

    #include <iostream> #include <cstring> #include <string> #include <vector> # ...

  4. H3C RIP基本配置举例

  5. H3C 用802.1Q和子接口实现VLAN间路由

  6. H3C 根据子网掩码计算子网数

  7. H3C配置设备的FTP服务

  8. Numpy 返回数组大小

    import numpy as np a = [[1, 2], [3, 4], [5, 6]] b = np.array(a) len(a) # 3 len(b) # 3 np.size(a) # 3 ...

  9. 【2016常州一中夏令营Day3】

    小 W 摆石子[问题描述]小 W 得到了一堆石子,要放在 N 条水平线与 M 条竖直线构成的网格的交点上.因为小 M 最喜欢矩形了,小 W 希望知道用 K 个石子最多能找到多少四边平行于坐标轴的长方形 ...

  10. Codeforces Round #524 (Div. 2) codeforces 1080A~1080F

    目录 codeforces1080A codeforces 1080B codeforces 1080C codeforces 1080D codeforces 1080E codeforces 10 ...