思考一個問題:如果為同一個提供者在Eureka中注冊多個服務?客戶端應該如何選擇服務呢?

這時,就需要在客戶端實現服務的負載均衡。而在Spring Cloud中推薦使用Ribbon來實現負載均衡。

 
1、Ribbon簡介

Ribbon是Netflix發布的負載均衡器。它有助于控制HTTP和TCP客戶端的行為。為Ribbon配置服務提供者地址列表后, Ribbon就可基于某種負載均衡算法,自動地幫助服務消費者去請求。Ribbon默認為我們提供了很多的負載均衡算法,例如輪詢、隨機等。當然,我們也可為 Ribbon實現自定義的負載均衡算法。

 
2、架構
如何在客戶端實現服務的負載均衡

 
3、開始使用Ribbon

 

3.1. 為microservice order增加ribbon依賴
如何在客戶端實現服務的負載均衡
    org.springframework.cloud    spring-cloud-starter-netflix-ribbon

其實,該依賴是可以省略的,因為spring-cloud-starter-netflix-eureka-client中已經包含了spring-cloud-starter-netflix-ribbon:
 如何在客戶端實現服務的負載均衡


3.2. 為RestTemplate設置@LoadBalanced注解

@SpringBootApplication@EnableEurekaClient@EnableFeignClientspublic class OrderApp {    public static void main(String[] args) {        SpringApplication.run(OrderApp.class, args);    }    @Bean    @LoadBalanced //使用負載均衡    public RestTemplate restTemplate() {        return new RestTemplate();    }}

3.3. 改造ItemService的實現

 

@Servicepublic class ItemService {    // Spring框架對RESTful方式的http請求做了封裝,來簡化操作    @Autowired    private RestTemplate restTemplate;    public Item queryItemById(Long id) {        // 該方法走eureka注冊中心調用(去注冊中心根據app-item查找服務,這種方式必須先開啟負載均衡@LoadBalanced)        String itemUrl = "http://app-item/item/{id}";        Item result = restTemplate.getForObject(itemUrl, Item.class, id);        System.out.println("訂單系統調用商品服務,result:" + result);        return result;    }}

可以發現,實現更加簡化了。

這種方式關鍵在于獲取RestTemplat對象時要加上@LosdBalanced注解,否則restTemplate.getFor Object方法會報java.net.UnknownHostException: app-item,而前面一種方式是手動指定了獲取的服務實例,不需要加此注解。

 

提示: 如果這里使用了@FeignClient完成的Restful的調用同樣也適用。

 

3.4. 重啟訂單服務進行測試

測試結果:
 
microservice-item

3.5. 測試負載均衡

 

測試方法:
第一步,啟動2個microservice-item服務(多個也可以):
 microservice-item

第二步,導入測試依賴,編寫單元測試用例:

    org.springframework.boot    spring-boot-starter-test    test

第三步,編寫測試用例:

@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest@Import(OrderApp.class)public class ItemServiceTest {    @Autowired    private LoadBalancerClient loadBalancerClient;//自動注入    @Test    public void test() {        String serviceId = "app-item";        for (int i = 0; i < 100; i++) {            ServiceInstance serviceInstance = this.loadBalancerClient.choose(serviceId);            System.out.println("第" + (i + 1) + "次:" + serviceInstance.getHost() + ": " + serviceInstance.getPort());        }    }}

4、設置負載均衡策略

只需要在配置文件中添加配置
serviceId.ribbon.NFLoadBalancerRuleClassName=自定義的負載均衡策略類,

例如在order微服務的yml配置文件中添加:

app-item:  ribbon:    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

其中app-item是要訪問的服務id。

測試:

第1次:127.0.0.1: 8081

第2次:127.0.0.1: 9081

第3次:127.0.0.1: 9081

第4次:127.0.0.1: 8081

第5次:127.0.0.1: 9081

第6次:127.0.0.1: 8081

第7次:127.0.0.1: 9081

第8次:127.0.0.1: 9081

第9次:127.0.0.1: 8081

第10次:127.0.0.1: 8081

...

5、其它策略

接口:com.netflix.loadbalancer.IRule,其實現類:
策略描述:

 

AbstractLoadBalancerRule

負載均衡的抽象類,負責獲得負載均衡器并保存在內部,通過負載均衡器維護的信息作為分配的依據,并以此設計一些算法來實現針對特定場景的高效策略。


RoundRobinRule

Ribbon默認的負載均衡機制,該策略實現了按照線性輪詢的方式以此選擇每個服務實例的功能。輪詢index,選擇index對應位置的server。

 

RandomRule

該策略實現了從服務實例清單中隨機選擇一個服務實例的功能。通過在index上隨機,選擇index對應位置的server。


RetryRule

該策略實現了一個具備重試機制的實例選擇功能。該策略下在一個配置時間段內當選擇server不成功,則一直嘗試使用subRule的方式選擇一個可用的server。