1. 服务注册与发现概述:什么是服务注册与发现、为什么需要它、核心概念

大家好,我是你们的老朋友。今天咱们正式开始聊服务注册与发现。说实话,这个主题我讲了不下几十次,但每次讲都有新感悟。你想想看,微服务架构里最头疼的问题是什么?服务之间怎么找到对方?怎么知道对方还活着?这就是注册与发现要解决的事。

1.1 什么是服务注册与发现

简单说,服务注册与发现就是一套「自动寻址」机制。传统单体应用里,A服务调用B服务,直接写死IP和端口就行。但在微服务架构下,服务实例会动态扩缩容、会迁移、会重启。你总不能每次部署都去改配置文件吧?

我习惯这么理解:注册中心就像一个「电话本」。服务提供者启动时,把自己的地址(IP+端口)登记上去。服务消费者需要调用时,去电话本里查一下,拿到地址再发起调用。就这么简单。

核心流程:
  • 服务提供者启动 → 向注册中心注册自己的元数据
  • 服务消费者启动 → 从注册中心订阅需要的服务列表
  • 服务提供者下线 → 注册中心主动剔除该实例
  • 服务消费者本地缓存 → 即使注册中心挂了,也能继续工作

1.2 为什么需要它

你可能要问:没有注册与发现,难道就不能做微服务了吗?嗯,理论上可以,但你会遇到一堆麻烦。

第一个痛点:硬编码地址

我在项目中遇到过这样的场景:某团队把所有服务地址写在配置文件里,每次上线都要手动改几十个文件。有一次改漏了一个,线上排查了整整三个小时。说白了,人力维护地址列表,在几十个服务规模下就是灾难。

第二个痛点:动态扩缩容

微服务的一大优势是弹性伸缩。流量高峰来了,自动扩容10个实例;流量低谷,缩容到2个。如果没有注册中心,新实例上线了,消费者怎么知道?老实例下线了,消费者还在往它发请求怎么办?

第三个痛点:健康检查

服务实例可能因为各种原因挂掉:内存溢出、网络分区、磁盘满。注册中心会定期做健康检查,把不健康的实例自动摘除。我曾经见过一个案例,某个服务挂了半小时,因为没有健康检查机制,上游服务一直往死节点发请求,导致整个调用链雪崩。

我的建议: 只要你的服务数量超过5个,或者有动态扩缩容需求,就应该引入注册中心。别等到出问题了再补,那时候代价就大了。

1.3 核心概念

咱们把三个核心角色拆开讲清楚。

1.3.1 注册中心

注册中心是整个机制的「大脑」。它维护着所有服务的地址列表,并提供查询和订阅能力。常见的注册中心有:

注册中心 特点 适用场景
Eureka AP原则,去中心化 中小规模,对一致性要求不高
Consul CP原则,支持多数据中心 需要强一致性,跨机房部署
Nacos 支持AP/CP切换 阿里系生态,功能丰富
Zookeeper CP原则,强一致性 对一致性要求极高,但性能有瓶颈

我个人习惯用Nacos,因为它既支持AP也支持CP,可以根据业务场景灵活切换。不过选型没有银弹,关键看你的业务对一致性和可用性的权衡。

1.3.2 服务提供者

服务提供者就是「提供服务」的一方。它启动时需要做三件事:

  • 向注册中心注册自己的服务名、IP、端口、健康检查接口
  • 定期发送心跳,告诉注册中心「我还活着」
  • 优雅关闭时,主动通知注册中心下线

这里有个坑:我曾经遇到过服务提供者注册时,把内网IP注册上去了,但消费者在外网访问不到。所以注册时要特别注意网络可达性,最好用服务所在网卡的IP,而不是localhost。

1.3.3 服务消费者

服务消费者是「调用服务」的一方。它的工作流程是:

  1. 启动时从注册中心拉取服务列表,并缓存到本地
  2. 订阅服务变更事件,注册中心推送更新时刷新本地缓存
  3. 调用时,从本地缓存中选取一个实例(负载均衡策略)
  4. 如果调用失败,尝试重试其他实例
注意: 消费者本地缓存非常重要。即使注册中心宕机,消费者也能基于缓存继续工作一段时间。但缓存时间不宜过长,我一般设置30秒刷新一次,既保证实时性,又避免频繁拉取造成压力。

1.4 一个简单的注册与发现示例

光说不练假把式。咱们用Spring Cloud + Nacos演示一下核心流程。代码很简单,但背后的原理值得深思。

// 服务提供者:注册到Nacos
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

// 服务消费者:从Nacos发现服务
@RestController
public class ConsumerController {
    @Autowired
    private DiscoveryClient discoveryClient;
    
    @GetMapping("/call")
    public String callService() {
        // 从注册中心获取服务实例
        List<ServiceInstance> instances = 
            discoveryClient.getInstances("my-service");
        // 选取第一个实例(实际应该用负载均衡)
        ServiceInstance instance = instances.get(0);
        String url = "http://" + instance.getHost() 
                   + ":" + instance.getPort() + "/api";
        // 发起调用...
        return restTemplate.getForObject(url, String.class);
    }
}

你看,代码里没有写死任何IP地址。服务提供者启动后自动注册,消费者通过服务名就能找到它。这就是注册与发现的价值所在。

1.5 小结

这一章咱们把服务注册与发现的「是什么、为什么、核心概念」讲清楚了。说白了,它就是微服务架构的「通讯录」,让服务之间能自动找到对方,不用人工维护地址列表。

下一章我会深入讲注册中心的工作原理,包括心跳机制、健康检查、服务剔除策略。这些都是我在生产环境踩过坑后总结出来的经验,保证实用。

课后思考: 如果注册中心完全宕机了,你的服务还能正常工作吗?如果不能,该怎么设计容错机制?带着这个问题,咱们下章见。