HM-SpringCloud微服务系列1.5【Ribbon负载均衡】
1 负载均衡原理

浏览器url直接访问http://userservice/user/1是无效的
2 负载均衡流程(难点)
2-1 源码跟踪
为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。
显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor,这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。
2-1-1 课件讲解





2-1-2 本地实操














说明ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);是在根据服务名称找eureka拉取服务列表
Server server = this.getServer(loadBalancer, hint);执行负载均衡






点击几次step over,直到return this.rule.choose(key);


选中IRule使用快捷键ctrl+h跳出IRule接口的实现类列表(即负载均衡的策略是由IRule这个接口决定的)






可以看到,此处经过负载均衡获得了8081,再次访问时可能就会获得8082
源码就先看到这里ok,取消断点,放行(其实若想继续看源码,一直点击step over,会返回到设置断点的地方)
public Server chooseServer(Object key) {
if (ENABLED.get() && this.getLoadBalancerStats().getAvailableZones().size() > 1) {
Server server = null;
try {
LoadBalancerStats lbStats = this.getLoadBalancerStats();
Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
logger.debug("Zone snapshots: {}", zoneSnapshot);
if (this.triggeringLoad == null) {
this.triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2D);
}
if (this.triggeringBlackoutPercentage == null) {
this.triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999D);
}
Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, this.triggeringLoad.get(), this.triggeringBlackoutPercentage.get());
logger.debug("Available zones: {}", availableZones);
if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
logger.debug("Zone chosen: {}", zone);
if (zone != null) {
BaseLoadBalancer zoneLoadBalancer = this.getLoadBalancer(zone);
server = zoneLoadBalancer.chooseServer(key);
}
}
} catch (Exception var8) {
logger.error("Error choosing server using zone aware logic for load balancer={}", this.name, var8);
}
if (server != null) {
return server;
} else {
logger.debug("Zone avoidance logic is not invoked.");
return super.chooseServer(key);
}
} else {
logger.debug("Zone aware logic disabled or there is only one zone");
return super.chooseServer(key);
}
}
2-2 负载均衡流程图
SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求,对地址做了修改

3 负载均衡策略(重点)
3-1 常见的负载均衡规则

默认常用的实现规则:ZoneAvoidanceRule

3-2 修改服务的负载均衡规则
3-2-1 修改方式2种

方式1是全局的,对所有服务生效
方式2需要指定服务名称,只对指定服务生效
3-2-2 修改之前测试
浏览器依次访问
http://localhost:8080/order/101
http://localhost:8080/order/102
http://localhost:8080/order/103
http://localhost:8080/order/104


3-2-3 采用方式1修改负载均衡规则之后测试

重启OrderApplication服务
清空UserApplication和UserApplication2服务的控制台后,还是依次访问上述4个地址


3-2-4 采用方式2修改负载均衡规则之后测试


重启OrderApplication服务
清空UserApplication和UserApplication2服务的控制台后,还是依次访问上述4个地址


4 懒加载与饥饿加载(重点)
4-1 懒加载
重启OrderApplication服务

清空控制台,进行首次访问
首次访问时间:385ms



清空控制台,进行2次访问
二次访问时间:100ms



原因:默认懒加载
4-2 饥饿加载


重启OrderApplication服务

清空控制台,进行首次访问
首次访问时间:260ms



清空控制台,进行2次访问
二次访问时间:43ms



PS:虽然访问时,饥饿加载比懒加载耗时短,但为啥两次访问时间还是首次比二次多?
原因是除了负载均衡这些外,还有例如DispacherServlet等需要首次访问时加载(其实也可以设置为服务启动时加载,此处不做演示)



浙公网安备 33010602011771号