5-2 服务注册与发现

3 阅读3分钟

5-2 服务注册与发现

概念解析

服务发现核心概念

概念说明
服务注册实例启动时向注册中心注册
服务注销实例关闭时从注册中心移除
心跳机制定期向注册中心发送心跳
服务剔除注册中心剔除不可用实例

注册中心对比

注册中心CAP一致性算法特点
EurekaAP-简单,停止维护
NacosCP + APRaft功能全面
ConsulCPRaft多数据中心
ZookeeperCPZab重量级

代码示例

1. Nacos 服务注册

pom.xml

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

application.yml

spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848
      username: nacos
      password: nacos
      discovery:
        namespace: dev
        group: DEFAULT_GROUP
        cluster-name: BJ-GROUP-1  # 集群
        metadata:
          version: v1
          instance: order-1

自动注册:添加依赖后自动注册到 Nacos

2. OpenFeign 服务调用

pom.xml

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

启动类

@SpringBootApplication
@EnableFeignClients  // 启用 Feign
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

定义 Feign Client

@FeignClient(name = "user-service", path = "/api/users")
public interface UserClient {

    @GetMapping("/{id}")
    Result<User> getUser(@PathVariable("id") Long id);

    @GetMapping
    Result<List<User>> list();
}

使用

@Service
public class OrderService {

    @Autowired
    private UserClient userClient;

    public OrderVO createOrder(Long userId) {
        // 调用用户服务
        User user = userClient.getUser(userId).getData();
        // 创建订单
        return buildOrder(user);
    }
}

3. 负载均衡配置

// 全局配置
@Configuration
public class FeignConfig {

    @Bean
    public Retryer.Retryer retryer() {
        // 重试配置:最多重试 3 次,每次间隔 100-500ms
        return new Retryer.Default(100, 500, 3);
    }
}

// 针对特定服务配置
@FeignClient(
    name = "user-service",
    configuration = UserFeignConfig.class
)
public interface UserClient { }

// 指定负载均衡策略
@Configuration
public class UserFeignConfig {
    @Bean
    public IRule roundRobinRule() {
        return new RoundRobinRule();  // 轮询
        // return new RandomRule();  // 随机
        // return new WeightedResponseTimeRule();  // 权重
        // return new NacosRule();  // Nacos 权重
    }
}

4. 服务降级

// 定义降级类
@Component
public class UserClientFallback implements UserClient {

    private static final Logger log = LoggerFactory.getLogger(
        UserClientFallback.class);

    @Override
    public Result<User> getUser(Long id) {
        log.warn("UserService 调用失败,返回降级结果");
        return Result.error("服务暂时不可用,请稍后重试");
    }

    @Override
    public Result<List<User>> list() {
        return Result.success(Collections.emptyList());
    }
}

// 使用降级
@FeignClient(
    name = "user-service",
    fallback = UserClientFallback.class  // 指定降级类
)
public interface UserClient { }

5. Nacos 集群配置

# application.yml
spring:
  cloud:
    nacos:
      server-addr: nacos-1:8848,nacos-2:8848,nacos-3:8848
      username: ${NACOS_USERNAME:nacos}
      password: ${NACOS_PASSWORD:nacos}

# nginx 代理
# upstream nacos-cluster {
#     server nacos-1:8848;
#     server nacos-2:8848;
#     server nacos-3:8848;
# }
# server {
#     listen 8848;
#     location / {
#         proxy_pass http://nacos-cluster;
#     }
# }

常见坑点

⚠️ 坑 1:服务注册不上

# ❌ 缺少 discovery 依赖
spring:
  cloud:
    nacos:
      discovery:
        enabled: true  # 确保开启

# ✅ 检查启动日志
# Located property source: [BootstrapPropertySource {name='bootstrap properties'}]
# Discovery Client started ...

⚠️ 坑 2:Feign 超时

# 配置超时
feign:
  client:
    config:
      default:
        connect-timeout: 5000
        read-timeout: 10000
      user-service:  # 特定服务配置
        connect-timeout: 3000
        read-timeout: 5000
  hystrix:
    enabled: true

⚠️ 坑 3:Ribbon vs LoadBalancer

// Spring Cloud 2020+ 使用 Spring Cloud LoadBalancer
@Configuration
public class LoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory factory) {

        String name = environment.getProperty(
            SpringCloudLoadBalancerClientFactory.LOADBALANCER_CONFIG_PROPERTY_NAME);

        return new RandomLoadBalancer(
            factory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name);
    }
}

面试题

Q1:Nacos 的 AP 和 CP 模式?

参考答案

Nacos 同时支持 CPAP 模式:

模式特点使用场景
AP可用性优先,分区容忍服务注册与发现
CP一致性优先配置管理
# 切换模式
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/mode?mode=CP'

# 或通过控制台切换

选择建议

  • 服务发现:使用 AP(保证可用性)
  • 配置管理:使用 CP(保证一致性)

Q2:Eureka 和 Nacos 的区别?

参考答案

维度EurekaNacos
CAPAPAP + CP 可切换
数据同步Peer-to-PeerRaft 协议
健康检查客户端心跳服务端主动探测
配置管理内置配置中心
运维成本
活跃度停止维护活跃

Q3:Feign 的工作原理?

参考答案

  1. 启动时:扫描 @FeignClient 注解
  2. 生成代理:为每个 FeignClient 生成代理对象
  3. 方法调用
    • 构建请求模板
    • 调用 LoadBalancer 选择实例
    • 发送 HTTP 请求
    • 解析响应
// 关键源码
public FeignClientFactoryBean implements FactoryBean<Object> {
    @Override
    public Object getObject() {
        return Feign.builder()
            .encoder(new SpringFormEncoder())
            .decoder(new ResponseEntityDecoder(
                new SpringDecoder(messageConverters)))
            .contract(new SpringMvcContract())
            .target(Target.class, url, fallbackFactory);
    }
}