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


    五、远程调用-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有哪些内置算法。
    在这里插入图片描述

    名称说明
    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代替它,更加方便简洁。

    承上:SpringCloudAlibaba系列微服务搭建笔记一_Nacos
    启下:SpringCloudAlibaba系列微服务搭建笔记三_Sentinel

    请添加图片描述

  • 相关阅读:
    若依对SpringSecurity框架的运用
    BGP配置和应用案例
    工地木模板多少钱一张?
    JavaScript实现动态时钟显示
    高德地图sdk设置marker并且将设置为地图中心
    R语言混合效应(多水平/层次/嵌套)模型及贝叶斯实现
    基于51单片机多路DTH11温湿度检测控制系统
    短视频/直播+教育成为教育新常态
    Python + re + scrapy.Selector: 分析提取某在线征信站体系内容(一)
    【机器学习教程】五、支持向量机(Support Vector Machines)
  • 原文地址:https://blog.csdn.net/qq_31856061/article/details/127090837