SpringCloudAlibaba系列微服务搭建笔记二-RestTemplate+Ribbon

目录儿

  • 五、远程调用-RestTemplate+Ribbon
    • 5.1 RestTemplate 简介
    • 5.2 Ribbon 简介
    • 5.3 Ribbon 内置负载均衡算法
    • 5.4 如何设置负载均衡规则
      • 5.4.1 默认规则
      • 5.4.2 修改规则
    • 5.5 RestTemplate 与 Ribbon的使用
    • 5.6 自定义负载均衡策略
    • 总结

五、远程调用-RestTemplate+Ribbon

5.1 RestTemplate 简介

RestTemplatespring-web.jar包下的一个类,简化了http的请求过程,在应用中能够方便地调用rest服务。
默认情况下,使用无参构造器创建的RestTemplate对象用的是java.net包的实现完成http的连接。
可以使用带参构造器RestTemplate(ClientHttpRequestFactory requestFactory)创建用HttpClient实现http连接的RestTemplate对象

5.2 Ribbon 简介

我们这里用到不仅仅是Netflix Ribbon这个基础的Ribbon组件,还包含springframework.cloud.netflix.ribbon 这个基于Netflix Ribbon再次封装的负载均衡框架。主要功能就是通过负载均衡算法完成服务调用。Ribbon可以从服务注册中心拿到具体的服务地址列表,根据负载均衡算法选择调用其中一个服务。

5.3 Ribbon 内置负载均衡算法

所有规则(算法)都要实现IRule接口,所以先看接口结构

package com.netflix.loadbalancer;

public interface IRule {
    Server choose(Object var1);  // 选择一个服务
    void setLoadBalancer(ILoadBalancer var1); // 设置负载均衡器
    ILoadBalancer getLoadBalancer(); // 获取负载均衡器
}

主要的方法就是那个choose()方法,用来选择服务,暂不深究,
查看IRule接口的实现类就能知道Ribbon有哪些内置算法。
SpringCloudAlibaba系列微服务搭建笔记二-RestTemplate+Ribbon_第1张图片

名称 说明
RoundRobinRule 轮询算法
RandomRule 随机算法
AvailabilityFilteringRule 先过滤掉不可用服务,再使用轮询算法
WeightedResponseTimeRule 自动根据响应时间计算权重,统计信息不足时使用轮询算法
RetryRule 使用轮询算法获取服务,如遇失败在规定时间内重试
BestAvaliableRule 先过滤掉不可用服务,选择并发量最小的服务
ZoneAvoidanceRule 根据服务的性能和可用性去选择服务

5.4 如何设置负载均衡规则

5.4.1 默认规则

在原本的Netflix Ribbon 组件中的BaseLoadBalancer中,可以看到默认的负载均衡策略是RoundRobinRule轮询算法。

package com.netflix.loadbalancer;

public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
	...
	private static final IRule DEFAULT_RULE = new RoundRobinRule();
	...
}

但是在springframework.cloud.netflix.ribbon框架中重新定义了负载均衡的初始化逻辑

    @Bean
    @ConditionalOnMissingBean // 当容器没有 IRule 这个 Bean 对象的时候进行初始化
    public IRule ribbonRule(IClientConfig config) {
    	// 先去检查有没有配置对应的规则
        if (this.propertiesFactory.isSet(IRule.class, this.name)) {
            return (IRule)this.propertiesFactory.get(IRule.class, config, this.name);
        } else { // 没有的话直接创建一个 ZoneAvoidanceRule 对象交给容器管理
            ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
            rule.initWithNiwsConfig(config);
            return rule;
        }
    }

所以在springframework.cloud.netflix.ribbon框架中Ribbon Client的默认负载均衡策略是ZoneAvoidanceRule根据服务的性能和可用性去选择服务。

5.4.2 修改规则

基于springframework.cloud.netflix.ribbon框架中负载均衡的初始化逻辑,可以知道它在容器中没有IRule对象的时候会先检查配置,如果没有就创建默认的规则。所以我们可以通过注入IRule对象的方式修改成自己想要的规则。

@Configuration
public class RuleConfig {
    @Bean
    public IRule injectRule() {
        return new RandomRule(); // 创建一个 RandomRule 交给容器管理
    }
}

5.5 RestTemplate 与 Ribbon的使用

创建一个配置文件,注入RestTemplate 对象

@Configuration
public class GenericConfig {
    @Bean
    @LoadBalanced // 必须添加负载均衡注解
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

因为前面已经设置过Ribbon的规则了,注意这个@LoadBalanced,它能让RestTemplate 对象直接被Ribbon代理,所以后面我们直接使用RestTemplate 对象去调用服务就行,它会自动均衡负载。
用这个RestTemplate 对象远程调用服务,我这里用了了nacos作为服务注册中心。

@RestController
public class TestController {
    @Value("${server.port}")
    private String port;

    private final String SERVER_URL = "http://nacos-provider"; // 这里不写具体的某个服务的ip和端口,而是通过注册到 Nacos 的服务名代替
    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/test")
    public String test() {
        String result = restTemplate.getForObject(SERVER_URL + "/test", String.class);
        return "①号消费者(" + port + "):" + result;
    }
}

5.6 自定义负载均衡策略

最简单的方法就是模仿,随便挑一个规则看看它是怎么实现的,这里挑最简单的RandomRule

public class RandomRule extends AbstractLoadBalancerRule {

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
		...
        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
	}
}

可以看到它继承了AbstractLoadBalancerRule,然后重写(这里应该叫实现比较合适)了它的choose()方法和initWithNiwsConfig(),还有两个内部的算法函数,里面是具体的负载均衡算法,暂不深究。

依葫芦画瓢,写个简单的算法

@Component
public class CustomRule extends AbstractLoadBalancerRule {
    private AtomicInteger atomicInteger = new AtomicInteger(0); //

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

    public Server chooseLogic(ILoadBalancer loadBalancer, Object key) {
        if (loadBalancer == null) {
            return null;
        }
        List<Server> allServers = loadBalancer.getAllServers(); // 获取服务列表
        int requestNum = this.atomicInteger.incrementAndGet();  // 自增
        if (requestNum >= Integer.MAX_VALUE) {
            atomicInteger = new AtomicInteger(0);    // 重置
        }
        if (allServers != null) {
            int size = allServers.size();
            int index = requestNum % size;
            Server server = allServers.get(index);
            if (server == null || !server.isAlive()) {
                return null;
            }
            return server;
        }
        return null;
    }

    public void initWithNiwsConfig(IClientConfig iClientConfig) { } // 空实现
}

同样的,注入容器即可

@Configuration
public class RuleConfig {
    @Bean
    public IRule injectRule() {
        return new CustomRule ();
    }
}

总结

RestTemplate+Ribbon这个远程调用方式是比较老的,而且在调用的时候都要填写地址。现在一般都用OpenFeign或者Dubbo Spring Cloud代替它,更加方便简洁。

你可能感兴趣的:(微服务,ribbon,java)