Spring Cloud Ribbon

Spring Cloud Ribbon

一.Sping Cloud Ribbon概述

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。

Ribbon中的核心概念是命名客户端的概念。每个负载均衡器是组合的组合的一部分,它们一起工作以根据需要联系远程服务器,并且集合具有您将其做为应用程序开发人员(例如使用@FeignClient注释)的名称。Spring Cloud使用RibbonClientConfiguration为每个命名的客户端根据需要创建一个新的集合,做为ApplicationContext。这包含(除其他外)IloadBalancer,

RestClient和ServerListFilter

 

Ribbon架构如下:

 

二. RestTemplate详解

2.1 HTTP请求的方法

(1)GET:通过请求URI得到资源
(2)POST:用于添加新的内容
(3)PUT:用于修改某个内容,若不存在则添加
(4)DELETE:删除某个内容
(5)OPTIONS :询问可以执行哪些方法
(6)HEAD :类似于GET, 但是不返回body信息,用于检查对象是否存在,以及得到对象的元数据
(7)CONNECT :用于代理进行传输,如使用SSL
(8)TRACE:用于远程诊断服务器

 

 

2.2 GET请求

对于Get请求,Spring的RestTemplate提供了许多的支持,这里仅仅列出常用的接口:

  public <T> T getForObject(String url, Class<T> responseType,Object... urlVariables) throws RestClientException

  public <T> T getForObject(String url, Class<T> responseType,Map<String, ?> urlVariables) throws RestClientException

  public <T> T getForObject(URI url, Class<T> responseType)throws RestClientException

 

对于GET请求来说,我一般常用的几种形式如下:

String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}",String.class,"42", "21");

或者下面这张形式:

Map<String, String> vars =Collections.singletonMap("hotel", "42");

String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}",String.class, vars);

以及:

Stringmessage =restTemplate.getForObject("http://localhost:8080/yongbarservice/appstore/appgoods/restTemplate?name=zhaoshijie&id=80",String.class );

 

2.3 POST请求

Spring的RestTemplate对post的常用接口:

public<T> T postForObject(String url, Object request, Class<T>responseType, Object... uriVariables)

                            throwsRestClientException

public<T> T postForObject(String url, Object request, Class<T>responseType, Map<String, ?> uriVariables)

                            throwsRestClientException

public<T> T postForObject(URI url, Object request, Class<T> responseType)throws RestClientException

我一般常用的方法为:

MultiValueMap<String,String> bodyMap = new LinkedMultiValueMap<String, String>();

bodyMap.setAll(urlVariables);

ResponseClassresponseClass = restTemplate.postForObject(CAR_CES_URL, bodyMap,ResponseClass.class);

以及:

 HttpHeaders headers = new HttpHeaders();

        headers.add("X-Auth-Token","e348bc22-5efa-4299-9142-529f07a18ac9");

 

        MultiValueMap<String, String>postParameters = new LinkedMultiValueMap<String, String>();

        postParameters.add("owner","11");

       postParameters.add("subdomain", "aoa");

        postParameters.add("comment","");

 

        HttpEntity<MultiValueMap<String,String>> requestEntity  = newHttpEntity<MultiValueMap<String, String>>(postParameters, headers);

 

        ParseResultVo exchange = null;

        try {

            exchange =restTemplate.postForObject("http://l-dnsutil1.ops.beta.cn6.qunar.com:10085/v1/cnames/tts.piao",  requestEntity, ParseResultVo.class);

            logger.info(exchange.toString());

        } catch (RestClientException e) {

            logger.info("。。。。");

        }

以及:

 DomainParam domainParam = new DomainParam();

        domainParam.setCustomerId(1);

        //...

 

        logger.info("....");

       restTemplate.getMessageConverters().add(newMappingJacksonHttpMessageConverter());

       restTemplate.getMessageConverters().add(newStringHttpMessageConverter());

        String responseResult =restTemplate.postForObject(url, domainParam, String.class);  

