springcloud eureka服务注册与发现

什么是eureka

spring cloud eureka是spring cloud Netflix微服务中的一部分,主要负责完成微服务架构中的服务治理功能,而在springcloud中为eureka 增加了自动化配置,我们只需要简单的额引入依赖和注解就能使用.

什么是服务治理

服务治理包括三个部分,服务注册中心,服务提供者,服务消费者

服务注册中心: eureka提供的服务端,提供服务注册与发现的功能.

失效剔除:在服务实例非正产退出的时候,并不一定会发送服务下线请求,在这种情况下为了防止失效服务继续被调用,EUREKA SERVER 在启动的时候通过创建一 个定时任务(默认60s),将当前服务清单中没有续约(默认90s)的服务剔除出去,
自我保护:在服务注册到EUREKA 之后,服务实例会维护一个心跳链接,EUREKA通过统计15分钟内心跳失败的比例是否低于85%,若低于85%,会将这些实例保护起 来以防止过期,可以通过设置来关闭
eureka:
  erver:
     enable-self-preservation: false

服务提供者:  提供服务的应用,可以是springboot应用以及其他技术平台上遵循eureka 通信规范的应用,通过将自身的一些信息提供给eureka 服务注册中心,以供消费者用.

服务注册:在服务实例启动时通过发送REST请求将自己注册到EUREKA SERVER服务上,并且带上自身相应的元数据信息,EUREKA SERVER 收到请求后通过一 系列校验,一个双层map中,第一层key为服务名,第二层key为具体服务实例.通过设置启动时将不会注册到服务中心

eureka:
    client:
       register-with-eureka: false 

	     服务同步:在我们项目为了应付种种情况,往往会设置多个服务注册中心,所以在服务提供者发送注册信息到一个服务注册中心时,会将请求转发给集群中的
			其他服务注册中心
	     服务续约:在注册完成后,服务提供者会启动一个定时任务(默认30s)定时向服务注册中心续约,以防止服务时效被剔除.

服务下线:在系统运行期间遇到关闭或者重启服务的情况时,客户端会发送一个服务下线的REST请求给EUREKA SERVER,EUREKA SERVER 收到请求后将该服务状 态设置为下线(DOWN).并且广播该事件

服务消费者:  通过向服务注册中心获取可用的服务列表,,从而了解该求何处调用所需要的服务.
获取服务:在我们启动服务实例时,会启动一个定时任务(默认30)向服务注册中心发送一个REST请求从而获取可用的服务清单,通过设置在启动时不向服务注册中心 获取服务清单
eureka:
  client:
    fetch-registry: false
服务调用:在获取到服务清单以后,通过服务名获得具体的服务实例信息,从而根据需求进行调用,在RIBBON中默认采用轮询方式实现负载均衡,在调用时优先访问处 于同一个zone中的服务,在访问其他的ZONE

源码分析

我们在住一个SPRING BOOT 应用到EUREKA SERVER 时需要在启动类加上 @EnableDiscoveryClient注解 ,并且配置,若有多个服务注册中心,用,隔开
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7777/eureka/,http://localhost:7777/eureka/

通过查看EnableDiscoveryClient类注释信息Annotation to enable a DiscoveryClient implementation.

可以发现用来开启DiscoveryClient 实例,通过访问该类注释可以了解该类的用途

1.向EUREKA SERVER 注册实例

2.向EUREKA SERVER 续租

3. 向EUREKA SERVER 获取服务实例列表

4.向EUREKA SERVER 取消注册

通过查看该类方法,发现一个register()方法,该方法向Eureka Server发起注册请求,并且传入一个com.netflix.appinfo.InstanceInfo对象,该对象在

   DiscoveryClient初始化的时候赋值,包含了该服务提供给服务注册中心的一些元数据

/**
     * Register with the eureka service by making the appropriate REST call.
     */
    boolean register() throws Throwable {
        EurekaHttpResponse<Void> httpResponse;
        try {
            httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
        } catch (Exception e) {
            logger.warn("{} - registration failed {}", PREFIX + appPathIdentifier, e.getMessage(), e);
            throw e;
        }
        if (logger.isInfoEnabled()) {
            logger.info("{} - registration status: {}", PREFIX + appPathIdentifier, httpResponse.getStatusCode());
        }
        return httpResponse.getStatusCode() == 204;
    }
  并且该方法是由 initScheduledTasks()方法进行调用
