如何在客戶端實(shí)現(xiàn)服務(wù)的負(fù)載均衡
這時(shí),就需要在客戶端實(shí)現(xiàn)服務(wù)的負(fù)載均衡。而在Spring Cloud中推薦使用Ribbon來實(shí)現(xiàn)負(fù)載均衡。
1、Ribbon簡(jiǎn)介
Ribbon是Netflix發(fā)布的負(fù)載均衡器。它有助于控制HTTP和TCP客戶端的行為。為Ribbon配置服務(wù)提供者地址列表后, Ribbon就可基于某種負(fù)載均衡算法,自動(dòng)地幫助服務(wù)消費(fèi)者去請(qǐng)求。Ribbon默認(rèn)為我們提供了很多的負(fù)載均衡算法,例如輪詢、隨機(jī)等。當(dāng)然,我們也可為 Ribbon實(shí)現(xiàn)自定義的負(fù)載均衡算法。
2、架構(gòu)

3、開始使用Ribbon
3.1. 為microservice order增加ribbon依賴

其實(shí),該依賴是可以省略的,因?yàn)閟pring-cloud-starter-netflix-eureka-client中已經(jīng)包含了spring-cloud-starter-netflix-ribbon:

3.2. 為RestTemplate設(shè)置@LoadBalanced注解
@SpringBootApplication@EnableEurekaClient@EnableFeignClientspublic class OrderApp { public static void main(String[] args) { SpringApplication.run(OrderApp.class, args); } @Bean @LoadBalanced //使用負(fù)載均衡 public RestTemplate restTemplate() { return new RestTemplate(); }}
3.3. 改造ItemService的實(shí)現(xiàn)
@Servicepublic class ItemService { // Spring框架對(duì)RESTful方式的http請(qǐng)求做了封裝,來簡(jiǎn)化操作 @Autowired private RestTemplate restTemplate; public Item queryItemById(Long id) { // 該方法走eureka注冊(cè)中心調(diào)用(去注冊(cè)中心根據(jù)app-item查找服務(wù),這種方式必須先開啟負(fù)載均衡@LoadBalanced) String itemUrl = "http://app-item/item/{id}"; Item result = restTemplate.getForObject(itemUrl, Item.class, id); System.out.println("訂單系統(tǒng)調(diào)用商品服務(wù),result:" + result); return result; }}
可以發(fā)現(xiàn),實(shí)現(xiàn)更加簡(jiǎn)化了。
這種方式關(guān)鍵在于獲取RestTemplat對(duì)象時(shí)要加上@LosdBalanced注解,否則restTemplate.getFor Object方法會(huì)報(bào)java.net.UnknownHostException: app-item,而前面一種方式是手動(dòng)指定了獲取的服務(wù)實(shí)例,不需要加此注解。
提示: 如果這里使用了@FeignClient完成的Restful的調(diào)用同樣也適用。
3.4. 重啟訂單服務(wù)進(jìn)行測(cè)試
測(cè)試結(jié)果:

3.5. 測(cè)試負(fù)載均衡
測(cè)試方法:
第一步,啟動(dòng)2個(gè)microservice-item服務(wù)(多個(gè)也可以):

第二步,導(dǎo)入測(cè)試依賴,編寫單元測(cè)試用例:
第三步,編寫測(cè)試用例:
@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest@Import(OrderApp.class)public class ItemServiceTest { @Autowired private LoadBalancerClient loadBalancerClient;//自動(dòng)注入 @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、設(shè)置負(fù)載均衡策略
只需要在配置文件中添加配置
serviceId.ribbon.NFLoadBalancerRuleClassName=自定義的負(fù)載均衡策略類,
例如在order微服務(wù)的yml配置文件中添加:
app-item: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
其中app-item是要訪問的服務(wù)id。
測(cè)試:
第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,其實(shí)現(xiàn)類:
策略描述:
AbstractLoadBalancerRule
負(fù)載均衡的抽象類,負(fù)責(zé)獲得負(fù)載均衡器并保存在內(nèi)部,通過負(fù)載均衡器維護(hù)的信息作為分配的依據(jù),并以此設(shè)計(jì)一些算法來實(shí)現(xiàn)針對(duì)特定場(chǎng)景的高效策略。
RoundRobinRule
Ribbon默認(rèn)的負(fù)載均衡機(jī)制,該策略實(shí)現(xiàn)了按照線性輪詢的方式以此選擇每個(gè)服務(wù)實(shí)例的功能。輪詢index,選擇index對(duì)應(yīng)位置的server。
RandomRule
該策略實(shí)現(xiàn)了從服務(wù)實(shí)例清單中隨機(jī)選擇一個(gè)服務(wù)實(shí)例的功能。通過在index上隨機(jī),選擇index對(duì)應(yīng)位置的server。
RetryRule
該策略實(shí)現(xiàn)了一個(gè)具備重試機(jī)制的實(shí)例選擇功能。該策略下在一個(gè)配置時(shí)間段內(nèi)當(dāng)選擇server不成功,則一直嘗試使用subRule的方式選擇一個(gè)可用的server。

