nacos<2>

nacos既支持ap 也支持cp

ap和eureka一样 点对点的 
cp和zk一样  有leader和follow,主从ms架构(master-slave架构)
springcloud 默认采用的是ap 非持久化实例 性能会比持久化实例高很多

cap原则中 ap是点对点的,所有节点都是一样的,你往哪一个节点发送数据都是一样的
nacos 的ap和eureka的集群架构ap是一样的
p 是分区容错性 a 是可用性 说白了,我一个节点挂了 我不需要选举实际上我只要不是所有的节点挂了 此时我的服务还是可用的,他现在要保证可用性,就得牺牲一致性
cp架构 nacos 就像zk一样,发一条数据到leader,此时不像eureka 一样
你发到我这边 我不管你数据有没有同步到其他节点,我都直接告诉客户端发送 成功了


你发一条数据,发到leader 而是等到半数以上的节点都同步成功了,我才会告诉client 你成功了,如果leader挂了 的话 他此时内部会做选举
此时选举中整个集群是不可用的,因此牺牲可用性达到你数据的一致性
等你选举完毕后,整个集群所有数据都同步,你再访问这个节点就有数据了
此时就保证了我们的一致性 而牺牲了可用性
cap原理,再解释一下p 容错就是 不能因为分区,网络不通,你就导致我整个系统宕机
分布式架构中有一个脑裂的概念

脑裂主要说的是主从架构这种集群,ms架构的集群,脑裂 当你这个集群出现网络分区,原来是可以访问的,现在由于网络原因了导致分区了,网络不通了,导致现在变成了2个独立的网络,2个独立的网络不能通信。

在这里插入图片描述

,
网络分区一旦发生 follow 就会重新选举,他吧自己选举为leader  意味着整个集群出现2个leader,2个Leader针对我Client来说既可以往上面的写数据,也可以往下面的写数据
万一网络分区正常了 意味着我整个集群的数据已经乱了,呢到时候再变成一个集群是一个很麻烦的事情

在这里插入图片描述

脑裂主要是在ms架构中,一旦出现网络分区,收不到心跳的呢一方会重新发起投票进行选举
Leader,出现脑裂了,在一个集群中出现多个Leader,客户端可以在任何一个Leader写数据
最终会导致集群间数据紊乱,
nacos和zk尽量要避免脑裂,做了一些避免脑裂的处理,对于zk和nacos来说,leader的选举是有要求的
有个过半机制就是你收到投票过半 你才可以成为Leader

	
如果有5个节点的话, 不管你怎么分,2个节点的分区是选举不出来leader的  集群中有5个节点  如果2,3分区的话 当出现分区的时候,选举不出来leader 的 因为此时最多只能有2票
没有达到过半要求
这样的话不管怎么分区  整个大集群只有一个Leader
呢我们的大集群只有一个Leader,呢对于客户端来说,我只要关注写数据,我永远只往我这个Leader中写数据
回头我网络恢复了,这些节点我发送心跳的时候再吧数据同步过去

当我网络分区恢复后,我再通过心跳机制再吧全量数据同步过去
对于ms架构 cp 中尽量节点数为奇数 .p2p用奇偶都可以,

ms架构中如果是偶数的话出现分区的话  比如说4个节点 ,22 分区此时就选不出leader ,因为一个节点最多只有2票,至少有3票才可以选出来leader,

对于主从架构而言 如果没有Leader 意味着 我整个集群就没有办法对外写服务了,对于ZK这种
架构如果没有Leader,他整个集群就会自动down掉,如果是偶数节点的话 重新选不出leader,(票数不够 因为他只有过半机制才能选举成新的Leader)
对于zk这种架构来说,出现分区了,你选不出Leader,整个系统就没有办法对外提供服务, 他内部有自己的实现机制,这些节点都会报错
如果是奇数节点的话  我不管怎么分区 我整个集群还是只有一个Leader可以满足容错条件的
还有就是集群的容错能力 比如说5个节点和6个节点的集群 容错能力是一一致的	
5个节点  挂了2个 再挂一个集群就不能访问了
6个节点  挂了2个 再挂一个集群就不能访问了
同等容错能力下 奇数比偶数更加节约资源

基于云架构的超大规模注册中心怎么去做,比如说阿里云 ,我一个公司几十个实例注册上去
我多个公司可能就几百 ,实例上去了 并发读或者并发写
不管你nacos 是ap/cp都是不行的

因为他在一个节点会有我所有的实例,不管是对于内存的消耗还是说说从内存找实例
或者是说 你数据在集群节点间的同步

