18.9.5 服务注册发现机制原理
1. 服务注册发现基础概念
1.1 服务注册发现原理
public class ServiceDiscoveryPrinciple {
/*
* 服务注册发现核心概念:
*
* 1. 服务注册
* - 服务启动时向注册中心注册自己的信息
* - 包括服务名、IP地址、端口、健康检查等
*
* 2. 服务发现
* - 客户端从注册中心获取服务列表
* - 根据负载均衡策略选择服务实例
*
* 3. 健康检查
* - 定期检查服务实例的健康状态
* - 自动剔除不健康的实例
*
* 4. 服务下线
* - 服务关闭时主动注销
* - 或通过健康检查被动剔除
*
* 常见实现:
* - Eureka (Netflix)
* - Consul (HashiCorp)
* - Zookeeper
* - Nacos (Alibaba)
*/
public void demonstrateServiceDiscovery() {
System.out.println("=== 服务注册发现演示 ===");
ServiceRegistry registry = new ServiceRegistry();
demonstrateServiceRegistration(registry);
demonstrateServiceDiscovery(registry);
demonstrateHealthCheck(registry);
demonstrateServiceDeregistration(registry);
}
private void demonstrateServiceRegistration(ServiceRegistry registry) {
System.out.println("--- 服务注册演示 ---");
System.out.println("1. 用户服务启动并注册:");
ServiceInstance userService1 = new ServiceInstance("user-service", "192.168.1.10", 8080);
registry.register(userService1);
ServiceInstance userService2 = new ServiceInstance("user-service", "192.168.1.11", 8080);
registry.register(userService2);
System.out.println("\n2. 订单服务启动并注册:");
ServiceInstance orderService = new ServiceInstance("order-service", "192.168.1.20", 8081);
registry.register(orderService);
System.out.println("\n3. 查看注册表:");
registry.showRegistry();
System.out.println();
}
private void demonstrateServiceDiscovery(ServiceRegistry registry) {
System.out.println("--- 服务发现演示 ---");
ServiceDiscoveryClient client = new ServiceDiscoveryClient(registry);
System.out.println("1. 发现用户服务:");
java.util.List<ServiceInstance> userServices = client.discover("user-service");
for (ServiceInstance instance : userServices) {
System.out.println(" 发现实例: " + instance.getHost() + ":" + instance.getPort());
}
System.out.println("\n2. 负载均衡选择实例:");
ServiceInstance selectedInstance = client.selectInstance("user-service");
System.out.println(" 选择实例: " + selectedInstance.getHost() + ":" + selectedInstance.getPort());
System.out.println();
}
private void demonstrateHealthCheck(ServiceRegistry registry) {
System.out.println("--- 健康检查演示 ---");
System.out.println("1. 执行健康检查:");
registry.performHealthCheck();
System.out.println("\n2. 模拟服务故障:");
registry.simulateServiceFailure("192.168.1.11", 8080);
System.out.println("\n3. 再次健康检查:");
registry.performHealthCheck();
System.out.println("\n4. 查看更新后的注册表:");
registry.showRegistry();
System.out.println();
}
private void demonstrateServiceDeregistration(ServiceRegistry registry) {
System.out.println("--- 服务下线演示 ---");
System.out.println("1. 订单服务主动下线:");
ServiceInstance orderService = new ServiceInstance("order-service", "192.168.1.20", 8081);
registry.deregister(orderService);
System.out.println("\n2. 查看最终注册表:");
registry.showRegistry();
System.out.println();
}
}
// 服务实例
class ServiceInstance {
private String serviceName;
private String host;
private int port;
private boolean healthy;
private long lastHeartbeat;
private java.util.Map<String, String> metadata;
public ServiceInstance(String serviceName, String host, int port) {
this.serviceName = serviceName;
this.host = host;
this.port = port;
this.healthy = true;
this.lastHeartbeat = System.currentTimeMillis();
this.metadata = new java.util.HashMap<>();
}
public String getServiceName() { return serviceName; }
public String getHost() { return host; }
public int getPort() { return port; }
public boolean isHealthy() { return healthy; }
public void setHealthy(boolean healthy) { this.healthy = healthy; }
public long getLastHeartbeat() { return lastHeartbeat; }
public void setLastHeartbeat(long lastHeartbeat) { this.lastHeartbeat = lastHeartbeat; }
public java.util.Map<String, String> getMetadata() { return metadata; }
public String getInstanceId() {
return serviceName + "-" + host + "-" + port;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ServiceInstance that = (ServiceInstance) obj;
return port == that.port &&
serviceName.equals(that.serviceName) &&
host.equals(that.host);
}
@Override
public int hashCode() {
return java.util.Objects.hash(serviceName, host, port);
}
}
// 服务注册表
class ServiceRegistry {
private java.util.Map<String, java.util.List<ServiceInstance>> registry = new java.util.concurrent.ConcurrentHashMap<>();
private java.util.Set<String> failedInstances = new java.util.concurrent.ConcurrentHashMap<String, Boolean>().keySet(java.util.concurrent.ConcurrentHashMap.newKeySet());
public void register(ServiceInstance instance) {
String serviceName = instance.getServiceName();
registry.computeIfAbsent(serviceName, k -> new java.util.concurrent.CopyOnWriteArrayList<>())
.add(instance);
System.out.println(" 服务注册成功: " + instance.getInstanceId());
System.out.println(" 服务名: " + serviceName);
System.out.println(" 地址: " + instance.getHost() + ":" + instance.getPort());
}
public void deregister(ServiceInstance instance) {
String serviceName = instance.getServiceName();
java.util.List<ServiceInstance> instances = registry.get(serviceName);
if (instances != null) {
instances.remove(instance);
System.out.println(" 服务下线成功: " + instance.getInstanceId());
if (instances.isEmpty()) {
registry.remove(serviceName);
System.out.println(" 服务 " + serviceName + " 所有实例已下线");
}
}
}
public java.util.List<ServiceInstance> getInstances(String serviceName) {
return registry.getOrDefault(serviceName, new java.util.ArrayList<>());
}
public void performHealthCheck() {
System.out.println(" 开始健康检查...");
long currentTime = System.currentTimeMillis();
long healthCheckTimeout = 30000; // 30秒超时
for (java.util.Map.Entry<String, java.util.List<ServiceInstance>> entry : registry.entrySet()) {
String serviceName = entry.getKey();
java.util.List<ServiceInstance> instances = entry.getValue();
java.util.Iterator<ServiceInstance> iterator = instances.iterator();
while (iterator.hasNext()) {
ServiceInstance instance = iterator.next();
String instanceKey = instance.getHost() + ":" + instance.getPort();
if (failedInstances.contains(instanceKey)) {
System.out.println(" 剔除不健康实例: " + instance.getInstanceId());
iterator.remove();
} else if (currentTime - instance.getLastHeartbeat() > healthCheckTimeout) {
System.out.println(" 实例心跳超时: " + instance.getInstanceId());
instance.setHealthy(false);
iterator.remove();
} else {
System.out.println(" 实例健康: " + instance.getInstanceId());
}
}
}
}
public void simulateServiceFailure(String host, int port) {
String instanceKey = host + ":" + port;
failedInstances.add(instanceKey);
System.out.println(" 模拟实例故障: " + instanceKey);
}
public void showRegistry() {
System.out.println(" 当前服务注册表:");
if (registry.isEmpty()) {
System.out.println(" (空)");
} else {
for (java.util.Map.Entry<String, java.util.List<ServiceInstance>> entry : registry.entrySet()) {
String serviceName = entry.getKey();
java.util.List<ServiceInstance> instances = entry.getValue();
System.out.println(" " + serv
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经