2.4 PUT请求

Spring的RestTemplate对put的常用接口:

put (String url, Object request, Object…urlVariables)

put (String url, Object request, MapurlVariables)

put (URI url, Object request)

2.5 DELETE请求

Spring的RestTemplate对delete的常用接口:

delete (String url, Object… urlVariables)

delete (String url, Map urlVariables)

delete (URI url)

三 负载均衡策略

 

3.1 简单轮询负载均衡

    以轮询的方式依次将请求调度不同的服务器,即每次调度执行i=(i+1) mod n

3.2 随机负载均衡

    随机选择状态为UP的server

3.3 加权响应时间负载均衡

 根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。

3.4 区域感知负载均衡

    区域感知负载均衡内置电路跳闸逻辑,可被配置基于区域同源关系(Zone Affinity,也就是更倾向于选择发出调用的服务所在的托管区域内,这样可以降低延迟,节省成本)选择目标服务实例。它监控每个区域中运行实例的行为,而且能够实时的快速丢弃一整个区域。这样在面对整个区域故障时,帮我们提升了弹性。

3.5 Ribbon自带负载均衡策略比较

策略名

策略声明

策略描述

实现说明

BestAvailableRule

public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule

选择一个最小的并发请求的server

逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server

AvailabilityFilteringRule

public class AvailabilityFilteringRule extends PredicateBasedRule

过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)

使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态

WeightedResponseTimeRule

public class WeightedResponseTimeRule extends RoundRobinRule

根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。

一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择 server。

RetryRule

public class RetryRule extends AbstractLoadBalancerRule

对选定的负载均衡策略机上重试机制。

在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server

RoundRobinRule

public class RoundRobinRule extends AbstractLoadBalancerRule

roundRobin方式轮询选择server

轮询index,选择index对应位置的server

RandomRule

public class RandomRule extends AbstractLoadBalancerRule

随机选择一个server

在index上随机,选择index对应位置的server

ZoneAvoidanceRule

public class ZoneAvoidanceRule extends PredicateBasedRule

复合判断server所在区域的性能和server的可用性选择server

使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个 zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的 Server。

 

四. 配置详解

4.1 Ribbon中的接口实现

通过自动化配置的实现,我们可以轻松地实现客户端负载均衡。同时针对一些个性化需求,我们可以方便地替换下面这些默认实现。

 

(1)IClientConfig:Ribbon的客户端配置,默认采用com.netflix.client.config.DefaultClientConfigImpl

(2)IRule:Ribbon的负载均衡策略,默认采用com.netflix.loadbalancer.ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问

(3)IPing:Ribbon的实例检查策略,默认采用com.netflix.loadbalancer.NoOpPing实现,该检查策略是一个特殊的实现,实际上它不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。

(4)ServerList<Server>:服务实例清单的维护机制,默认采用com.netflix.loadbalancer.ConfigurationBasedServerList实现

(5)ServerListFilter<Server>:服务实例清单的过滤机制,默认采用org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter实现,该策略能够优先过滤出请求调用方处于同区域的服务实例。

(6)IloadBalancer:负载均衡器,默认采用com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,它具备了区域感知的能力。

 

4.2 @RibbonClient和@RibbonClients 

 可以通过使用@RibbonClient注解来实现更细粒度的客户端配置,Spring Cloud允许通过使用@RibbonClient声明其他配置(位于RibbonClientConfiguration之上)来完全控制客户端。在这种情况下,客户端由RibbonClientConfiguration中已经存在的组件与FooConfiguration中的任何组件组成(后者通常会覆盖前者)

如下:

@Configuration

public class FooConfiguration {

    @Bean

    public IPingribbonPing(IClientConfig config) {

        return new PingUrl();

    }

}

 

@Configuration

@RibbonClient(name="foo",configuration=FooConfiguration.class)

publicclass TestConfiguration{

}

 

4.3 使用属性自定义Ribbon客户端

