Ribbon自定义负载均衡策略有两种方式,一是JavaConfig,一是经过配置文件(yml或properties文件)。html
假设我有包含A和B服务在内的多个微服务,它们均注册在一个Eureka上,信息以下:
java
我但愿当访问服务A时候,2个服务(端口分别是8087和8081)每两次一换,好比访问两次8087,再访问两次8081,如此反复。
当访问服务B时,与A相似,不过是3次一换。
当访问其余服务时,采用随机规则,即RandomRule,而不是默认策略1web
使用这种方式,总共分3步(以服务A的规则为例):spring
@Primary
2,重写逻辑需要根据实际需求来定,详见下面的代码IRule
的Bean,此处咱们选RandomRule
@RibbonClients
(只有一种自定义规则,则使用@RibbonClient
),添加不适用公共规则的其余自定义规则import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import org.springframework.context.annotation.Primary; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @Primary public class SvcARule extends AbstractLoadBalancerRule { private AtomicInteger total = new AtomicInteger(); private AtomicInteger index = new AtomicInteger(); public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } List<Server> upList = lb.getReachableServers(); List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { return null; } if (total.get() < 2) { server = upList.get(index.get()); total.incrementAndGet(); } else { total.set(0); index.set(index.incrementAndGet() % upList.size()); } if (server == null) { Thread.yield(); continue; } if (server.isAlive()) { return (server); } server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub } }
略,只须要把if (total.get() < 2)
改为if (total.get() < 3)
便可服务器
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import com.yan.ribbon.rule.SvcARule; import com.yan.ribbon.rule.SvcBRule; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @RibbonClients( value = { @RibbonClient(name = "SVCA", configuration = SvcARule.class), @RibbonClient(name = "SVCB", configuration = SvcBRule.class) }, defaultConfiguration = LBConfig.class) public class LBConfig { @Bean public IRule commonRule() { return new RandomRule(); } }
经过postman屡次访问服务A、B和C,获得日志以下:并发
2019-03-19 20:22:09.511 INFO 13372 --- [nio-8004-exec-4] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2019-03-19 20:22:09.511 INFO 13372 --- [nio-8004-exec-4] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2019-03-19 20:22:09.519 INFO 13372 --- [nio-8004-exec-4] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms 2019-03-19 20:22:09.693 INFO 13372 --- [nio-8004-exec-4] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-SVCA 2019-03-19 20:22:09.708 INFO 13372 --- [nio-8004-exec-4] c.netflix.loadbalancer.BaseLoadBalancer : Client: SVCA instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=SVCA,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null 2019-03-19 20:22:09.712 INFO 13372 --- [nio-8004-exec-4] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater 2019-03-19 20:22:09.729 INFO 13372 --- [nio-8004-exec-4] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client SVCA initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=SVCA,current list of Servers=[YanWei:8087, YanWei:8081],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;] },Server stats: [[Server:YanWei:8087; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] , [Server:YanWei:8081; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@7f0246c6 "svcA:8087===>\nname:xixi\ntype:haha" "svcA:8087===>\nname:xixi\ntype:haha" "svcA:8081===>\nname:xixi\ntype:haha" "svcA:8081===>\nname:xixi\ntype:haha" "svcA:8087===>\nname:xixi\ntype:haha" "svcA:8087===>\nname:xixi\ntype:haha" "svcA:8081===>\nname:xixi\ntype:haha" "svcA:8081===>\nname:xixi\ntype:haha" "svcA:8087===>\nname:xixi\ntype:haha" "svcA:8087===>\nname:xixi\ntype:haha" "svcA:8081===>\nname:xixi\ntype:haha" "svcA:8081===>\nname:xixi\ntype:haha" 2019-03-19 20:22:37.173 INFO 13372 --- [nio-8004-exec-5] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-SVCB 2019-03-19 20:22:37.174 INFO 13372 --- [nio-8004-exec-5] c.netflix.loadbalancer.BaseLoadBalancer : Client: SVCB instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=SVCB,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null 2019-03-19 20:22:37.177 INFO 13372 --- [nio-8004-exec-5] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater 2019-03-19 20:22:37.178 INFO 13372 --- [nio-8004-exec-5] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client SVCB initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=SVCB,current list of Servers=[YanWei:8086, YanWei:8082],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;] },Server stats: [[Server:YanWei:8082; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] , [Server:YanWei:8086; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@485ed210 "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8082===>\nname:xixi\ntype:haha" "svcB:8082===>\nname:xixi\ntype:haha" "svcB:8082===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8082===>\nname:xixi\ntype:haha" "svcB:8082===>\nname:xixi\ntype:haha" "svcB:8082===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" "svcB:8086===>\nname:xixi\ntype:haha" 2019-03-19 20:23:01.319 INFO 13372 --- [nio-8004-exec-8] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-SVCC 2019-03-19 20:23:01.320 INFO 13372 --- [nio-8004-exec-8] c.netflix.loadbalancer.BaseLoadBalancer : Client: SVCC instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=SVCC,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null 2019-03-19 20:23:01.320 INFO 13372 --- [nio-8004-exec-8] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater 2019-03-19 20:23:01.322 INFO 13372 --- [nio-8004-exec-8] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client SVCC initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=SVCC,current list of Servers=[YanWei:8083, YanWei:8085],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;] },Server stats: [[Server:YanWei:8083; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] , [Server:YanWei:8085; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@77b35c9 "svcC:8085===>\nname:xixi\ntype:haha" "svcC:8083===>\nname:xixi\ntype:haha" "svcC:8085===>\nname:xixi\ntype:haha" "svcC:8085===>\nname:xixi\ntype:haha" "svcC:8083===>\nname:xixi\ntype:haha" "svcC:8085===>\nname:xixi\ntype:haha" "svcC:8085===>\nname:xixi\ntype:haha"
配置文件方式需要遵照如下格式:app
<serviceName>.ribbon.<key>=<value>
几个变量解释以下:负载均衡
serviceName
就是服务名
key
是指Ribbon为实现不一样领域(咱们这里只说IRule,其实还有IPing等)所指定的关联类名,这里我须要自定义IRule
,其关联类名,也就是所谓的key
,是NFLoadBalancerRuleClassName
3
value
是我所要指定的自定义规则,好比,SvcB的负载均衡策略SvcBRule
dom
所以,在配置文件中添加以下配置:ide
svcB: ribbon: NFLoadBalancerRuleClassName: com.yan.ribbon.rule.SvcBRule
从新启动Ribbon服务后,发现此配置并无生效,缘由有两个:
一是个人服务名字写的是svcB
,理由是个人配置spring.appliaction.name=svcB
,可是使用Ribbon调用时使用了http://SVCB/...
,SVCB是大写的,因此没有获得指望的效果4
二是我已经有了用来替换默认规则的LBConfig,使得IRule的默认配置没有生效,由于查看源码org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration
中对于IRule的定义以下:
@Bean @ConditionalOnMissingBean public IRule ribbonRule(IClientConfig config) { if (this.propertiesFactory.isSet(IRule.class, name)) { return this.propertiesFactory.get(IRule.class, config, name); } ZoneAvoidanceRule rule = new ZoneAvoidanceRule(); rule.initWithNiwsConfig(config); return rule; }
因为我自定义的commonRule
已经存在了,因此此处不会触发,更不会走到判断那一步,就是说,个人上面的关于SvcB的自定义规则的配置,是没有什么地方去读的,所以,为了方便演示,直接将LBConfig所有注掉,再次重启后,把访问Uri中的大写改为一致的svcB
,发现对于服务B的配置生效了,可是没有指定的服务,所有都采用了默认的策略ZoneAvoidanceRule
。
配置文件方式,比较麻烦,且不能-不必也懒得研究如何-修改默认规则,而JavaConfig能够完美替代,所以我选JavaConfig。
关于Ribbon中对于IRule的实现,总共有以下几种,其简略说明也附注以下:
对应类为ZoneAvoidanceRule,直译过来是区域回避规则,我也不知道为啥这样叫:D↩
若是不加此注解,会报错,内容是找类型为IRule的Bean,可是找到了俩,一个commonRule,一个svcARule。若是你不嫌麻烦,能够选择网上流行的较为复杂的形式,好比springcloud-04-自定义ribbon的配置方式↩
能够在类org.springframework.cloud.netflix.ribbon.PropertiesFactory
中查看↩
这个Eureka也要背锅,由于使用服务名来进行服务间调用,是被大小写是被兼容过的,致使我这边疏忽大意了,仍是要细心的好。↩