Ribbon之ZoneAwareLoadBalancer及其父类做了些什么?

1.看看ZoneAwareLoadBalancer都做了些什么?

这个类主要是跟Zone有关的,提供了跟zone有关的方法。但是在国内基本上用不上。

eureka提供了region和zone两个概念来进行分区,这两个概念均来自于亚马逊的AWS:
region:可以简单理解为地理上的分区,比如亚洲地区,或者华北地区,再或者北京等等,没有具体大小的限制。根据项目具体的情况,可以自行合理划分region。
zone:可以简单理解为region内的具体机房,比如说region划分为北京,然后北京有两个机房,就可以在此region之下划分出zone1,zone2两个zone。

简单的说一下这个类里面的几个方法:

1.setServerListForZones : 这个基于Zone进行服务划分

2.chooseServer这里也是主要跟zone有关的计算,当然默认的Zone只有一个,所以直接是调用的父类的chooseServer(key)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8TDLFqVn-1623737287889)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/394d05a4-5452-44c6-8534-8bd2fb53a2c7/Untitled.png)]

3.getLoadBalancer(String zone) 基于zone去获取LoadBalancer

4.setRule(IRule rule) 为每个负载均衡器设置规则。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mWAOpfBM-1623737287896)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0e62905c-f9dc-4456-bba6-ede1304a95a0/Untitled.png)]

这里可以看到,其实这个主要是针对Zone做了一些分类处理,就是将原来属于同一服务的服务实例,再根据地区进行划分。这也是为了能够快速响应而设置的。



2.ZoneAwareLoadBalancer的父类DynamicServerListLoadBalancer 做了些什么?

这个类按照名称来说就是动态加载服务列表使用的。其中有个几个比较重要的方法

1.获取服务列表并更新本地缓存的服务列表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADYLJRZj-1623737287898)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0063cd9e-c3c0-4d45-bb01-fdc9c4a32c1d/Untitled.png)]

2.开启服务列表更新定时任务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7JnlBGfF-1623737287901)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7006fcf2-5b3b-4a2c-b4e5-0d29c0308b33/Untitled.png)]

3.开启监听

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YMujsbGW-1623737287903)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/996f100d-36c3-4064-9dbe-a1ba6c4f6665/Untitled.png)]

DynamicServerListLoadBalancer的核心就是获取服务列表,默认是通过DomainExtractingServerList来获取,这个类是在org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientConfiguration#ribbonServerList

方法中声明的。这是eureka为ribbon提供的获取服务列表的入口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pY3rt10d-1623737287905)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3c8c695f-a2fb-4c1e-b3ba-d7cb61640242/Untitled.png)]
在这里插入图片描述



3.如何通过DynamicServerListLoadBalancer 来获取服务列表的呢?

从上面的两张图可以看出,DomainExtractingServerList是用来获取服务列表,那底层是如何实现的呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ItH2al88-1623737287908)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e926d172-e9bc-4abd-8bc9-1044c39a055e/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JjJNfpo3-1623737287910)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ecbcba40-ece4-47d4-851c-55f37aeee1a2/Untitled.png)]

这两张图刚好与ribbonServerList方法中创建DomainExtractingServerList的情形一致。那么我们就知道了,DiscoveryEnabledNIWSServerList才是获取服务列表的最终处理类(这是在基于有eureka的情况下)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KNniuqlh-1623737287913)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7f35d1fa-9b94-484a-9f61-ddb7cd0b324e/Untitled.png)]
在这里插入图片描述



7.DynamicServerListLoadBalancer的父类BaseLoadBalancer做了些什么?

核心默认值

  • 默认的负载均衡策略RoundRobinRule

  • 默认的Ping策略SerialPingStrategy

  • 所有服务实例容器:allServerList

  • 在线服务实例容器:upServerList

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SbEOKRRj-1623741864050)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/197ab285-9b1f-4ebd-96d1-8cadb2af5f6e/Untitled.png)]

从子类构造中将对应的负载均衡规则,ping策略,ping等传递过来

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rC56K9Hl-1623741864055)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5ad2e71d-deea-436a-bc1f-e5ad1907903e/Untitled.png)]

这里可以看到ping为null,setPingTask是用来开启ping的定时任务,默认每10秒ping一次。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRbQwM3d-1623741864058)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/6996aac3-4b24-4da3-a870-0b2f7103954a/Untitled.png)]



8.ping做了些什么?