从1.2.0版本开,Spring CloudNetflix支持使用属性自定义Ribbon客户端。这允许我们在不同环境更改启动时的行为。这些属性中定义的类优先于使用@RibbonClient(configuration=MyRibbonConfig.class)定义的bean和Spring CloudNetflix提供的默认值。

支持的属性如下所示:应以<clientName>.ribbon.为前缀:

(1)      NFLoadBalancerClassName:应实施IloadBalancer

(2)      NFLoadBalancerRuleClassName:应实施Irule

(3)      NFLoadBalancerPingClassName:应实施IPing

(4)      NIWSServerListClassName:应实施ServerList

(5)      NIWSServerListFilterClassName应实施ServerListFilter

 

例如:要设置服务名称users的IRule,您可以设置以下内容:

Application.properties

    Users.ribbon.NFLoadBalancerRuleClassName:com.netflix.loadbancer.WeightedResponseTimeRule

 

4.4 使用Ribbon和Eureka集成

当Eureka与Ribbon结合使用(即两者都在类路径上)时,Ribbon的ServerList的维护机制实现将被将被DiscoveryEnabledNIWSServerList实例所覆盖,该实现会将服务清单列表交个Eureka的服务治理机制来进行维护。IPing的实现将被NIWSDiscoveeryPing实例所覆盖,该实现也将实例检查的任务交给了服务治理框架来进行维护,以确定服务器是否启动。默认情况下,用于获取实例请求的Serverlist接口实现将采用Eureka中的DomainExtractingServerList,其目的是使物理元数据可用于负载平衡器,而不使用AWS AMI元数据(Netflix依赖的是)。默认情况下,服务器列表将使用实例元数据(如远程客户机集eureka.instance.metadataMap.zone)中提供的“区域”信息构建,如果缺少,则可以使用服务器主机名中的域名做为代理对于区域(如果设置了标志approximateZoneFromHostname)。一旦区域信息可用,它可以在ServerListFilter中使用。默认情况下,它将用于定位与客户端相同区域的服务器,因为默认值为ZonePreferenceServerListFilter。默认情况下,即通过eureka.instance.metadataMap.zone,客户端的区域与远程实例的方式相同。

在于SpringCloud Eureka结合使用的时候,我们的配置将会变得更加简单。不再需要通过类似hello-service.ribbon.listOfServers的参数来制定具体的服务实例清单,因为Eureka将会为我们维护所有服务的实例清单。而对于Ribbon的参数配置,我们依然可以采用之前的两种配置方式来实现,而指定客户端的配置方式可以直接使用Eureka中的服务名做为<Client>来完成针对各个微服务的个性化配置。

此外,由于SpringCloud Ribbon默认实现了区域亲和策略,所以,我们可以通过Eureka实例的元数据配置来实现区域化实例配置方案。比如,可以将处于不同机房的实例配置成不同的区域值,以作为跨区域的容错机制实现。而实现方式非常简单,只需要在服务实例的元数据中增加zone参数来制定自己所在的区域。比如:

eureka.instance.metadataMap.zone=shanghai

在Spring CloudRibbon与Spring Cloud Eureka结合的工程中,我们也可以通过参数配置的方式来禁用Eureka对Ribbon服务实例的维护实现。只需要在配置文件中增加如下参数,这时我们对于服务实例的维护就有奖回到使用<client>.ribbon.listOfServers参数配置的方式来实现了。

ribbon.ereka.enabled=false

 

l  设置客户端区域的正统“archaius”方式是通过一个名为“@zone”的配置属性,如果可用,SpringCloud将优先使用所有其他设置(请注意,该键必须被引用)在YAML配置中

l  如果没有其他的区域数据源,则基于客户端配置(与实例配置相反)进行猜测。我们将eureka.client.availabilityZones,它是从区域名称到区域列表的地图,并拉出实例本身区域的第一个区域(即eureka.client.region,默认为“us-east-1”,为与本机Netflix的兼容性)。

 

