Spring Cloud 服务注册与发现:Eureka 从原理到实战
在微服务架构中,服务注册与发现是最核心的基础能力,它彻底解决了硬编码 IP + 端口带来的维护噩梦。本文基于 Spring Cloud 实战课程,带你吃透 Eureka 的设计思想、CAP 理论、搭建流程与服务调用实践,零基础也能快速落地。
一、为什么需要注册中心?
1.1 上一章遗留的痛点
在之前的电商案例里,我们用 RestTemplate 实现服务调用时,地址是写死的:
java
String url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();
这种方式在生产环境完全不可用,会带来一系列问题:
-
服务迁移、扩容、下线必须手动改代码、重新部署
-
多服务互相调用时,配置满天飞,维护成本爆炸
-
无法实现负载均衡,无法自动剔除故障节点
-
运维人员苦不堪言,大量无效重复工作
1.2 生活中的解决方案:114 查号台
生活里我们不存机构电话,而是查 114:
-
机构把电话注册到 114
-
用户需要时查询获取最新号码
-
机构号码变更只需更新 114,不用通知所有人
微服务直接借鉴这套逻辑:注册中心 = 微服务的 114。
1.3 注册中心到底是什么?
注册中心是微服务架构的通讯录,负责:
-
维护服务名 → IP: 端口 的映射关系
-
自动感知服务上线、下线、故障
-
给调用方返回可用服务列表
三大角色:
-
服务提供者:提供接口,启动时把自己注册进去
-
服务消费者:调用接口,从注册中心拉取地址
-
注册中心:统一管理服务列表、健康检查
核心流程:
-
服务注册:提供者启动 → 上报信息到注册中心
-
心跳检测:提供者定期报活,证明自己还活着
-
服务发现:消费者先查注册中心 → 拿到可用地址 → 发起调用
1.4 必懂理论:CAP 定理
分布式系统三大指标:
-
C(一致性):所有节点同一时间数据完全一样
-
A(可用性):服务随时能响应,不宕机
-
P(分区容错性):网络断了仍能正常工作
结论 :三者不可兼得,分布式系统必须保留 P,只能二选一:
-
CP:优先一致(如 Zookeeper),网络故障可能拒绝响应
-
AP:优先可用(如 Eureka/Nacos 默认),允许短暂不一致,但绝不挂掉
电商、秒杀、高并发场景一律选 AP:能返回旧数据,也比直接报错强。
1.5 主流注册中心对比
| 注册中心 | CAP | 特点 | 状态 |
|---|---|---|---|
| Zookeeper | CP | 强一致,选主,可能短暂不可用 | 老牌,常用在 Dubbo |
| Eureka | AP | 高可用,节点平等,自我保护 | 2.0 停更,但存量大量使用 |
| Nacos | AP/CP 可切 | 服务发现 + 配置中心一体 | 阿里开源,现在主流 |
二、Eureka 核心介绍
Eureka 是 Netflix 开源的服务注册发现框架,Spring Cloud 早期默认方案。
两大组件
-
Eureka Server:注册中心服务端,管理服务列表
-
Eureka Client:嵌入业务服务,负责注册、心跳、发现
虽然 Eureka 2.0 已停止维护,但学习它依然极具价值:
-
理解注册中心通用模型
-
大量老项目仍在使用
-
为学习 Nacos 打下基础
三、动手搭建:Eureka Server 注册中心
Eureka Server 本身就是一个独立微服务。
3.1 创建模块
新建 Maven 模块:eureka\-server
JDK 17,继承父工程 spring\-cloud\-demo
3.2 引入依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.3 启动类加注解
java
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
3.4 配置文件(关键)
yaml
server:
port: 10010
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
client:
fetch-registry: false # 单点不需要抓取注册信息
register-with-eureka: false # 不自己注册自己
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.5 启动并访问控制台
启动后访问:
http://127.0.0.1:10010/
看到 Eureka 面板即成功。
四、服务注册:把商品服务注册进去
以 product\-service 为例。
4.1 引入 client 依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
4.2 添加配置
yaml
spring:
application:
name: product-service # 服务名(非常重要)
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10010/eureka
4.3 启动服务
刷新 Eureka 面板,能看到 PRODUCT\-SERVICE 已注册。
五、服务发现:订单服务调用商品服务
改造 order\-service,不再硬编码地址,从 Eureka 拉取。
5.1 同样引入 client 依赖
同上。
5.2 配置
yaml
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10010/eureka
5.3 使用 DiscoveryClient 实现动态调用
java
@Service
@Slf4j
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Resource
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
public OrderInfo selectOrderById(Integer orderId) {
// 1. 查询订单
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
// 2. 从 Eureka 获取服务列表
List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
ServiceInstance instance = instances.get(0);
// 3. 拼接真实地址
String url = instance.getUri() + "/product/" + orderInfo.getProductId();
// 4. 远程调用
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
orderInfo.setProductInfo(productInfo);
return orderInfo;
}
}
5.4 测试
启动 order\-service,访问:
http://127.0.0.1:8080/order/1
调用成功,且完全没有硬编码 IP。
六、Eureka vs Zookeeper
-
设计理念
-
Eureka:AP,高可用优先
-
Zookeeper:CP,强一致优先
-
-
集群模式
-
Eureka:节点对等,一个挂了其他顶上
-
Zookeeper:主从模式,Leader 挂掉需要选举,短暂不可用
-
-
适用场景
-
Eureka:Spring Cloud 微服务、高并发 Web 系统
-
Zookeeper:Dubbo、需要强一致性的场景
-
七、总结
这一章我们完成了微服务最关键的一步:从硬编码走向服务治理。
你学到了:
-
注册中心解决了什么问题
-
CAP 理论与 AP/CP 选择
-
Eureka 架构与搭建
-
服务注册 + 服务发现完整流程
-
基于 DiscoveryClient 实现动态调用
下一章我们将进入更现代化的组件 Nacos,它同时支持注册中心 + 配置中心,是目前企业微服务的标配方案。