zoukankan      html  css  js  c++  java
  • springcloud ribbon实现原理

    一、ribbon  负载均衡原理

    1.客户端负载均衡,通过LoadBalancerclient来实现,ILoadBalancer 通过配置IRule 和IPin 来实现

    2.ILoadBalancer 通过每10s 获取一次Eureka 注册地址,获取到注册列表后按照IRule 注册规则进行负载均衡

    二、核心原理拦截器

    1.ribbon 的核心其实就是代理,通过拦截器的方式

    2.拦截器实现的功能1:通过对请求的拦截,获取url ,解析hostname 通过hostname 再到Eureka 拿取真实的ip 端口,建立连接发送数据

    3.拦截器实现的功能2:拿到目标服务的列表后,按照Rule规则选择具体的目标服务,从而实现负载均衡

    三、代码的实现过程

    spring启动过程

    1.通过@Bean向spring中注入RestTemplete 对象

    2.通过@LoadBanlance 注解,实现RestTemplete  注入拦截器,将自定义的拦截器注入RestTemplete  的拦截器链中

    http调用过程

    1.调用RestTemplete  调用目标服务交口(hostname+接口名称),RestTemplete 的拦截器会拦截该方法,从而对接口修改和增强,把url地址改为(ip+端口+接口名称) 

    2.完成规则获取以及ip端口准备后,就开始连接目标服务发送数据,连接是通过httpclient 实现,通过工厂类获取httpclient 连接对象

    四、源代码

    MyConfig 实现启动时给RestTemplete 绑定拦截器
    @Configuration
    public class MyConfig {
    
        
        // 需要使用 Autowired 注解注入所有被 @MyLoadBalanced 定义的 RestTemplate 配置 ,因为使用了 @Configuration
        // (required=false) 非必须的, 有没有都可以注入,正常运行
        @Autowired(required=false)
        @MyLoadBalanced
        private List<RestTemplate> tpls = Collections.emptyList();
    
        @Bean
        public SmartInitializingSingleton lbInitializing() {
    
            return new SmartInitializingSingleton() {
    
                public void afterSingletonsInstantiated() {
    
    //                System.out.println(tpls.size());
                    
                    for (RestTemplate restTemplate : tpls) {
                        
                        List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
                        interceptors.add(new MyInterceptor());
                        //interceptors.add(new MyInterceptor2());
                        restTemplate.setInterceptors(interceptors);
                    }
    
                }
            };
        }
    }
    MyInterceptor 拦截器类,实现url转化及规则处理
    public class MyInterceptor implements ClientHttpRequestInterceptor {
    
    
        public ClientHttpResponse intercept(HttpRequest request, byte[] body,
                ClientHttpRequestExecution execution) throws IOException {
    
            System.out.println("####这是自定义拦截器####");
            System.out.println("***********旧的 URI:" + request.getURI());
            
            HttpRequest newRequest = new MyRequest(request);
            System.out.println("&&&&&&&&&&&&新的 URI:" + newRequest.getURI());
            
            return execution.execute(newRequest, body);
        }
    MyRequest  封装的新的httpRequest类(ip+端口)
    public class MyRequest implements HttpRequest {
    
        HttpRequest sourceRequest;
        
        public MyRequest(HttpRequest sourceRequest){
            this.sourceRequest = sourceRequest;
        }
        
        public HttpHeaders getHeaders() {
    
            return sourceRequest.getHeaders();
        }
    
        public HttpMethod getMethod() {
            
            return sourceRequest.getMethod();
        }
    
        public URI getURI() {
    
            try {
                URI newUri = new URI("http://localhost:8086/hello");
                
                return newUri;
            } catch (URISyntaxException e) {
    
                e.printStackTrace();
            }
            
            return sourceRequest.getURI();
        }
    
    }
    MyController  客户端controller
    @RestController
    @Configuration
    public class MyController {
    
        @Resource(name="tplA")
        RestTemplate restTemplate;
    
        @RequestMapping(value="/call", method=RequestMethod.GET)
        public String call(){
    
            return restTemplate.getForObject("http://hello-service/call4", String.class);
        }
        
        @RequestMapping(value="/hello", method=RequestMethod.GET)
        public String hello(){
            
            return "hello word";
        }
    }
    RestTplApp  启动类,把restemplete 注入spring容器以及配置负载均衡标记
    @SpringBootApplication
    public class RestTplApp {
    
        public static void main(String[] args) {
            
            SpringApplication.run(RestTplApp.class, args);
        }
    
        @Bean
        //@MyLoadBalanced
        RestTemplate tplA(){
    
            return new RestTemplate();
        }
    
        @Bean
        @MyLoadBalanced
        RestTemplate tplB(){
    
            return new RestTemplate();
        }
    }

    五、ribbon的负载均衡算法
    1.RoundRobinRule轮询(默认的算法)
    2.RandomRule 随机
    3.AvailabilityFilteringRule 优先过滤一部分算法,被过滤的是多次访问故障处于断路器状态的服务,以及并发连接数量超过阈值的服务,然后执行轮询算法
    4.WeightedResponseTimeRule 响应时间权重算法,响应时间越短,权重越大,被调用的机会越大
    5.RetryRule 轮询算法重试,如果轮询失败,则在有限时间内重试
    6.BestAvailableRule 并发量算法,优先过滤掉熔断的服务,然后再选择并发量最小的连接
    7.ZoneAvoidanceRule 复合算法,计算server的可用性,从而选取最有

    六、ribbon 负载算法代码配置
    //配置负载均衡的策略为随机,默认算法为轮询算法
        @Bean
        public IRule myRule()
        {
            //return new RoundRobinRule();
            return new RandomRule();  
        }      
    
    
    
     

    源码地址:https://github.com/197wj/Ribbon

  • 相关阅读:
    event loop笔记
    webpack不同devtools打包对比
    windows 7系统搭建本地SVN服务器的过程
    Eclipse安装SVN插件
    总结eclipse中安装maven插件
    myeclipse building workspace如何禁止及提高myeclipse速度
    基于SAML的单点登录介绍
    使用 CAS 在 Tomcat 中实现单点登录
    SSO之CAS备忘
    Maven环境变量配置
  • 原文地址:https://www.cnblogs.com/lufei33180/p/14489157.html
Copyright © 2011-2022 走看看