一、简介
ribbon是一个支持http,tcp客户端的负责均衡库。
二、引入
在这里,结合spring-boot的方式,在pom中添加如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
三、使用
-
直接使用ribbon
@Autowired private LoadBalancerClient loadBalancer; @Test public void testRibbon() throws InterruptedException { ServiceInstance instance = loadBalancer.choose("count-server"); System.out.println(instance); } application.yml配置如下: count-server: ribbon: listOfServers: vstat.v.blog.sohu.com,vstat.my.tv.sohu.com
这里没有结合RestTemplate,也没有结合eureka,这里只为简单说明一下ribbon的负载均衡:
-
首先LoadBalancerClient是如何自动注入到spring容器中的
可以查看spring-cloud-netflix-core/META-INF/spring.factories,可以知道配置了RibbonAutoConfiguration
而RibbonAutoConfiguration会创建LoadBalancerClient的实例->RibbonLoadBalancerClient
-
loadBalancer.choose选择一个实例返回,这里源码比较复杂,分析请参见。
-
-
结合resttemplate:
@Configuration public class RibbonConfig { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } } @Service @RibbonClient(name="count-server") public class CountConsumer { @Autowired private RestTemplate restTemplate; public String getCount() { String result = restTemplate.getForObject( "http://count-server/dostat.do?method=getVideoPlayCount&v=85152140|85162109&rt=json", String.class); return result; } }
这里多了两个注解:
第一个@LoadBalanced标注在RestTemplate上用于指示RestTemplate具备负载均衡作用。
第二个@RibbonClient(name=“count-server”)标注在类上,用于表示该类对应的服务名,可以从application.yml中的count-server.ribbon.listOfServers中获取地址。
当和eureka结合时,可以从注册中心发现服务地址并负载均衡
-
加上@LoadBalanced注解后,是如何作用于RestTemplate的?
LoadBalancerAutoConfiguration是自动配置类,位于spring-cloud-commons中,它会发现LoadBalanced注解并将拦截器LoadBalancerInterceptor注入到RestTemplate中。
当调用到RestTemplate的getForObject时,会调用到InterceptingClientHttpRequest,其持有所有的拦截器,它遍历调用拦截器,并将自己(this)传入,形成递归,完成最终调用,其内部调用如下:
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException { if (this.iterator.hasNext()) { ClientHttpRequestInterceptor nextInterceptor = this.iterator.next(); return nextInterceptor.intercept(request, body, this); } else { ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod()); for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) { List<String> values = entry.getValue(); for (String value : values) { delegate.getHeaders().add(entry.getKey(), value); } } if (body.length > 0) { StreamUtils.copy(body, delegate.getBody()); } return delegate.execute(); } }
具体分析请参考http://blog.didispace.com/springcloud-sourcecode-ribbon/
四、一些配置
-
@RibbonClient(name = “foo”, configuration = CountServiceRibbonConfiguration.class)
其中FooConfiguration可以对ribbon进行配置,例如,配置IPing为PingUrl:
public class CountServiceRibbonConfiguration { public IPing ribbonPing(IClientConfig config) { return new PingUrl(); } }
目前可以配置的类如下:
- IClientConfig=>默认值:DefaultClientConfigImpl
- IRule=>默认值:ZoneAvoidanceRule
- IPing=>默认值:NoOpPing
- ServerList=>默认值:ConfigurationBasedServerList
- ServerListFilter=>默认值:ZonePreferenceServerListFilter
- ILoadBalancer=>默认值:ZoneAwareLoadBalancer
-
从spring-cloud-nexflix 1.2.0开始,支持在application.yml进行配置,如下:
ribbon: NFLoadBalancerClassName: 实现ILoadBalancer NFLoadBalancerRuleClassName: 实现IRule NFLoadBalancerPingClassName: 实现IPing NIWSServerListClassName: 实现ServerList NIWSServerListFilterClassName: 实现ServerListFilter
但是这种配置文件的方式在某些旧版本还有bug,参见https://github.com/spring-cloud/spring-cloud-netflix/issues/1608,直至1.3.0.M1中才修复。
-
ribbon的配置项参考com.netflix.client.config.CommonClientConfigKey,常见配置如下(默认值参考DefaultClientConfigImpl):
ribbon: MaxAutoRetriesNextServer:默认值1 MaxAutoRetries:默认值0
默认配置含义:当访问到故障请求的时候,由于MaxAutoRetries为0,故切换到下一个实例进行访问,如果还是不行,由于MaxAutoRetriesNextServer为1,返回失败信息
五、参考
http://blog.didispace.com/spring-cloud-ribbon-failed-retry/
https://my.oschina.net/sean1989/blog/904016
http://www.cnblogs.com/zhangjianbin/p/7228628.html