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圣经

全部评论

相关推荐

2025-12-27 22:46
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务