一、ribbon 負載均衡原理
1.客戶端負載均衡,通過LoadBalancerclient來實現,ILoadBalancer 通過配置IRule 和IPin 來實現
2.ILoadBalancer 通過每10s 獲取一次Eureka 注冊地址,獲取到注冊列表后按照IRule 注冊規則進行負載均衡
二、核心原理攔截器
1.ribbon 的核心其實就是代理,通過攔截器的方式
2.攔截器實現的功能1:通過對請求的攔截,獲取url ,解析hostname 通過hostname 再到Eureka 拿取真實的ip 端口,建立連接發送數據
3.攔截器實現的功能2:拿到目標服務的列表后,按照Rule規則選擇具體的目標服務,從而實現負載均衡
三、代碼的實現過程
spring啟動過程
1.通過@Bean向spring中注入RestTemplete 對象
2.通過@LoadBanlance 注解,實現RestTemplete 注入攔截器,將自定義的攔截器注入RestTemplete 的攔截器鏈中
http調用過程
1.調用RestTemplete 調用目標服務交口(hostname+接口名稱),RestTemplete 的攔截器會攔截該方法,從而對接口修改和增強,把url地址改為(ip+端口+接口名稱)
2.完成規則獲取以及ip端口准備后,就開始連接目標服務發送數據,連接是通過httpclient 實現,通過工廠類獲取httpclient 連接對象
四、源代碼
MyConfig 實現啟動時給RestTemplete 綁定攔截器
@Configuration public class MyConfig { // 需要使用 Autowired 注解注入所有被 @MyLoadBalanced 定義的 RestTemplate 配置 ,因為使用了 @Configuration // (required=false) 非必須的, 有沒有都可以注入,正常運行 @Autowired(required=false) @MyLoadBalanced private List<RestTemplate> tpls = Collections.emptyList(); @Bean public SmartInitializingSingleton lbInitializing() { return new SmartInitializingSingleton() { public void afterSingletonsInstantiated() { // System.out.println(tpls.size()); for (RestTemplate restTemplate : tpls) { List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors(); interceptors.add(new MyInterceptor()); //interceptors.add(new MyInterceptor2()); restTemplate.setInterceptors(interceptors); } } }; } }
MyInterceptor 攔截器類,實現url轉化及規則處理
public class MyInterceptor implements ClientHttpRequestInterceptor { public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { System.out.println("####這是自定義攔截器####"); System.out.println("***********舊的 URI:" + request.getURI()); HttpRequest newRequest = new MyRequest(request); System.out.println("&&&&&&&&&&&&新的 URI:" + newRequest.getURI()); return execution.execute(newRequest, body); }
MyRequest 封裝的新的httpRequest類(ip+端口)
public class MyRequest implements HttpRequest { HttpRequest sourceRequest; public MyRequest(HttpRequest sourceRequest){ this.sourceRequest = sourceRequest; } public HttpHeaders getHeaders() { return sourceRequest.getHeaders(); } public HttpMethod getMethod() { return sourceRequest.getMethod(); } public URI getURI() { try { URI newUri = new URI("http://localhost:8086/hello"); return newUri; } catch (URISyntaxException e) { e.printStackTrace(); } return sourceRequest.getURI(); } }
MyController 客戶端controller
@RestController @Configuration public class MyController { @Resource(name="tplA") RestTemplate restTemplate; @RequestMapping(value="/call", method=RequestMethod.GET) public String call(){ return restTemplate.getForObject("http://hello-service/call4", String.class); } @RequestMapping(value="/hello", method=RequestMethod.GET) public String hello(){ return "hello word"; } }
RestTplApp 啟動類,把restemplete 注入spring容器以及配置負載均衡標記
@SpringBootApplication public class RestTplApp { public static void main(String[] args) { SpringApplication.run(RestTplApp.class, args); } @Bean //@MyLoadBalanced RestTemplate tplA(){ return new RestTemplate(); } @Bean @MyLoadBalanced RestTemplate tplB(){ return new RestTemplate(); } }
五、ribbon的負載均衡算法
1.RoundRobinRule輪詢(默認的算法)
2.RandomRule 隨機
3.AvailabilityFilteringRule 優先過濾一部分算法,被過濾的是多次訪問故障處於斷路器狀態的服務,以及並發連接數量超過閾值的服務,然后執行輪詢算法
4.WeightedResponseTimeRule 響應時間權重算法,響應時間越短,權重越大,被調用的機會越大
5.RetryRule 輪詢算法重試,如果輪詢失敗,則在有限時間內重試
6.BestAvailableRule 並發量算法,優先過濾掉熔斷的服務,然后再選擇並發量最小的連接
7.ZoneAvoidanceRule 復合算法,計算server的可用性,從而選取最有
六、ribbon 負載算法代碼配置
//配置負載均衡的策略為隨機,默認算法為輪詢算法 @Bean public IRule myRule() { //return new RoundRobinRule(); return new RandomRule(); }
源碼地址:https://github.com/197wj/Ribbon