• spring cloud 学习笔记 客户端(本地)均衡负载(三)


    前言

    在微服务中,一个服务可能即是服务端也是客户端,当别的服务调用该服务的时候这个服务就是服务端,当这个服务主动调用另外一个服务的时候,那么就是服务端。

    作为客户端通过服务注册与发现获取某个服务的注册列表后,那么如何均衡负载呢?前面我们提及到了,那么eureka客户端中自带了均衡负载策略,这个均衡负载组件就是ribbon。

    为什么需要一个独立组件来均衡负载呢?一个是均衡负载的算法有很多,比如说轮询算法,但是通用轮询算法也有问题,比如说两台不同量级的机器,如果分配同等的工作量,那么有一个满了,另外一台还是空闲很多。

    这里介绍一个ribbon客户端均衡负载的组件,其他的也一样,看文档就好。

    正文

    首先引入包:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    

    然后再订单模块中加入一个请求。

    @GetMapping("/consumer/payment/getForEntity/{id}")
        public CommonResult<Payment> getPayment2(@PathVariable("id") Long id){
             ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
             if (entity.getStatusCode().is2xxSuccessful()){
                 return  entity.getBody();
             }else{
                 return  new CommonResult<>(444,"error request for payment");
             }
        }
    

    然后调用一下:

    两次请求都不一样。这里是效果。

    查看结构图ribbon 结构图:

    从上图可以看出ribbon 有7种方式进行负载均衡方式。

    如果是网上有详细介绍的,一般不自己写,这里贴一下别人写好的:

    https://blog.csdn.net/whiteBearClimb/article/details/108703356

    我们可以根据不同场景进行选择,这些都是看情况讨论。

    比如说,4台机器的响应速度和配置都差不多,那么轮询就好,这样开销小,如果是不同,那么可以考虑其他的方式来更大的利用资源。

    那么如何替换规则:

    自定义一个类:

    package myrule;
    
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RandomRule;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MySelfRule {
        @Bean
        public IRule myRule(){
            return new RandomRule();
        }
    }
    

    然后在启动类上进行声明:

    @RibbonClient(name="CLOUD-PROVIDER-SERVICE",configuration = MySelfRule.class)
    

    效果:两次访问都是8001,随机访问任意一台。

    那么这个RibbonClient 是如何实现的呢?

    这里直接说原理:RibbonClient 会直接读取eureka的该服务的注册表,通过服务的注册表来实现均衡负载。

    打开类继承关系:

    在右边找到RoundRobinRule这个,然后就可以看到具体轮询的实现了。

    public Server choose(ILoadBalancer lb, Object key) {
    	if (lb == null) {
    		log.warn("no load balancer");
    		return null;
    	}
    
    	Server server = null;
    	int count = 0;
    	while (server == null && count++ < 10) {
                    // 获取有效服务
    		List<Server> reachableServers = lb.getReachableServers();
                    // 获取全部服务
    		List<Server> allServers = lb.getAllServers();
    		int upCount = reachableServers.size();
    		int serverCount = allServers.size();
                    // 有效服务为0返回null
    		if ((upCount == 0) || (serverCount == 0)) {
    			log.warn("No up servers available from load balancer: " + lb);
    			return null;
    		}
                    // 通过全部服务获取下一个服务
    		int nextServerIndex = incrementAndGetModulo(serverCount);
    		server = allServers.get(nextServerIndex);
    
    		if (server == null) {
    			/* Transient. */
    			Thread.yield();
    			continue;
    		}
    
    		if (server.isAlive() && (server.isReadyToServe())) {
    			return (server);
    		}
    
    		// Next.
    		server = null;
    	}
    
    	if (count >= 10) {
    		log.warn("No available alive servers after 10 tries from load balancer: "
    				+ lb);
    	}
    	return server;
    }
    

    实现选择,直接看choose,里面我注释了一部分。

    可以看到选择哪个服务其实是通过incrementAndGetModulo 这个方法来选择的。

    private int incrementAndGetModulo(int modulo) {
            for (;;) {
                // 获取当前的值
                int current = nextServerCyclicCounter.get();
                // 计算获得新的索引
                int next = (current + 1) % modulo;
                // 更新新的索引
                if (nextServerCyclicCounter.compareAndSet(current, next))
                    return next;
            }
        }
    

    nextServerCyclicCounter 是new AtomicInteger(0); 这个的实例。

    AtomicInteger 是一个原子操作类,至于其原理需要自己去看,效果是原子操作,就是在并发的时候依然可以保持其本来的面目,故而原子。

    上面的注释应该很清楚了。原理还是比较简单的。

    通过了解上面的选择方式,那么可以自己去实现对应的接口和写相应的code来实现自己特殊业务需要的均衡负载方式。

  • 相关阅读:
    python反射
    numpy笔记
    leetcode43
    leetcode-42
    The Github Flow
    leetcode-37
    leetcode-41
    leetcode-40
    TCP扫盲2
    字节码分析与操作
  • 原文地址:https://www.cnblogs.com/aoximin/p/14675220.html
Copyright © 2020-2023  润新知