当你服务压力上来之后带来的各种问题

我们可以用到分片存储就相当于redis的cluster,分片架构
redis 集群架构是一个数据分片架构 	

Rabbon源码

在这里插入图片描述

我们user是怎么通过 多个order节点去调用到一个节点的,实际上是调用了rabbon

当我们通过feign的时候底层也是封装了rabbon

restTemplate说白了我只要加上一个@LoadBalanced注解  我就可以做rabbon的负载均衡
 说白了rabbon会把 http://order/  的order 变成ip 然后 restTemplate发送请求
 

在这里插入图片描述

我们可以找到他 (同包 同目录下找)LoadBalancerAutoConfiguration 关于负载均衡的自动装配类
LoadBalancerInterceptor(拦截器) 
RestTemplateCustomizer restTemplate 定制器
SmartInitializingSingleton 

我们可以看到他的配置类就是吧restTemplate   中添加一个拦截器,回头我们RestTemplate调用的时候可能要用到

org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor#intercept‘

我们可以看一下这个拦截器的拦截方法
很有可能当我们
String url = "http://mall-order/";
ResponseEntity<String> responseEntity = restTemplate. getForEntity(url, String.class);
当我们调用这里的时候 拦截器就会最一些事情,  可能从nacos吧对应的ip列表全部拉过来,
内部还要做一次负载均衡去选一个节点
org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient#execute(java.lang.String, org.springframework.cloud.client.loadbalancer.LoadBalancerRequest<T>, java.lang.Object)


	public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
			throws IOException {
		//基于服务名获取一个负载均衡器
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		//根据负载均衡器去选取一个服务 [回头我可能3个节点 我就从3个节点中选一个]
		Server server = getServer(loadBalancer, hint);
		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);
	}
我们看下这个

在这里插入图片描述

	说白了我现在已经找到我对应的负载均衡器了 这里很有可能就是要和nacos做交互
	从nacos中获取列表的地方

在这里插入图片描述
在这里插入图片描述

在springBoot中我们一般找这个Configuration为结尾的  我们可以看到他这个Irule 如果配置了 就用他配置的 比如说配置文件

如果没有配置的就用他ZoneAvoidanceRule  这个默认的 Irule  实例他前先实例他父类 我们先看下 他父类的  choose 方法

在这里插入图片描述

key 是defaulr
  public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
      // 找到可用的服务 过滤掉不可用的服务 
        List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
        if (eligible.size() == 0) {
            return Optional.absent();
        }
        // getone 获取一个
        return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
    }



// 我们主要看这个方法  获取下一个 1,2,3 轮询  这里采用了cas 可以看到 这些框架底层中用了很多方法来提高性能 比如说cas ,之前讲的异步队列   异步  以及copyonwrite 思想	
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextIndex.get();
            int next = (current + 1) % modulo;
            if (nextIndex.compareAndSet(current, next) && current < modulo)
                return current;
        }
    }
然后 get(0),get(1) get(2)
底层真正选server走的是轮询
cas 我不用加锁  我有多个线程同时调用一个方法  

我们这里lb.lb.getAllServers(),  代表我们此时已经拿到了所有的服务了

我们的负载均衡器是怎么拿到的呢??
我们再看看他这个负载均衡器的init 方法
// 我们先看下这个负载均衡器是怎么根据服务id 获取到的
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);

在这里插入图片描述

这里从容器中拿 我们的先放入容器 我们还是看这里的autoconfig 中有没有注入

在这里插入图片描述

我说了我们一般找tConfiguration  为结尾的为自动装配类

ZoneAwareLoadBalancer  我们可以看到他的这个 就是默认的负载均衡器  
我们可以看下他的 serverList是怎么获取的

在这里插入图片描述

大致是这样一个流程

在这里插入图片描述

//获取一个负载均衡器
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);<==========


//获取一个server
Server server = getServer(loadBalancer, hint);<------------ZoneAvoidanceRule
// 所有的去选择一个
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
-------->cas 机制
//  我们发现他是怎么选取的



现在我们要找他是怎么吧所有的服务拿到的com.netflix.loadbalancer.AbstractServerPredicate#incrementAndGetModulo


start--->[1.线程,2.线程池 线程池异步执行线程 [ invoke  updateAction.doUpdate();]]

updateAction.doUpdate();(具体逻辑)------------> updateListOfServers();-->[交互Nacos 获取 所有服务列表]


最终放到tabbon 的这了allServerList

之后定时任务执行刷新这里 因为要保证nacos 是最新的服务 我rabbon也是最新的服务 要拥有服务感知能力
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值