Ribbon策略推薦如下兩種:
ZoneAvoidanceRule:復合判斷server所在區域的性能和server的可用性選擇server(默認)
WeightedResponseTimeRule:根據響應時間分配一個weight,響應時間越長,weight越小,被選中的可能性越低。
很多場景下,需要實現不同的微服務采用不同的策略,例如修改Ribbon的負載均衡規則等。Spring Cloud允許使用Java代碼自定義Ribbon的配置。
在Spring Cloud中,Ribbon默認配置如下
IClientConfig:Ribbon 的客戶端配置,默認采用 com.netflix.client.config.DefaultClientConfigImpl 實現。 IRule:Ribbon 的負載均衡策略,默認采用 com.netflix.loadbalancer.ZoneAvoidanceRule 實現,該策略能夠在多區域環境下選擇最佳區域的實例進行訪問 IPing:Ribbon 的實例檢查策略,默認采用 com.netflix.loadbalancer.NoOpPing 實現,該檢查策略是一個特殊的實現,實際上他並不會檢查實例是否可用,而是始終返回 true ,默認認為所有服務實例都是可以使用 ServerList<Server>:服務實例清單的維護機制,默認采用 com.netflix.loadbalancer.ConfigurationBasedServerList 實現。 ServerListFilter<Server>:服務實例清單過濾機制,默認采用 org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter 實現,該策略能夠優先過濾出與請求調用方處理同區域的服務實現 ILoadBalancer:負載均衡器,默認采用 com.netflix.loadbalancer.ZoneAwareLoadBalancer 實現,他具備了區域感知的能力
現使用Java代碼自定義Ribbon配置,模擬mima-cloud-producer 服務采用輪詢的方式訪問,mima-cloud-producer2服務采用隨機的方式訪問。
mima-cloud-producer 服務啟動如下節點:
http://localhost:9905/
http://localhost:9906/
mima-cloud-producer2 服務啟動如下節點:
http://localhost:9907/
http://localhost:9908/
打開瀏覽器,多次訪問 http://192.168.1.100:8803/ribbon/get/1,運行效果如下:
host:PC-20161120GHGR,port:9906,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9906
host:PC-20161120GHGR,port:9908,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9908
============= host:PC-20161120GHGR,port:9905,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9905
host:PC-20161120GHGR,port:9908,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9908
============= host:PC-20161120GHGR,port:9906,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9906
host:PC-20161120GHGR,port:9908,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9908
============= host:PC-20161120GHGR,port:9905,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9905
host:PC-20161120GHGR,port:9908,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9908
============= host:PC-20161120GHGR,port:9906,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9906
host:PC-20161120GHGR,port:9907,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9907
============= host:PC-20161120GHGR,port:9905,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9905
host:PC-20161120GHGR,port:9907,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9907
============= host:PC-20161120GHGR,port:9906,serviceId=mima-cloud-producer,uri=http://PC-20161120GHGR:9906
host:PC-20161120GHGR,port:9908,serviceId=mima-cloud-producer2,uri=http://PC-20161120GHGR:9908
=============
從運行結果來看,可以發現mima-cloud-producer服務采用輪詢的方式,mima-cloud-producer2服務采用隨機的方式。
1、創建Ribbon配置類
1.1、ConsumerRibbonClientConfig——Ribbon配置類,采用輪詢的策略
package com.mimaxueyuan.consumer.config; import org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.DummyPing; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.PollingServerListUpdater; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.netflix.loadbalancer.ServerListFilter; import com.netflix.loadbalancer.ServerListUpdater; import com.netflix.loadbalancer.ZoneAvoidanceRule; import com.netflix.loadbalancer.ZoneAwareLoadBalancer; //自定義ribbon策略可以覆蓋RibbonClientConfiguration中的默認配置。 //RibbonClientConfiguration每個方法都可以被覆蓋 //自定義的Ribbon配置不能放在SpringApplication的同級或下級目錄中會覆蓋所有的Ribbon客戶端配置,所有的客戶端都使用了相同的配置。 //自定義的Ribbon配置不能放在ComponentScan的目錄中否則次配置會覆蓋所有的Ribbon客戶端配置,所有的客戶端都使用了相同的配置。
@Configuration public class ConsumerRibbonClientConfig { public static final int DEFAULT_CONNECT_TIMEOUT = 1000; public static final int DEFAULT_READ_TIMEOUT = 1000; @Bean public IRule ribbonRule(IClientConfig config) {
//輪詢策略 ZoneAvoidanceRule rule = new ZoneAvoidanceRule(); rule.initWithNiwsConfig(config); return rule; } // 檢測服務是否存活
@Bean public IPing ribbonPing(IClientConfig config) { return new DummyPing(); } /* 服務列保, 覆蓋此方法,必須在yml/properties文件中配置服務列表 @Bean public ServerList<Server> ribbonServerList(IClientConfig config) { ConfigurationBasedServerList serverList = new ConfigurationBasedServerList(); serverList.initWithNiwsConfig(config); return serverList; } */
//服務列表更新器
@Bean public ServerListUpdater ribbonServerListUpdater(IClientConfig config) { return new PollingServerListUpdater(config); } //負載均衡器
@Bean public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) { return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList, serverListFilter, serverListUpdater); } //此接口允許過濾配置或動態獲得的具有良好特性的候選服務器列表。
@Bean public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) { ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter(); filter.initWithNiwsConfig(config); return filter; } }
1.2、ConsumerRibbonClientConfig2——Ribbon配置類,采用隨機的策略
package com.mimaxueyuan.consumer.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; //自定義ribbon策略可以覆蓋RibbonClientConfiguration中的默認配置。 //RibbonClientConfiguration每個方法都可以被覆蓋 //自定義的Ribbon配置不能放在SpringApplication的同級或下級目錄中會覆蓋所有的Ribbon客戶端配置,所有的客戶端都使用了相同的配置。 //自定義的Ribbon配置不能放在ComponentScan的目錄中否則次配置會覆蓋所有的Ribbon客戶端配置,所有的客戶端都使用了相同的配置。
@Configuration public class ConsumerRibbonClientConfig2 { @Bean public IRule ribbonRule(IClientConfig config) { // 負載均衡規則,改為隨機
return new RandomRule(); } }
2、RibbonConsumerApplication——Ribbon啟動類,及指定Ribbon的配置類
package com.mimaxueyuan.consumer.robbin; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; 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.Primary; import org.springframework.web.client.RestTemplate; import com.mimaxueyuan.consumer.config.ConsumerRibbonClientConfig; import com.mimaxueyuan.consumer.config.ConsumerRibbonClientConfig2; @SpringBootApplication //@EnableEurekaClient
@EnableDiscoveryClient //name=服務提供者的instanceName,configuration指定Ribbon的配置類 //@RibbonClient(name="mima-cloud-producer",configuration=ConsumerRibbonClientConfig.class)
@RibbonClients( //配置defaultConfiguration會報空指針異常,有知道的同學麻煩告訴下 //defaultConfiguration=RibbonClientConfiguration.class,
value= { @RibbonClient(name="mima-cloud-producer",configuration=ConsumerRibbonClientConfig.class), @RibbonClient(name="mima-cloud-producer2",configuration=ConsumerRibbonClientConfig2.class) }) public class RibbonConsumerApplication { @Bean // 需要使用負載均衡,必須與Bean一同使用
@LoadBalanced public RestTemplate balanceRestTemplate() { return new RestTemplate(); } //需要多個RestTemplate, 有的RestTemplate使用負載均衡,有的不使用,不使用的不增加@LoadBalanced注解
@Primary @Bean public RestTemplate noBalanceRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonConsumerApplication.class, args); } }
3、RibbonConfigController——Ribbon測試類
package com.mimaxueyuan.consumer.robbin.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class RibbonConfigController { // 注入restTemplate, 這個類已經在RibbonConsumerApplication中初始化,並且使用負載均衡
@Autowired //默認按照類型注入,如果需要按照名字注入需要使用@Qualifier注解
@LoadBalanced //使用帶有負載均衡的RestTemplate
private RestTemplate balanceRestTemplate; // 以下注入負載均衡客戶端LoadBalancerClient是一個接口,下面只有一個RibbonLoadBalancerClient實現類
@Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RibbonLoadBalancerClient ribbonLoadBalancerClient; /** * ribbon使用 * * @author Kevin * @Title: ribbon * @param id * @return * @return: String */ @GetMapping("/ribbon/get/{id}") public String ribbon(@PathVariable("id") String id) { ServiceInstance instance = loadBalancerClient.choose("mima-cloud-producer"); System.out.println("host:" + instance.getHost() + ",port:" + instance.getPort() + ",serviceId=" + instance.getServiceId() + ",uri=" + instance.getUri()); instance = ribbonLoadBalancerClient.choose("mima-cloud-producer2"); System.out.println("host:" + instance.getHost() + ",port:" + instance.getPort() + ",serviceId=" + instance.getServiceId() + ",uri=" + instance.getUri()); System.out.println("============="); return "ribbon's demo,please to see console output"; } }