上文介绍了服务如何通过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. 三分钟学会@Autowired@Qualifier@Primary注解

    三分钟学会@Autowired@Qualifier@Primary注解 2018.10.08 20:24 154浏览 今天主要简单的跟大家介绍一下spring自动装配相关的@Autowired,@Qu ...

  2. poj 2993

    跟poj 2996反过来了,这里比较麻烦的就是处理白棋和黑棋各棋子对应的位置 还有在最后打印棋盘式|,:,.的时候会有点繁琐(- - ACMer新手 ): 直接看代码吧: #include<cs ...

  3. 140种Python标准库、第三方库和外部工具

    导读:Python数据工具箱涵盖从数据源到数据可视化的完整流程中涉及到的常用库.函数和外部工具.其中既有Python内置函数和标准库,又有第三方库和工具. 这些库可用于文件读写.网络抓取和解析.数据连 ...

  4. java IO的概述和File方法

    IO流用来处理设备之间的数据传输        Java对数据的操作是通过流的方式        Java用于操作流的对象都在IO包中 File类在整个IO包中与文件本身有关的操作类,所有的与文件本身 ...

  5. CSS多余文本省略号显示

    CSS多余文本省略号显示 本次案例代码是在 elementui 当中的 table 组件中实际需求 当然使用的是纯 CSS3 代码,所以原生支持度高,兼容性高,所以可多场景应用 对于过长文本进行单行省 ...

  6. ssh 简写

    << remotessh remotessh 这一对之间,可以写多个命令,换行即可. 否者就简单的 双引号,里面每个命令用分号隔开. 注意: 在远程服务器上的执行权限. 注意:login密 ...

  7. 王雅超的学习笔记-大数据hadoop集群部署(七)

    MySQL的安装部署

  8. Spring Boot 整合 slf4j+log4j 实现日志管理

    一:首先新建一个jar项目,如下图: 二:添加log4j的依赖,如下pom.xml文件: <project xmlns="http://maven.apache.org/POM/4.0 ...

  9. U3D Shader_图片模糊处理

    shader"practice/12.14"{ properties { _MainTex("MainTex",2D) = ""{} } S ...

  10. 20191121-10 Scrum立会报告+燃尽图 06

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/10070 一:组名: 组长组 组长:杨天宇 组员:魏新  罗杨美慧  王歆 ...