什麼是Ribbon
在微服務項目中,一個後端服務我們一般會配置一個集羣在不同服務器中進行啓動,用來保證即使一個服務器宕機其他服務器也能進行服務的提供。這樣一來我們獲取的服務列表中就會有多個,那麼到底該訪問哪一個呢?一般這種情況下我們就需要編寫負載均衡算法,在多個實例列表中進行選擇。
Ribbon是netflix發佈的負載均衡器,有助於控制HTTP和TCP客戶端的行爲,爲Ribbon配置服務提供者列表後,Ribbon就可基於某種負載均衡算法,自動的幫助服務消費者去請求。Ribbon默認爲我們提供了很多的負載均衡算法(輪詢、隨機等),並且我們也可以自己定義算法。
從某種程度上說,Ribbon是作爲了一種服務的調用功能存在,即當一個後端服務部署成了集羣之後,到底需要調用那個具體的服務,可以有Ribbon來爲我們解決。
RestTemplate進行客戶端訪問
Spring提供了一個RestTemplate模板工具類,對基於Http的客戶端進行了封裝,並且實現了對象與json的序列化和反序列化,非常方便。RestTemplate並沒有限定Http的客戶端類型,而是進行了抽象,目前常用的3種都有支持:
- HttpClient
- OkHttp
- JDK原生的URLConnection(默認的)
在上一篇文章中我們已經對RestTemplate的使用進行了講解,我們來回顧一下:
首先我們進行了一個RestTemplate對象的註冊(注入到spring容器,當然也可以在啓動類位置註冊)
@Configuration
public class ApplicationContext {
@Bean
public RestTemplate GetrestTemplate(){
return new RestTemplate();
}
}
之後就可以在controller中注入並使用:
@RestController
public class TestServer {
private static final String ITEMSERVER_URL="http://localhost:8002";
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test")
public CommonResult<Integer> test(){
return restTemplate.getForObject(ITEMSERVER_URL+"/test",CommonResult.class);
}
}
通過RestTemplate的getForObject()方法,傳遞url地址及實體類的字節碼,RestTemplate會自動發起請求,接收響應,並且幫我們對響應結果進行反序列化。
上面只是對於單個服務進行訪問時的使用,那麼對於服務集羣,我們需要怎樣進行服務調用呢?
Ribbon的使用
下面我們接着上一篇文章服務註冊中心-Eureka,做一個item-server服務的服務集羣:
兩個服務提供的功能完全一樣,只是在配置文件中進行了不一樣的端口配置:
我們來重寫controller中的調用(加上端口號,這樣我們在訪問的時候能夠識別出來消費者是訪問了哪一個後端服務):
@RestController
public class TestServer {
@Value("${server.port}")
private String serverPort;
@GetMapping("/test")
public CommonResult test(){
Integer a=1;
return new CommonResult(200,"查詢成功"+serverPort,a) ;
}
}
因爲Eureka中已經集成了Ribbon,所以我們無需引入新的依賴,直接修改代碼,在消費者服務中,我們在RestTemplate對象的註冊類中添加一個註解 @LoadBalanced,開啓負載均衡算法:
@Configuration
public class ApplicationContext {
@Bean
@LoadBalanced
public RestTemplate GetrestTemplate(){
return new RestTemplate();
}
}
修改消費者服務對其他服務的調用方式:
@RestController
public class TestServer {
// private static final String ITEMSERVER_URL="http://localhost:8002";
private static final String ITEMSERVER_URL="http://ITEM-SERVER";
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test")
public CommonResult<Integer> test(){
return restTemplate.getForObject(ITEMSERVER_URL+"/test",CommonResult.class);
}
}
重起所有服務,對消費者路徑進行訪問,可以看到訪問的後端服務是交替進行的:
在上面的調用中我們只輸入了service名稱就可以訪問了,並不需要獲取ip和端口。
這顯然有人幫我們根據service名稱,獲取到了服務實例的ip和端口。它就是LoadBalancerInterceptor
。
由上可以看出,RestTemplate的服務調用,默認是通過簡單的輪詢方式進行的。
那麼我們是否能夠修改負載均衡的策略呢?
在Ribbon的底層,有兩個IRule的實現類,一個是輪詢一個是隨機:
SpringBoot也幫我們提供了修改負載均衡規則的配置入口,在消費者服務的的application.yml中添加如下配置:
service-provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
格式是:{服務名稱}.ribbon.NFLoadBalancerRuleClassName
,值就是IRule的實現類(文章開頭已經說明,我們也可以進行自定義算法實現服務調用,自定義的類需要實現IRule接口)。
再次重啓服務進行測試,發現是隨機訪問了。