4.5 参数配置

 对于Ribbon的参数配置通常有两种方式:全局配置以及指定客户端配置。

4.5.1 全局配置

全局配置使用  ribbon.<key> =<value>格式进行配置即可。

其中,<key>代表了Ribbon客户端配置的参数名,<value>则代表了对应参数的值。比如,我们可以像下面这样全局配置Ribbon创建连接的超时时间:

ribbon.ConnectTimeout=250

全局配置可以做为默认值进行设置,当指定客户端配置了响应的key值时,将覆盖全局配置的内容。

4.5.2 客户端配置

指定客户端配置使用  <client>.ribbon.<key> =<value>的格式进行配置。其中<key>和<value>的含义通全局配置相同,而<client>代表了客户端的名称,如上文中我们在@RibbonClient中指定的名称。

例如:当没有服务治理框架的情况下,我们需要为该客户端指定具体的实例清单,可以指定服务名来做详细的配置,具体如下:

hello-service.ribbon.listOfServers=localhost:8001.localhost:8002.localhost:8003

对应ribbon参数的key以及value类型的定义,可以通过查看com.netflix.client.config.CommonClientConfigKey类来查看更加明显的配置内容。

五. 重试机制

由于Spring Cloud Eureka实现的服务治理机制强调了CAP原理中的AP,即可用性与可靠性,它与Zookeeper这类强调CP(一致性、可靠性)的服务治理框架最大的区别就是,Eureka为了实现更高的服务可用性,牺牲了一定的一致性,在极短情况下它宁愿接收故障实例也不要丢到健康实例。比如,当服务注册中心的网路发生故障断开时,由于所有的服务实例无法维持续约心跳,在强调AP的服务治理中会把所有服务实例都剔除掉,而Eureka则会因为超过85%的实例丢失心跳而触发保护机制,注册中心将会保留此时的所有节点,以实现服务间依然可以进行互相调用的场景,即使其中有部分故障节点,但这样做可以继续保障大多数的服务正常消费。

不论是由于触发了保护机制还是服务剔除的延迟,引起服务调用到故障实例的时候,我们还是希望能够增强这类问题的容错。

从Camden SR2版本开始,SpringCloud整合了Retry来增强RestTemplate实现的服务访问就会自动根据配置来实现重试策略。

相关参数配置如下:

(1)      spring.cloud.loadbalancer.retry.enable:该参数用来开启重试机制,它默认是关闭的。这里需要注意,官方文档中的配置参数少了enabled。

(2)      hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:断路器的超时时间需要大于Ribbon的超时时间,不然不会触发重试。

(3)      <clientname>.ribbon.ConnectTimeout:请求连接的超时时间

(4)      <clientname>.ribbon.ReadTimeout:请求处理的超时时间

(5)      <clientname>.ribbon.OkToRetryOnAllOperations:对所有操作请求都进行重试

(6)      <clientname>.ribbon.MaxAutoRetriesNextServer:切换实例的重试次数

(7)      <clientname>.ribbon.MaxAutoRetries:对当前实例的重试次数

 

配置信息如下:

spring.cloud.loadbalancer.retry.enabled=true

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000

<clientname>.ribbon.ConnectTimeout=250

<clientname>.ribbon.ReadTimeout=1000

<clientname>.ribbon.OkToRetryOnAllOperations=true

<clientname>.ribbon.MaxAutoRetriesNextServer=2

<clientname>.ribbon.MaxAutoRetries=1

# spring.cloud.loadbalancer.retry.enable

 

根据如上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由MaxAutoRetries配置),如果不行,就换一个实例进行访问,如果还是不行,再换一个实例访问(更换次数由MaxAutoTriesNextServer配置),如果依然不想,则返回失败。

--------------------- 本文来自 大道化简 的CSDN 博客 ,

全文地址请点击:https://blog.csdn.net/sunhuiliang85/article/details/76718810?utm_source=copy

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值