一、Nacos安装与基础配置

1.1 Nacos安装步骤

Nacos(Naming and Configuration Service)是阿里巴巴开源的一个动态服务发现、配置管理和服务管理平台。安装过程如下:

# 1. 下载Nacos Server
wget https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.tar.gz

# 2. 解压并启动
tar -zxvf nacos-server-2.0.3.tar.gz
cd nacos/bin

# 3. 启动(单机模式)
sh startup.sh -m standalone

1.2 Spring Cloud项目集成配置

在Spring Cloud项目中,通过简单配置即可接入Nacos:

# application.yml
spring:
  application:
    name: service-order  # 服务名称
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos服务地址
        namespace: public           # 命名空间
# application.yml
spring:
  application:
    name: service-product  # 服务名称
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos服务地址
        namespace: public           # 命名空间

二、Nacos服务注册与发现机制

2.1 服务注册原理

当微服务启动时,会自动向Nacos Server注册自身信息,包括:

  • 服务名称(spring.application.name)

  • IP地址和端口

  • 集群信息

  • 健康状态

2.2 服务发现实现方式

方式一:基于DiscoveryClient的原始方式
@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private DiscoveryClient discoveryClient;
    
    private Product getProductFromRemote(Long productId) {
        // 1. 获取所有商品服务实例
        List<ServiceInstance> instances = 
            discoveryClient.getInstances("service-product");
        
        // 2. 手动选择实例并拼接URL
        ServiceInstance instance = instances.get(0);
        String url = "http://" + instance.getHost() + ":" + 
                    instance.getPort() + "/product/" + productId;
        
        // 3. 发起远程调用
        return restTemplate.getForObject(url, Product.class);
    }
}
方式二:基于LoadBalancerClient的负载均衡
private Product getProductFromRemoteWithLoadBalancer(Long productId) {
    // 1. 负载均衡选择服务实例
    ServiceInstance choose = 
        loadBalancerClient.choose("service-product");
    
    // 2. 拼接URL
    String url = "http://" + choose.getHost() + ":" + 
                choose.getPort() + "/product/" + productId;
    
    return restTemplate.getForObject(url, Product.class);
}
方式三:基于@LoadBalanced注解的优雅实现(推荐)
@Configuration
public class OrderConfig {
    
    @LoadBalanced  // 关键注解,启用负载均衡
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
public class OrderServiceImpl {
    
    @Autowired
    private RestTemplate restTemplate;  // 已具备负载均衡能力
    
    private Product getProductFromRemoteWithAnnotation(Long productId) {
        // 直接使用服务名,RestTemplate会自动处理服务发现和负载均衡
        String url = "http://service-product/product/" + productId;
        return restTemplate.getForObject(url, Product.class);
    }
}

三、微服务远程调用实践

3.1 完整订单创建示例

@Override
public Order createOrder(Long productId, Long userId) {
    // 1. 通过服务发现获取商品信息
    Product product = getProductFromRemoteWithAnnotation(productId);
    
    // 2. 构建订单对象
    Order order = new Order();
    order.setId(System.currentTimeMillis());
    order.setUserId(userId);
    order.setUserName("张三");
    order.setAddress("北京");
    
    // 3. 计算订单总价
    BigDecimal total = product.getPrice()
        .multiply(new BigDecimal(product.getNum()));
    order.setTotal(total);
    
    // 4. 设置商品列表
    List<Product> productList = new ArrayList<>();
    productList.add(product);
    order.setProductList(productList);
    
    return order;
}

四、核心面试题解析:注册中心宕机,远程调用还能实现吗?

4.1 短期影响分析

可以,但有限制条件:

  1. 服务消费者本地缓存:

    • 微服务客户端会缓存从注册中心获取的服务实例列表

    • 缓存有效期内(默认30秒),仍可使用缓存的地址进行调用

  2. 心跳检测机制:

    • Nacos客户端与服务实例保持心跳连接

    • 即使Nacos Server宕机,现有TCP连接不会立即断开

4.2 技术实现原理

// Nacos客户端缓存机制伪代码
public class NacosDiscoveryClient {
    
    private Map<String, List<ServiceInstance>> serviceCache = new ConcurrentHashMap<>();
    private long lastUpdateTime = System.currentTimeMillis();
    
    public List<ServiceInstance> getInstances(String serviceId) {
        // 1. 首先检查本地缓存
        if (cacheIsValid() && cacheContains(serviceId)) {
            return getFromCache(serviceId);
        }
        
        // 2. 缓存过期或不存在,尝试从注册中心获取
        try {
            List<ServiceInstance> instances = fetchFromNacos(serviceId);
            updateCache(serviceId, instances);
            return instances;
        } catch (NacosException e) {
            // 3. 注册中心不可用,使用最后一次有效的缓存
            if (cacheContains(serviceId)) {
                log.warn("Nacos不可用,使用缓存数据");
                return getFromCache(serviceId);
            }
            throw new ServiceUnavailableException(serviceId);
        }
    }
}

4.3 长期影响与风险

时间段

影响程度

具体表现

0-30秒

几乎无影响

客户端使用本地缓存,调用正常

30秒-5分钟

部分影响

新服务无法注册,已有服务实例变更无法感知

5分钟以上

严重影响

健康检查失效,故障实例无法剔除,可能导致调用失败

通过本文的实践,我们不仅掌握了Nacos的基本使用,更重要的是理解了微服务架构中注册中心的核心作用及其容错机制。这种深入理解对于构建高可用的分布式系统至关重要。

更多推荐