PingTask作为一个线程任务,就是定期检查服务是否都存活,跟ServerListUpdater服务更新机制不冲突。这是ribbon自己维护的一套服务检测机制,主要是为了降低访问失败的概率。默认在使用eureka时,ping是使用的是NIWSDiscoveryPing来完成服务保活检测。由eureka 和 ServerListUpdater来刷新服务列表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9b8KCqK5-1623741864061)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/6bda93f4-f215-45cc-bf52-db8da2643d40/Untitled.png)]

这里有个常用的定时任务快速退出的方法,我觉得在我们自己写的时候也可以使用。

就是在同一个定时任务如果执行时间超过了定时周期,那么下一个定时任务发现上一个定时任务还没有执行完时,就先取消。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-byGHa3Ws-1623741864065)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a78aaf08-2852-4040-b7f9-2ea193abd9ce/Untitled.png)]

这里也用了很多锁机制,比如复制所有服务实例到一个新的对象时使用的是读锁,就是告诉allServers现在只能读不能写。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YNioWBHe-1623741864066)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1f6ac654-a66c-4713-adec-132e0f4c0a42/Untitled.png)]

在发送ping后,将检测通过的服务放入newUpList中,最后通过写锁,将upServerList锁住。

这里就是只能有一个写,且不能读。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t0ODuik6-1623741864067)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/6ee589e0-c5a9-4cde-b93e-008d598e66c2/Untitled.png)]

上面是ping在检测过程中关于读写锁和原子类的使用,是我们应该学着融入我们自己的项目中的东西。

主要流程就是:

1.读取全部服务实例列表

2.检测服务实例是否存活pingServers

3.将服务状态发生改变的放入changedServers

4.将服务在线的放入newUpList

5.将newUpList赋值到upServerList 在线服务实例列表中

这里面pingServers就是检查心跳的

private static class SerialPingStrategy implements IPingStrategy {

        @Override
        public boolean[] pingServers(IPing ping, Server[] servers) {
            int numCandidates = servers.length;
            boolean[] results = new boolean[numCandidates];

            logger.debug("LoadBalancer:  PingTask executing [{}] servers configured", numCandidates);

            for (int i = 0; i < numCandidates; i++) {
                results[i] = false; /* Default answer is DEAD. */
                try {
                    // NOTE: IFF we were doing a real ping
                    // assuming we had a large set of servers (say 15)
                    // the logic below will run them serially
                    // hence taking 15 times the amount of time it takes
                    // to ping each server
                    // A better method would be to put this in an executor
                    // pool
                    // But, at the time of this writing, we dont REALLY
                    // use a Real Ping (its mostly in memory eureka call)
                    // hence we can afford to simplify this design and run
                    // this
                    // serially
										// 上面一片注释告诉我们,如果我们有很多服务,其实直接使用for循环来写
										// 会比较耗时,最好是用线程池来做。但是,ribbon主要是为了跟eureka进行结合,
										// 这里的调用就是调用的当前服务的eurekaClient来检测
										// 其实不涉及到ping其他服务,所以这里就偷懒了。
										// 而spring cloud ribbon连ping都没用
                    if (ping != null) {
                        results[i] = ping.isAlive(servers[i]);
                    }
                } catch (Exception e) {
                    logger.error("Exception while pinging Server: '{}'", servers[i], e);
                }
            }
            return results;
        }
    }
}

其实在我使用eureka和ribbon进行连接的时候,ping是为NIWSDiscoveryPing的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQnDWtmk-1623741864069)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/eb4ab59e-2693-4237-8664-e7f227fdf41a/Untitled.png)]
其实如果不使用ping的话,默认的ribbon从eureka读取注册表信息是30秒一次。且也没有事件监听机制。那么ribbon自己的缓存更新,可能会造成一个服务上线或者下线30秒后才会被ribbon发现。所以ping机制还是有必要的,所以每10秒检测一次服务存活状态刚好弥补了30秒的空档期。

9.BaseLoadBalancer的其他功能简述

  1. 对allServerList和upServerList的读写锁方法
  2. 提供对allServerList和upServerList的增删改功能
  3. 提供了PingTask(ping的定时任务),Pinger(ping的执行器)
  4. 基于负载均衡策略选择服务rule.choose(key)
  5. 提供默认的ping策略SerialPingStrategy

ILoadBalancer各个层级之间负责不同的功能,这也是我们自己在设计一个对象时需要考虑的事情,从不同的层次去继承和组合我们就能得到我们想要的东西。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值