eureka的負載均衡、ribbon的原理
阿新 • • 發佈:2018-11-30
ribbon 來完成負載均衡
RibbonLoadBalanceClient 類,是用來 進行負載均衡的;
其中有個 choose 的方法,原始碼如下:
》
意思是,對serverId 進行例項化;
建立測試類;
那麼對其進行詳解下:
RibbonLoadBalanceClient 中有getServer( )這個獲取服務的方法:
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId) , serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
點選 getServer 跟進去,底層維護了 chooseServer()的一個方法,繼續點
protected Server getServer(ILoadBalancer loadBalancer) {
if (loadBalancer == null) {
return null;
}
return loadBalancer.chooseServer ("default"); // TODO: better handling of key
}
進入chooseServer 跟蹤到 ILoadBalancer
Ctrl alt B 檢視, 該介面的一個 實現類 BaseLoadBalancer
public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
private static Logger logger = LoggerFactory.getLogger(BaseLoadBalancer.class);
// rule的預設值
private static final IRule DEFAULT_RULE = new RoundRobinRule();
private static final BaseLoadBalancer.SerialPingStrategy DEFAULT_PING_STRATEGY = new BaseLoadBalancer.SerialPingStrategy();
private static final String DEFAULT_NAME = "default";
private static final String PREFIX = "LoadBalancer_";
// IRule 類
protected IRule rule;
protected IPingStrategy pingStrategy;
protected IPing ping;
@Monitor(
name = "LoadBalancer_AllServerList",
type = DataSourceType.INFORMATIONAL
)
private static final IRule DEFAULT_RULE = new RoundRobinRule();
可以得知,IRule rule 的預設值是 RoundRobinRule 的一個物件,即輪詢的物件,即預設的規則是輪詢的方式;
public Server choose(Object key) {
ILoadBalancer lb = this.getLoadBalancer();
Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
return server.isPresent() ? (Server)server.get() : null;
}
在服務的消費者新增@LoadBalanced 註解;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
@Bean
@LoadBalanced //新增負載均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
直接使用服務名來查詢服務:
@RestController
@RequestMapping("consumer")
public class ConsumerController {
/**
* 注入 springCloud 的DiscoveryClient
*/
// @Autowired
// private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}")
public User get(@PathVariable("id")Long id){
// 從eureka 中取出一個服務
// List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
// ServiceInstance serviceInstance = instances.get(0);
// 從服務中 獲取 port 以及host 組成url 、 進行查詢
// String url = String.format("http://%s:%s/user/%s", serviceInstance.getHost(), serviceInstance.getPort(), id);
// String url="http://localhost:8081/user/"+id;
// return restTemplate.getForObject(url, User.class, id);
String url="http://user-service/user/"+id;
return restTemplate.getForObject(url,User.class );
}
}
訪問 http://localhost:8080/consumer/1
建立測試類,重寫RibbonLoadBalanceClient 類 中的choose 方法,進行測試;
/**
* @auther SyntacticSugar
* @data 2018/11/29 0029下午 9:04
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConsumerApplication.class)
public class LoadBalancedTest {
@Autowired
RibbonLoadBalancerClient loadBalancerClient;
@Test
public void test() {
for (int i = 0; i < 10; i++) {
ServiceInstance instance = loadBalancerClient.choose("user-service");
System.out.println(instance.getPort());
}
}
}
執行:
可以看到負載均衡預設是採用輪詢的方式;
對配置檔案進行更改,可以更改IRule 的實現類,從而修改規則;
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
檢視 IRule 的實現類如下;