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

1 负载均衡原理

image
浏览器url直接访问http://userservice/user/1是无效的

2 负载均衡流程(难点)

2-1 源码跟踪

为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。
显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor,这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

2-1-1 课件讲解

image
image
image
image
image

2-1-2 本地实操

image
image

image

image
image
image
image
image

image
image
image

image
image
image
image

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

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

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

image
image
image
image
image
image

可以看到,此处经过负载均衡获得了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发出的请求,对地址做了修改

image

3 负载均衡策略(重点)

3-1 常见的负载均衡规则

image
默认常用的实现规则:ZoneAvoidanceRule
image

3-2 修改服务的负载均衡规则

3-2-1 修改方式2种

image
方式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
image
image

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

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

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

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

4 懒加载与饥饿加载(重点)

4-1 懒加载

重启OrderApplication服务
image
清空控制台,进行首次访问
首次访问时间:385ms
image
image
image
清空控制台,进行2次访问
二次访问时间:100ms
image
image
image
原因:默认懒加载

4-2 饥饿加载

image
image
重启OrderApplication服务
image
清空控制台,进行首次访问
首次访问时间:260ms
image
image
image
清空控制台,进行2次访问
二次访问时间:43ms
image
image
image

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

image

posted @ 2022-01-09 13:38  yub4by  阅读(58)  评论(0)    收藏  举报