服务注册与发现
深入理解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源码深度解析概览
下一章节:配置中心
返回目录:源码阅读