追踪源码自定义负载均衡策略
生活随笔
收集整理的這篇文章主要介紹了
追踪源码自定义负载均衡策略
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們來了解一下負載均衡的源碼,是怎么實現的,它是怎么實現的,開始我們說了第三種方式只是用了一個注解,實質上是和第二種方式是一模一樣的,那么為了方便觀察呢,這里使用第二種方式,來查看源碼ServiceInstance serviceInstance = this.loadBalancerClient.choose("PRODUCT");這里調用了choose這種方法,我們點進來可以看到他的一個接口/*** Implemented by classes which use a load balancer to choose a server to* send a request to.** @author Ryan Baxter*/
public interface ServiceInstanceChooser {/*** Choose a ServiceInstance from the LoadBalancer for the specified service* @param serviceId the service id to look up the LoadBalancer* @return a ServiceInstance that matches the serviceId*/ServiceInstance choose(String serviceId);
}按進來跳到他的實現,看一下他的實現類public class RibbonLoadBalancerClient implements LoadBalancerClient {可以看到他實現了一個接口,LoadBalancerClient,LoadBalancerClient又繼承了一個ServiceInstanceChooser/*** Represents a client side load balancer* @author Spencer Gibb*/
public interface LoadBalancerClient extends ServiceInstanceChooser {注意我們看源碼的時候呢,可以這樣子來看,比如我已經進入到這個類里面了,你想看他類之間的關系的話,回到我們要觀察的方法@Override
public ServiceInstance choose(String serviceId) {Server server = getServer(serviceId);if (server == null) {return null;}return new RibbonServer(serviceId, server, isSecure(server, serviceId),serverIntrospector(serviceId).getMetadata(server));
}我們知道他第一步要把服務列表要給找出來,你看到這個方法protected Server getServer(String serviceId) {return getServer(getLoadBalancer(serviceId));
}然后又繼續往下找protected Server getServer(ILoadBalancer loadBalancer) {if (loadBalancer == null) {return null;}return loadBalancer.chooseServer("default"); // TODO: better handling of key
}可以看到他這里用了哪個去找,用的是一個ILoadBalancer,看一下這個/*** Interface that defines the operations for a software loadbalancer. A typical* loadbalancer minimally need a set of servers to loadbalance for, a method to* mark a particular server to be out of rotation and a call that will choose a* server from the existing list of server.* * @author stonse* */
public interface ILoadBalancer {他用的這個組件去找,這個組件就是屬于Ribbo下面的com.netflix.loadbalancer.ILoadBalancer所以說他一旦用了負載均衡的技術,都是Ribbon,我們可以看這個方法protected Server getServer(ILoadBalancer loadBalancer) {if (loadBalancer == null) {return null;}return loadBalancer.chooseServer("default"); // TODO: better handling of key
}這里有幾個選擇,我們就選擇com.netflix.loadbalancer.BaseLoadBalancer.chooseServer(Object)/** Get the alive server dedicated to key* * @return the dedicated server*/
public Server chooseServer(Object key) {if (counter == null) {counter = createCounter();}counter.increment();if (rule == null) {return null;} else {try {return rule.choose(key);} catch (Exception e) {logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);return null;}}
}進來之后同樣的可以觀察這個類之間的關系,這個就比上一個復雜一些了public class BaseLoadBalancer extends AbstractLoadBalancerpublic abstract class AbstractLoadBalancer implements ILoadBalancer {看一下ILoadBalancer接口,這里有一個getServerList/*** @deprecated 2016-01-20 This method is deprecated in favor of the* cleaner {@link #getReachableServers} (equivalent to availableOnly=true)* and {@link #getAllServers} API (equivalent to availableOnly=false).** Get the current list of servers.** @param availableOnly if true, only live and available servers should be returned*/
@Deprecated
public List<Server> getServerList(boolean availableOnly);這個已經標記廢棄了,getAllServers這個還在用/*** @return All known servers, both reachable and unreachable.*/
public List<Server> getAllServers();所以我們斷定獲取所有服務列表,肯定是在這個方法com.netflix.loadbalancer.BaseLoadBalancer.getAllServers()@Override
public List<Server> getAllServers() {return Collections.unmodifiableList(allServerList);
}這里我們要獲取列表,所以我們啟動兩個實例,由于服務剛剛啟動完成,還沒來得及獲取服務列表,你就來訪問就來刷新,所以會遇到這個問題,你看這個日志剛剛報了個錯之后,DiscoveryClient打印出的日志,他去獲取所有已經注冊了的服務,這個時候才去獲取,這個時候我們再來訪問,此時能夠獲取服務列表了,就是把這個list作為不能再修改的Listlocalhost:8081/getProductMsghttp://10.40.8.144:8080/msg這是第一步獲取服務列表,我們再來看一下他的負載均衡策略,/** Get the alive server dedicated to key* * @return the dedicated server*/
public Server chooseServer(Object key) {if (counter == null) {counter = createCounter();}counter.increment();if (rule == null) {return null;} else {try {return rule.choose(key);} catch (Exception e) {logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);return null;}}
}我們關心的是規則了protected IRule rule = DEFAULT_RULE;有個默認的規則private final static IRule DEFAULT_RULE = new RoundRobinRule();默認的規則是什么,通過名字也能夠看出來吧,就是輪詢的方式,那我們可以來測試一下,看到底是不是輪詢,把Product兩個都給啟動了,為了以示區別@RestController
public class ClientController {// @Autowired
// private RestTemplate restTemplate;@Autowiredprivate LoadBalancerClient loadBalancerClient;@GetMapping("/getProductMsg")public String getProductMsg() {// 1.第一種方式(直接使用RestTemplate,url寫死)RestTemplate restTemplate = new RestTemplate();
// String response = restTemplate.getForObject("http://localhost:8080/msg", String.class);
// System.out.println(response);// 第二種方式(利用loadBalancerClient通過應用名獲取url,然后再使用restTemplate 注意這里不能用第三種的restTemplate)ServiceInstance serviceInstance = this.loadBalancerClient.choose("product");String url = String.format("http://%s:%s", serviceInstance.getHost(),serviceInstance.getPort()+"/msg");System.out.println(url);return restTemplate.getForObject(url, String.class);// 3.第三種方式(利用@LoadBalanced,可以在restTemplate里使用應用名字)
// String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);
// System.out.println(response);
// return response;}
}一個是8080,一個是9080localhost:8080/msglocalhost:9080/msg可以看到他時輪詢出現的,這里有三個負載均衡類,他用的到底是哪一個呢,我們可以重啟一下,日志里面也會打印出來,public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,ServerList<T> serverList, ServerListFilter<T> filter,ServerListUpdater serverListUpdater) {super(clientConfig, rule, ping);this.serverListImpl = serverList;this.filter = filter;this.serverListUpdater = serverListUpdater;if (filter instanceof AbstractServerListFilter) {((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());}restOfInit(clientConfig);
}就是我們剛剛說到的輪詢,那假如我們想改變負載均衡的規則,其實一般情況下我們不需要改變,你基本上用這個輪詢就可以了,假如需要自己定義的時候,直接在配置里面加一個配置就行了,這個配置很長,不建議大家去記,https://cloud.spring.io/spring-cloud-static/Finchley.SR4/multi/multi_spring-cloud.html我們搜索Ribbon關鍵字,看目錄里面,最好在目錄里面搜到,我們直接通過配置文件就可以配置了https://cloud.spring.io/spring-cloud-static/Finchley.SR4/multi/multi_spring-cloud-ribbon.html#
_customizing_the_default_for_all_ribbon_clients16.4 Customizing the Ribbon Client by Setting Propertiesusers:ribbon:NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerListNFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule這個就是表示我們要配置的ClassName,order.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRuleZoneAvoidanceRule
?
總結
以上是生活随笔為你收集整理的追踪源码自定义负载均衡策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 负载均衡器 Ribbion
- 下一篇: Feign的使用