知识模块
☕ Java 知识模块
八、Spring 全家桶
服务发现

服务发现

什么是服务发现?

在微服务架构中,服务实例动态变化(扩缩容、故障恢复),需要一种机制让服务相互发现。

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   服务 A      │     │   服务 B      │     │   服务 C      │
└──────┬───────┘     └──────┬───────┘     └──────┬───────┘
       │                    │                    │
       └────────────────────┼────────────────────┘

                   ┌────────▼────────┐
                   │   服务注册中心    │
                   │   (Nacos/Eureka) │
                   └─────────────────┘

Nacos 服务注册发现

依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置

spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: dev
        group: DEFAULT_GROUP

服务注册

@SpringBootApplication
@EnableDiscoveryClient  // 开启服务发现
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

服务发现

@Service
public class OrderService {
    
    @Autowired
    private DiscoveryClient discoveryClient;
    
    public void callUserService() {
        // 获取服务实例列表
        List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
        
        if (instances.isEmpty()) {
            throw new RuntimeException("无可用服务");
        }
        
        // 负载均衡选择一个实例
        ServiceInstance instance = instances.get(0);
        String url = instance.getUri() + "/user/1";
        
        // 调用服务
        User user = restTemplate.getForObject(url, User.class);
    }
}

负载均衡

Ribbon(已废弃,使用 Spring Cloud LoadBalancer)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

使用 RestTemplate + @LoadBalanced

@Configuration
public class RestConfig {
    
    @Bean
    @LoadBalanced  // 自动负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
 
@Service
public class OrderService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    public User getUser(Long id) {
        // 直接使用服务名,自动负载均衡
        return restTemplate.getForObject("http://user-service/user/" + id, User.class);
    }
}

使用 OpenFeign

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@FeignClient("user-service")
public interface UserClient {
    
    @GetMapping("/user/{id}")
    User getUser(@PathVariable("id") Long id);
}
 
// 使用
@Service
public class OrderService {
    
    @Autowired
    private UserClient userClient;
    
    public User getUser(Long id) {
        return userClient.getUser(id);
    }
}

负载均衡策略

策略说明
RoundRobinLoadBalancer轮询(默认)
RandomLoadBalancer随机

自定义负载均衡

@Configuration
public class LoadBalancerConfig {
    
    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

服务注册中心对比

特性NacosEurekaConsulZookeeper
CAPAP/CPAPCPCP
健康检查TCP/HTTP/MySQL心跳TCP/HTTP心跳
负载均衡RibbonRibbonFabio
配置中心支持不支持支持不支持
社区活跃度低(停更)

面试高频问题

Q1: 服务发现的流程?

  1. 服务启动时向注册中心注册
  2. 注册中心维护服务实例列表
  3. 消费者从注册中心获取实例列表
  4. 消费者通过负载均衡调用服务

Q2: Nacos 和 Eureka 的区别?

对比NacosEureka
模式AP/CP 可切换AP
配置中心支持不支持
健康检查多种方式心跳
状态活跃停止维护

Q3: 如何保证服务发现的高可用?

  1. 注册中心集群部署
  2. 本地缓存服务列表
  3. 健康检查及时剔除故障实例

总结

服务发现核心要点:
1. 服务注册:启动时向注册中心注册
2. 服务发现:从注册中心获取实例列表
3. 负载均衡:Ribbon 或 Spring Cloud LoadBalancer
4. 常用注册中心:Nacos(推荐)、Eureka、Consul