balancer:均衡器
如果是自己寫一個負載均衡器思路應該是什麼?
參考nginx,部署多個服務,形成一對多的關系
當一個請求發送,通過攔截這個請求,随機或者算法到其中的一個服務上去處理
那麼,這中間關鍵的一點就是:攔截
最精簡的LB需求:
- 設定添加和讀取後端伺服器的清單
- 能從中選擇一個伺服器去執行
代碼實作思路就是:
讀取後端服務,标記一個服務不可用,最主要是選擇一個後端服務來提供服務
//使用負載均衡加載服務
public interface ILoadBalancer {
void addServers(List var1);向負載均衡器中維護的執行個體清單增加服務執行個體。
Server chooseServer(Object var1);通過某種政策,從負載均衡器中挑選出一個具體的服務執行個體。
void markServerDown(Server var1);用來通知和辨別負載均衡器中某個具體執行個體已經停止服務,不然負載均衡器在下一次擷取服務執行個體清單前都會認為服務執行個體均是正常服務的。
List getServerList(boolean var1);//目的相容2.1.3以前的。(之後本方法拆分下面兩個)
List getReachableServers();擷取目前正常服務的執行個體清單。
List getAllServers();擷取所有已知的服務執行個體清單,包括正常服務和停止服務的執行個體。
}
ILoadBalancer:
基礎實作類 com.netflix.loadbalancer.BaseLoadBalancer
擴充功能 DynamicServerListLoadBalancer和ZoneAwareLoadBalancer
通過檢視BaseLoadBalancer源碼發現:
- 裡面幾個重要的對象
1.通過(@LoadBalanced)注解的形式去攔截:RestTemplate的請求
注意一點:模式是根據http請求的
使用HTTP通路
eureka.instance.non-secure-port-enabled=true
使用更加安全的HTTPS通路
eureka.instance.secure-port-enabled=true
@Autowired
RestTemplate restTemplate;
/**
* 當網絡不穩定的情況下,配置傳回資訊
*
* 當一個被@LoadBalanced注解修飾的RestTemplate對象向外發起HTTP請求時,
* 會被LoadBalancerInterceptor類的intercept函數所攔截。
* 由于我們在使用RestTemplate時候采用了服務名作為host,
* 是以直接從HttpRequest的URI對象中通過getHost()就可以拿到服務名,
* 然後調用execute函數去根據服務名來選擇執行個體并發起實際的請求。
* @return
*/
@HystrixCommand(fallbackMethod = “addServiceFallback”)
public String addService() {
return restTemplate.getForEntity(“http://COMPUTE-SERVICE/add?a=10&b=20“, String.class).getBody();
public String addServiceFallback() {
return “error”;
2.LoadBalancerInterceptor中的intercept會攔截RestTemplate中的請求
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
URI originalUri = request.getURI();//獲得請求的位址,因為是host是服務名 是以使用http://“注意:”:COMPUTE-SERVICE/add?a=10&b=20
String serviceName = originalUri.getHost();//COMPUTE-SERVICE
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, new LoadBalancerRequest() {
public ClientHttpResponse apply(ServiceInstance instance) throws Exception {//選取一個執行個體去執行
LoadBalancerInterceptor.ServiceRequestWrapper serviceRequest = LoadBalancerInterceptor.this.new ServiceRequestWrapper(request, instance);
return execution.execute(serviceRequest, body);
});
3.通過搜尋LoadBalancerClient,我們可以發現這是Spring Cloud中定義的一個接口:
public interface LoadBalancerClient {
ServiceInstance choose(String serviceId); //選擇服務執行個體,根據傳入的服務名serviceId,從負載均衡器中挑選一個對應服務的執行個體。
T execute(String serviceId, LoadBalancerRequest request) throws IOException; //使用從負載均衡器中挑選出的服務執行個體來執行請求内容。
URI reconstructURI(ServiceInstance instance, URI original);
這個接口的具體實作類是RibbonLoadBalancerClient
負載均衡器應用也是SpringBoot普通應用,不過要配置RestTemplate對象
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class RibbonApplication {
* @LoadBalanced注解源碼的注釋中,我們可以知道該注解用來給RestTemplate标記,
* 以使用負載均衡的用戶端(LoadBalancerClient)來配置它。
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);