Skip to content

服务注册与发现 ​

深入理解SpringCloud服务注册与发现的实现机制,掌握Eureka、Nacos等注册中心的工作原理,理解服务实例管理、服务发现机制、心跳续约等核心功能。

📋 服务注册发现概览 ​

服务注册与发现是微服务架构的基础,SpringCloud提供了多种注册中心的集成。

🎯 一、Eureka实现 ​

1.1 Eureka Server ​

Eureka Server是服务注册中心,负责管理服务实例。

EurekaServerAutoConfiguration:

java
@Configuration
@EnableEurekaServer
public class EurekaServerAutoConfiguration {
    
    @Bean
    public EurekaServerContext eurekaServerContext() {
        return new DefaultEurekaServerContext();
    }
}

1.2 服务注册 ​

服务注册流程:

InstanceRegistry.register:

java
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
    read.lock();
    try {
        Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
        if (gMap == null) {
            final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = 
                    new ConcurrentHashMap<String, Lease<InstanceInfo>>();
            gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
            if (gMap == null) {
                gMap = gNewMap;
            }
        }
        Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
        if (existingLease != null && (existingLease.getHolder() != null)) {
            Long existingLastDirtyTimestamp = existingLease.getHolder()
                    .getLastDirtyTimestamp();
            Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
            if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp) {
                registrant = existingLease.getHolder();
            }
        } else {
            synchronized (lock) {
                if (this.expectedNumberOfClientsSendingRenews > 0) {
                    this.expectedNumberOfClientsSendingRenews++;
                    updateRenewsPerMinThreshold();
                }
            }
        }
        Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration);
        if (existingLease != null) {
            lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
        }
        gMap.put(registrant.getId(), lease);
        recentlyChangedQueue.add(new RecentlyChangedItem(lease));
        registrant.setLastUpdatedTimestamp();
        invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), 
                registrant.getSecureVipAddress());
    } finally {
        read.unlock();
    }
}

1.3 服务发现 ​

服务发现流程:

ApplicationResource.getApplication:

java
@GET
public Response getApplication(@PathParam("version") String version,
        @HeaderParam("Accept") final String acceptHeader,
        @HeaderParam("Accept-Encoding") final String acceptEncoding) {
    Applications applications = serverContext.getRegistry()
            .getApplications();
    if (applications == null) {
        return Response.status(Status.NOT_FOUND).build();
    }
    return Response.ok(applications).build();
}

1.4 心跳续约 ​

心跳续约机制:

java
public boolean renew(String appName, String id, boolean isReplication) {
    Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
    Lease<InstanceInfo> leaseToRenew = null;
    if (gMap != null) {
        leaseToRenew = gMap.get(id);
    }
    if (leaseToRenew == null) {
        return false;
    } else {
        InstanceInfo instanceInfo = leaseToRenew.getHolder();
        if (instanceInfo != null) {
            InstanceStatus overriddenInstanceStatus = this.getOverriddenInstanceStatus(
                    instanceInfo, leaseToRenew, isReplication);
            if (overriddenInstanceStatus == InstanceStatus.UNKNOWN) {
                instanceInfo.setStatusWithoutDirty(InstanceStatus.UP);
            }
            instanceInfo.setLastDirtyTimestamp();
        }
        leaseToRenew.renew();
        return true;
    }
}

🎯 二、Nacos集成 ​

2.1 Nacos服务注册 ​

NacosServiceRegistry.register:

java
@Override
public void register(Registration registration) {
    String serviceId = registration.getServiceId();
    String group = getGroup(registration);
    Instance instance = getNacosInstanceFromRegistration(registration);
    try {
        namingService.registerInstance(serviceId, group, instance);
    } catch (Exception e) {
        throw new RuntimeException("Failed to register service to nacos", e);
    }
}

2.2 Nacos服务发现 ​

NacosServiceDiscovery.getInstances:

java
@Override
public List<ServiceInstance> getInstances(String serviceId) {
    String group = discoveryProperties.getGroup();
    List<Instance> instances = namingService.getAllInstances(serviceId, group);
    return hostToServiceInstanceList(instances, serviceId);
}

🎯 三、服务实例管理 ​

3.1 实例状态 ​

服务实例的状态包括:

  • UP:服务正常
  • DOWN:服务下线
  • OUT_OF_SERVICE:服务不可用
  • UNKNOWN:状态未知

3.2 实例下线 ​

服务下线流程:

java
public boolean cancel(String appName, String id, boolean isReplication) {
    Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
    Lease<InstanceInfo> leaseToCancel = null;
    if (gMap != null) {
        leaseToCancel = gMap.remove(id);
    }
    if (leaseToCancel == null) {
        return false;
    } else {
        leaseToCancel.cancel();
        InstanceInfo instanceInfo = leaseToCancel.getHolder();
        if (instanceInfo != null) {
            instanceInfo.setActionType(ActionType.DELETED);
            recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
            instanceInfo.setLastUpdatedTimestamp();
        }
        invalidateCache(appName, instanceInfo.getVIPAddress(), 
                instanceInfo.getSecureVipAddress());
        return true;
    }
}

📖 学习资源 ​

视频教程 ​

书籍推荐 ​

  • 《Spring Cloud微服务实战》 - 翟永超
  • 《深入理解Spring Cloud与微服务构建》 - 方志朋

网站资源 ​

✅ 学习检查清单 ​

  • [ ] 已理解Eureka服务注册机制
  • [ ] 已理解Eureka服务发现机制
  • [ ] 已理解心跳续约机制
  • [ ] 已理解Nacos集成方式
  • [ ] 已理解服务实例管理
  • [ ] 已绘制服务注册发现流程图
  • [ ] 已总结核心知识点

上一章节:SpringCloud源码深度解析概览
下一章节:配置中心
返回目录:源码阅读