/**
     * Initializes all scheduled tasks.
     */
    private void initScheduledTasks() {
        if (clientConfig.shouldFetchRegistry()) {
            // registry cache refresh timer
            int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
            int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "cacheRefresh",
                            scheduler,
                            cacheRefreshExecutor,
                            registryFetchIntervalSeconds,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new CacheRefreshThread()
                    ),
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }

        if (clientConfig.shouldRegisterWithEureka()) {
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs);

            // Heartbeat timer
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "heartbeat",
                            scheduler,
                            heartbeatExecutor,
                            renewalIntervalInSecs,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new HeartbeatThread()
                    ),
                    renewalIntervalInSecs, TimeUnit.SECONDS);

            // InstanceInfo replicator
            instanceInfoReplicator = new InstanceInfoReplicator(
                    this,
                    instanceInfo,
                    clientConfig.getInstanceInfoReplicationIntervalSeconds(),
                    2); // burstSize

            statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
                @Override
                public String getId() {
                    return "statusChangeListener";
                }

                @Override
                public void notify(StatusChangeEvent statusChangeEvent) {
                    if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                            InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
                        // log at warn level if DOWN was involved
                        logger.warn("Saw local status change event {}", statusChangeEvent);
                    } else {
                        logger.info("Saw local status change event {}", statusChangeEvent);
                    }
                    instanceInfoReplicator.onDemandUpdate();
                }
            };

            if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                applicationInfoManager.registerStatusChangeListener(statusChangeListener);
            }

            instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        } else {
            logger.info("Not registering with Eureka server per configuration");
        }
    }
通过查看该方法创建了两个定时任务,用来进行服务获取以及服务续约,通过eurekaclientconfig的配置信息来进行服务注册,续约,以及服务清单获取,以及定时任务的 时间等.

我们在配置一个服务的时候还配置了对应的serverurl信息等,我们通过在DiscoveryClient类搜索serviceurl关键字可以发现获取serviceurl的方法标识过期并且连接 到com.netflix.discovery.endpoint.EndpointUtils 类里面,在该类下面发现getServiceUrlsFromConfig()方法:

/**
     * Get the list of all eureka service urls from properties file for the eureka client to talk to.
     *
     * @param clientConfig the clientConfig to use
     * @param instanceZone The zone in which the client resides
     * @param preferSameZone true if we have to prefer the same zone as the client, false otherwise
     * @return The list of all eureka service urls for the eureka client to talk to
     */
    public static List<String> getServiceUrlsFromConfig(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone) {
        List<String> orderedUrls = new ArrayList<String>();
        String region = getRegion(clientConfig);
        String[] availZones = clientConfig.getAvailabilityZones(clientConfig.getRegion());
        if (availZones == null || availZones.length == 0) {
            availZones = new String[1];
            availZones[0] = DEFAULT_ZONE;
        }
        logger.debug("The availability zone for the given region {} are {}", region, Arrays.toString(availZones));
        int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);

        List<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(availZones[myZoneOffset]);
        if (serviceUrls != null) {
            orderedUrls.addAll(serviceUrls);
        }
        int currentOffset = myZoneOffset == (availZones.length - 1) ? 0 : (myZoneOffset + 1);
        while (currentOffset != myZoneOffset) {
            serviceUrls = clientConfig.getEurekaServerServiceUrls(availZones[currentOffset]);
            if (serviceUrls != null) {
                orderedUrls.addAll(serviceUrls);
            }
            if (currentOffset == (availZones.length - 1)) {
                currentOffset = 0;
            } else {
                currentOffset++;
            }
        }

        if (orderedUrls.size() < 1) {
            throw new IllegalArgumentException("DiscoveryClient: invalid serviceUrl specified!");
        }
        return orderedUrls;
    }
该方法一次加载了Region和Zone,并且只返回了一个Region和多个Zone,若配置文件中没有配置的话,默认使用default和defaultZone,所以一个微服务应用只能属于一个 Region,并且可以配置多个Zone,在获取到region和zone后开始加载对应的Eureka Server的具体地址,并且通过地址向对应的注册中心注册,续约获取服务等.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值