• Eureka源码探索(一)-客户端服务端的启动和负载均衡


    1. Eureka源码探索(一)-客户端服务端的启动和负载均衡

    1.1. 服务端

    1.1.1. 找起始点

    1. 目前唯一知道的,就是启动Eureka服务需要添加注解@EnableEurekaServer,但是暂时找不到它被使用的地方
    2. 看日志,明显有打印discovery client,服务端同时也用作客户端,因为它可以相互注册,以下是自动配置类
    3. 知道了客户端有自动配置类,可以想象服务端也应该有,找到相应的包,发现果然有

    1.1.2. 服务初始化

    1. 启动初始化
    2. 接下来是个发布订阅方法,发布对象继承了Spring的ApplicationEvent,可以看出肯定会有订阅者接收该配置,配置内容就是我们application.properties里配置的属性,不配则是默认属性

    1.1.3. @EnableEurekaServer起作用的原理

    1. 进入该注解,可以看到注解中还有个注解@Import它的作用就是将之后的类对象所对应的实例,实例化并加入spring容器管理
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(EurekaServerMarkerConfiguration.class)
    public @interface EnableEurekaServer {
    
    }
    
    1. 进入EurekaServerMarkerConfiguration类,可以看到如下,该类的作用仅仅用来标记下,为启动类判断是否需要启动EurekaServer
    @Configuration
    public class EurekaServerMarkerConfiguration {
    
    	@Bean
    	public Marker eurekaServerMarkerBean() {
    		return new Marker();
    	}
    
    	class Marker {
    
    	}
    
    }
    
    
    1. 它具体被使用的地方如下,用一个@ConditionalOnBean表示,若存在该类Bean,则启动配置生效

    1.2. 客户端

    1.2.1. 调用解析过程

    1. restTemplate调用
    restTemplate.getForEntity("http://eureka-server", String.class);
    
    1. 在不断深入后,最终处理的是一个拦截器
    2. 拦截器进的实际处理类是LoadBalancerInterceptor
    3. 但里面实际的负载均衡调用loadBalancer又是RibbonLoadBalancerClient
    4. 这就真真的进了Ribbon的负载均衡调用了,至于这个RibbonLoadBalancerClient怎么注入进来的,这也简单,这里有两层关系,该LoadBalancerInterceptor如何实例化的,和RibbonLoadBalancerClient如何实例化并注入的,可以看如下图


    5. 好了,不扯开去了,继续解析服务名,实际上,接下来就是RibbonLoadBalancerClient的实现了
    6. 继续深入
    7. 轮询核心算法

    1.3. 模拟负载均衡调用

    1.3.1. 代码直接上

    @SpringBootApplication
    @EnableDiscoveryClient
    @RestController
    @Slf4j
    public class EurekaClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaClientApplication.class, args);
        }
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private DiscoveryClient discoveryClient;
    
        /**
         * 使用Ribbon的负载均衡
         * @return
         */
        @GetMapping("/")
        public ResponseEntity<String> getTime(){
            return restTemplate.getForEntity("http://eureka-server", String.class);
        }
    
        /**
         * 模拟轮询负载的调用
         * @return
         */
        @GetMapping("/discovery")
        public ResponseEntity<String> discovery(){
            List<ServiceInstance> instances = discoveryClient.getInstances("eureka-server");
            int i = incrementAndGetModule(instances.size());
            return restTemplate.getForEntity(((EurekaDiscoveryClient.EurekaServiceInstance) instances.get(i)).getInstanceInfo().getHomePageUrl(), String.class);
        }
    
        private AtomicInteger nextIndex = new AtomicInteger();
        private int incrementAndGetModule(int module) {
            for (; ; ) {
                int current = nextIndex.get();
                int next = (current + 1) % module;
                if (nextIndex.compareAndSet(current,next) && current < module) {
                    return current;
                }
            }
        }
    
        /**
         * 加上@LoadBalanced该注解使用的Ribbon的负载均衡算法
         */
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    
    
    1. 这里用了Ribbon的负载均衡轮询算法和直接调用discoveryClient实现最简单的模拟轮询算法
    2. 注意,测试discovery的时候可以需要把@LoadBalanced注掉
  • 相关阅读:
    XML入门
    BOM编程
    hdfs高可用
    Hadoop搭建问题及解决方案 --持续更新
    hadoop3完全分布式搭建
    hadoop环境搭建笔记
    hadoop3.x介绍
    基于JavaAPI对远程hdfs的操作
    13. Roman to Integer C++
    9. Palindrome Number(回文数)C++
  • 原文地址:https://www.cnblogs.com/sky-chen/p/10756721.html
Copyright © 2020-2023  润新知