eureka+Ribbon实现负载均衡(二)

Ribbon简述

是什么
spring cloud ribbon 是一套客户端的负载均衡工具
主要用来:客户端的软件负载均衡算法和服务的调用

做什么
负载均衡+RestTemplate调用

LB负载均衡:将用户请求平摊到多个服务器上,从而达到系统的HA(高可用)
ribbon是本地负载均衡:在调用微服务接口时,会在注册中心中获取注册信息服务列表之后缓存到jvm本地,从而在本地实现rpc的远程调用;
nginx是服务器负载均衡:客户端所用请求交给nginx,然后由nginx实现转发请求.即负载均衡是由服务端实现的。

Ribbon核心组件IRule

负载均衡方式

IRule接口实现类关系图:
在这里插入图片描述
RoundRobinRule:轮询
RandomRule:随机
RetryRule:先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务
WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的实例选择权重越多大,越容易被选择
BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例
ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器

切换负载均衡方式

已知,当我们搭建好的Eureka微服务(参考Eureka
搭建微服务架构
),默认的负载均衡方式是轮询,本案例要做的是将默认的轮询方式切换为随机方式。

pom
由于eureka自带了 Ribbon的依赖,故我们不需要额外的引入。

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

在这里插入图片描述
如何替换算法,把轮询改为随机
官网明确警告:这个自定义配置类不能放在@componentScan所扫描的当前包以及子包下。否则我们的自定义配置类会被所有的Ribbon客户端所共享,达不到特殊化制定的目的。(负载均衡方式,一般配置在消费者端,因此我们只需要对消费者端的代码做一下修改即可)
已知,@SpringBootApplication已经将@componentScan的注解引入,故此,我们不能将我创建的配置类被该注解扫描到
在这里插入图片描述
在这里插入图片描述
从我的代码结构,可以看到,我的配置类MySelfRule创建的位置与主启动类不在同步一包下的,这就避免了MySelfRule被扫描进去。

MySelfRule:

@Configuration
public class MySelfRule {

    @Bean
    public IRule myRule() {
        // 定义为随机
        return new RoundRobinRule();
    }
}

主启动类:

@SpringBootApplication
@EnableEurekaClient
//CLOUD-PAYMENT-SERVICE是服务注册中心的服务名
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OraderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OraderMain80.class,args);
    }
}

在主启动类添加@RibbonClient。

自定义负载均衡

在平时的工作中,往往现有的负载均衡策略无法满足需求,因此我们有必要了解如何自定义负载均衡。
要写一个自定义的负载均衡,我们需要先了解负载均衡的原理。下面将通过刨析RoundRobinRule轮询方式来深入了解。

RoundRobinRule的工作原理

由上述的配置类可知,我们若想切换一个新的负载均衡策略,我们只需要改变配置类注册bean的类型即可。如下:

@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule() {
        // 定义为随机
        return new RandomRule();
    }
}

因此,我们可以从这里入手,要想自定义一个负载均衡策略,只需要自行创建一个与RandomRule同性质的类并注入到容器中供即可。
什么是同性质?
在这里插入图片描述
我们参考上述截图,可见AbstractLoadBalancerRule抽象类之下有几个实现类,分别对应了上述类图关系的其中已有的负载均衡策略,而且他们都实现了相关的三个方法。从这里可以发现,我们若要自定义一个负载均衡,完完全全可以参考该类的实现,只需要将核心的实现方法替换一下就可以了,这里就是我们可以从源码看到的信息。
(友情提示:有时候看源码,不能单纯的看,还要懂得会套用)
我们继续看RandomRule实现:

public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }

            int index = chooseRandomInt(serverCount);
            server = upList.get(index);

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub
		
	}
}

上面的源码很简单,也就是随机获取一个服务int index = chooseRandomInt(serverCount);,getLoadBalancer()方法是父类的实现,因此我们只需要看choose(ILoadBalancer lb, Object key)方法的实现即可。(我们也可以想到,我们自定义的负载均衡类,也只重点实现该方法即可)

至此,没什么好说的,看到这我们已经知道要实现一个自定义的负载均衡策略,已经很明了了。好人做到底,随便贴一下轮询方式的算法原理:
在这里插入图片描述

自定义负载均衡实现

在这里插入图片描述
在这里插入图片描述
如上述截图,具体只需要参考实现抽象类的核心方法就可以了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值