Eureka-server源码解读

学习springcloud相关组件前,必须先清楚springboot的原理:Application启动/自动配置/依赖注入等等

springboot原理讲解

  • server是如何启动的
    使用@EnableEurekaServer之后,EurekaServerMarkerConfiguration被引入,自动配置EurekaServerAutoConfiguration开始执行。
  • eureka-server提供的api
/**
 * List of packages containing Jersey resources required by the Eureka server
 */
private static String[] EUREKA_PACKAGES = new String[] { "com.netflix.discovery","com.netflix.eureka" };

/**
 * Construct a Jersey {@link javax.ws.rs.core.Application} with all the resources
 * required by the Eureka server.
 */
@Bean
public javax.ws.rs.core.Application jerseyApplication(Environment environment,
		ResourceLoader resourceLoader) {

	ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
			false, environment);

	// Filter to include only classes that have a particular annotation.
	//
	provider.addIncludeFilter(new AnnotationTypeFilter(Path.class));
	provider.addIncludeFilter(new AnnotationTypeFilter(Provider.class));

	// Find classes in Eureka packages (or subpackages)
	//
	Set<Class<?>> classes = new HashSet<Class<?>>();
	for (String basePackage : EUREKA_PACKAGES) {
		Set<BeanDefinition> beans = provider.findCandidateComponents(basePackage);
		for (BeanDefinition bd : beans) {
			Class<?> cls = ClassUtils.resolveClassName(bd.getBeanClassName(),
					resourceLoader.getClassLoader());
			classes.add(cls);
		}
	}

	// Construct the Jersey ResourceConfig
	//
	Map<String, Object> propsAndFeatures = new HashMap<String, Object>();
	propsAndFeatures.put(
			// Skip static content used by the webapp
			ServletContainer.PROPERTY_WEB_PAGE_CONTENT_REGEX,
			EurekaConstants.DEFAULT_PREFIX + "/(fonts|images|css|js)/.*");

	DefaultResourceConfig rc = new DefaultResourceConfig(classes);
	rc.setPropertiesAndFeatures(propsAndFeatures);

	return rc;
}

如上源码,加载了两个包路径下的Resource到javax.ws.rs.core.Application

  • 如何监测心跳剔除服务
public class EurekaBootStrap implements ServletContextListener
initEurekaServerContext();
EurekaServerContext serverContext = new DefaultEurekaServerContext(
                eurekaServerConfig,
                serverCodecs,
                registry,
                peerEurekaNodes,
                applicationInfoManager
        );
initialize();
registry.init(peerEurekaNodes);
scheduleRenewalThresholdUpdateTask();
updateRenewalThreshold();

剔除逻辑整理

public void evict(long additionalLeaseMs) {
    logger.debug("Running the evict task");

    if (!isLeaseExpirationEnabled()) {
        logger.debug("DS: lease expiration is currently disabled.");
        return;
    }

	// 我们首先收集所有过期的物品,以随机的顺序驱逐它们。对于大型的驱逐集,如果我们不这么做,
	// 我们可能会在自我保护开始之前将整个应用程序都清除掉。通过随机化,影响应该均匀地分布在所有应用程序中
    // We collect first all expired items, to evict them in random order. For large eviction sets,
    // if we do not that, we might wipe out whole apps before self preservation kicks in. By randomizing it,
    // the impact should be evenly distributed across all applications.
    List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>();
    for (Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) {
        Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue();
        if (leaseMap != null) {
            for (Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) {
                Lease<InstanceInfo> lease = leaseEntry.getValue();
                if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) {
                    expiredLeases.add(lease);
                }
            }
        }
    }

	// 为了补偿GC暂停或漂移的本地时间,我们需要使用当前注册表大小作为触发自我保护的基础。没有这个,我们就会把所有的注册表都抹掉。
    // To compensate for GC pauses or drifting local time, we need to use current registry size as a base for
    // triggering self-preservation. Without that we would wipe out full registry.
    int registrySize = (int) getLocalRegistrySize();
    int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold());
    int evictionLimit = registrySize - registrySizeThreshold;

    int toEvict = Math.min(expiredLeases.size(), evictionLimit);
    if (toEvict > 0) {
        logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit);

        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < toEvict; i++) {
	        // 选择一个随机项(Knuth shuffle算法)
            // Pick a random item (Knuth shuffle algorithm)
            int next = i + random.nextInt(expiredLeases.size() - i);
            Collections.swap(expiredLeases, i, next);
            Lease<InstanceInfo> lease = expiredLeases.get(i);

            String appName = lease.getHolder().getAppName();
            String id = lease.getHolder().getId();
            EXPIRED.increment();
            logger.warn("DS: Registry: expired lease for {}/{}", appName, id);
            internalCancel(appName, id, false);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值