Wang's Blog头像
关注
Java框架 SpringCloud 快速入门: Eureka 注册中心的搭建封面图

Java框架 SpringCloud 快速入门: Eureka 注册中心的搭建

概述

微服务拆分之后,订单服务调用用户服务不能再写死 http://localhost:8081,因为用户服务会扩容成多个实例,IP 和端口随时在变。这一篇就把解决这个问题的 Eureka 注册中心跑起来:一个独立的微服务,三步配置,启动后打开控制台能看到实例列表。

纲要

  • 角色划分
    • Eureka Server:注册中心,保存「服务名 → 实例地址列表」的映射
    • Eureka Client:服务提供者与消费者,注册信息、拉取列表都走这一端
  • 核心流程
    • 服务注册:provider 启动时上报自己的服务名、IP、端口
    • 服务保存:Server 保管地址列表,靠心跳(默认 30s)判断实例存活
    • 服务发现:consumer 按服务名拉取实例列表
    • 远程调用:负载均衡挑一个实例发请求
  • 动手搭建(五步)
    • 建 eureka-server 子模块
    • 引 spring-cloud-starter-netflix-eureka-server 依赖
    • 启动类加 @EnableEurekaServer
    • application.yml 配端口、服务名、defaultZone
    • 启动并访问 http://127.0.0.1:10086 验证控制台
  • 关键坑:defaultZone 少写 /eureka、漏掉 @EnableEurekaServer、spring.application.name 不写导致控制台显示 UNKNOWN、端口冲突
  • 延伸:集群为什么要互相注册;Eureka 2.x 停维护与 Nacos 替代

Eureka 的两个角色

注册中心解决的问题只有一个:让调用方通过服务名找到可用实例的真实地址。围绕这件事,Eureka 把参与方分成两类。

角色对应依赖职责典型代表
Eureka Serverspring-cloud-starter-netflix-eureka-server接收注册、保存地址列表、心跳检测、对外提供查询eureka-server 模块
Eureka Clientspring-cloud-starter-netflix-eureka-client上报自身信息(注册)、拉取他人信息(发现)user-service、order-service

这里有个容易被忽略的点:注册和发现被封装在同一个 client 依赖里。一个微服务既可能是提供者,也可能是消费者,所以 Eureka 没有拆成两套 API,引入 eureka-client 就同时具备两种能力。也就是说,user-service 用这个依赖,order-service 也用这个依赖,配置写法几乎一样。

整体链路如下。

服务消费者 order-service

注册中心 eureka-server :10086

服务提供者 user-service

服务注册

心跳续约

服务发现/拉取列表

调用真实地址

启动时注册
服务名 + IP + 端口

每 30s 发送心跳

保存映射关系
userservice -> [8081, 8082]

剔除心跳超时实例

按服务名拉取实例列表

负载均衡选一个实例

一次完整调用在时间轴上是这样铺开的。

order-service eureka-server(10086) user-service(8081) order-service eureka-server(10086) user-service(8081) POST 注册请求(userservice, 192.168.x.x:8081) 写入地址列表 每 30s 心跳(续约) GET /eureka/apps 拉取 userservice 实例 返回 [8081, 8082] 负载均衡挑一个 HTTP GET http://192.168.x.x:8081/user/1

搭建前的工程结构

注册中心必须是一个独立的微服务,不能塞进 user-service 里。原因很直接:注册中心自己要是挂掉重启,不应该牵连任何一个业务服务;反过来业务服务重启,也不该影响注册中心的地址列表。所以它单独建模块,单独占端口。

沿用前面的 cloud-demo 父工程,最终结构如下。

cloud-demo
├── pom.xml                      # 父工程,统一管理 SpringCloud / SpringBoot 版本
├── eureka-server                # 注册中心(本篇主角)
│   ├── pom.xml
│   └── src/main
│       ├── java/cn/itcast/eureka/EurekaApplication.java
│       └── resources/application.yml
├── user-service                 # 服务提供者,后续注册进来
│   ├── pom.xml
│   └── src/main
│       ├── java/cn/itcast/user/UserApplication.java
│       └── resources/application.yml
└── order-service                # 服务消费者,后续来拉取列表
    ├── pom.xml
    └── src/main
        ├── java/cn/itcast/order/OrderApplication.java
        └── resources/application.yml

父工程先把 eureka-server 登记进 <modules>,否则建了模块也不会参与构建。

<modules>
    <module>user-service</module>
    <module>order-service</module>
    <module>eureka-server</module>
</modules>

引依赖:为什么不用写版本号

在 eureka-server 的 pom.xml 里加上服务端 starter。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- eureka 服务端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>

注意这里没有 version。不是漏写,是踩在有版本管理的前提下才成立:父工程 cloud-demo 里用 dependencyManagement 导入了 spring-cloud-dependencies 这个 BOM,所有 SpringCloud 组件的版本已经在 BOM 里定义好了。

<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

父工程 spring-boot-starter-parent 的版本是 2.3.9.RELEASE,对应 SpringCloud Hoxton.SR10,Eureka 的 1.9.x 就在里面。写版本号不是不可以,只是后面升级 BOM 时会漏改,反而容易出「某个模块版本对不上」的诡异问题。

artifactId 后缀是 -server,说明这是服务端依赖。换成 -client 就是客户端依赖,这是选依赖时最容易看错的地方,两个名字只差一个词。

starter 的含义是:依赖里已经带好了 Eureka Server 的自动装配,理论上可以零配置启动。但自动装配需要一个开关,开关就是下一步的注解。

启动类:@EnableEurekaServer 是那个开关

package cn.itcast.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

注解拆开看:

注解作用漏写会怎样
@SpringBootApplication开启 SpringBoot 自动配置、组件扫描应用根本起不来
@EnableEurekaServer开启注册中心功能,导入 Eureka Server 的自动配置类服务能启动,但 /eureka/** 全部 404,控制台打不开

两个注解顺序无所谓,但 @EnableEurekaServer 一定不能少。它做的事情是把 EurekaServerAutoConfiguration 拉进容器,注册中心的一整套 REST 接口(注册、续约、下线、查询)都是这么装上去的。

写完之后 IDE 里应该有一个 Eureka 的启动项。启动类的包名是 cn.itcast.eureka,注意别被组件扫描的范围挡住——它自己就在根包下,扫描没问题。

application.yml:三块配置各管什么

src/main/resources/application.yml:

server:
  port: 10086 # 服务端口
spring:
  application:
    name: eurekaserver # eureka 的服务名称
eureka:
  client:
    service-url: # eureka 的地址信息
      defaultZone: http://127.0.0.1:10086/eureka

三段配置,各自解决一个问题。

server.port = 10086

注册中心对外端口
控制台与注册接口都在这个端口

spring.application.name = eurekaserver

微服务名称
注册进地址列表时用作 key

eureka.client.service-url.defaultZone
= http://127.0.0.1:10086/eureka

告诉客户端
注册中心在哪里

端口用 10086 是课程惯例,换别的也行,但要和下面的 defaultZone 一致,改一个必须改另一个。

服务名是 eurekaserver。这里最容易犯的错是干脆不写,Eureka 控制台 那一栏就会显示成 UNKNOWN。因为服务端启动时也会把自己当成一个微服务注册进去,没有名字就只能叫 UNKNOWN。

defaultZone 是注册中心的地址。既然自己就是注册中心,为什么还要配自己的地址?因为Eureka Server 自己也是一个微服务,启动时会把自己也注册到自己身上。这一步在单机环境下看起来多余,但它是为集群准备的:两台/三台 Eureka 互相把对方写进 defaultZone,就能彼此交换地址列表,数据才通。多节点写法就是把地址用逗号隔开。

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:10086/eureka,http://eureka2:10087/eureka

本篇是单节点,写自己就够了。到这里「服务名 + 地址」其实就是在做服务注册,这两项是注册动作的必要参数。

defaultZone 为什么必须带 /eureka 后缀

这是整个搭建过程里最经典的坑。地址写成 http://127.0.0.1:10086,启动时不会立刻报错,而是在注册阶段抛异常,或者实例状态一直是 DOWN。

原因是 Eureka Server 的 REST 接口挂在 /eureka 这个上下文路径下,注册用的是 /eureka/apps/{appName},查询用的是 /eureka/apps。defaultZone 指的是注册接口的基准地址,不是首页地址。少了后缀就等于请求打到了 http://127.0.0.1:10086/apps/...,自然 404。

正确:http://127.0.0.1:10086/eureka
错误:http://127.0.0.1:10086
错误:http://127.0.0.1:10086/eureka/     ← 尾部多余斜杠,某些版本会拼出 //eureka/apps,也出问题

顺带记住:浏览器里访问控制台用的是 http://127.0.0.1:10086,不带 /eureka;配置文件里写的是 http://127.0.0.1:10086/eureka,带。两者的区别就在这,别混着抄。

register-with-eureka 与 fetch-registry

两个开关经常和 defaultZone 一起出现,但课程里默认没配,先看它们默认值是什么。

配置项默认值含义单节点下建议
eureka.client.register-with-eurekatrue是否把自己注册到注册中心可设 false
eureka.client.fetch-registrytrue是否拉取服务列表并缓存到本地可设 false

默认都是 true,所以课程里不配,Eureka 也会注册自己——这正是控制台「Instances currently registered with Eureka」里有 eurekaserver 一行的原因。

单节点部署时把它们关掉是常见做法:注册中心不需要发现别人,也不需要被自己发现,关掉能少一次无意义的注册请求和一份本地缓存。代价是控制台那一栏会空着,看不出「服务是否正常上报」,调试阶段反而不如留着。

eureka:
  client:
    register-with-eureka: false # 单节点不需要注册自己
    fetch-registry: false       # 单节点不需要拉取服务列表
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

结论:集群下必须保持默认 true(节点之间靠注册和拉取同步数据),单节点下关不关都行。遇到「控制台列表为空」先回头确认这两个开关,别急着怀疑网络。

启动与验证

找到 EurekaApplication 的 main 方法直接运行。IDEA 的 Services 面板会多出一个 EurekaApplication 启动项,启动日志里搜 Started EurekaApplication,端口是 10086。

浏览器访问 http://127.0.0.1:10086(IDEA 里直接点日志中的端口也能跳过去),看到的就是 Eureka 自带的管理页面。

+--------------------------------------------------------------------------------+
|  Eureka                                                          [Last updated] |
+--------------------------------------------------------------------------------+
|  System Status                                                                 |
|    Environment .................... test                                       |
|    Current time ................... Wed Sep 30 21:03:41 CST 2026               |
|    Uptime ......................... 0000 00:02:15                              |
|    Memory ......................... 301M (max 402M, total 402M)                |
|    Available processors ........... 8 (of 8)                                   |
+--------------------------------------------------------------------------------+
|  DS Replicas                                                                   |
|    eurekaserver                                                                |
|    <hr/>                                                                       |
|    Instances currently registered with Eureka                                  |
|      Application     AMIs    Availability Zones    Status                      |
|      EUREKASERVER    n/a     (1)                    UP (1) - Wang:10086        |
+--------------------------------------------------------------------------------+
|  General Info                                                                  |
|    total-avail-memory ............ 402mb                                       |
|    num-of-cpus ................... 8                                           |
+--------------------------------------------------------------------------------+

三段内容各看什么:

  • System Status:环境、启动时间、JVM 内存。用来确认应用真的起来了,不是缓存页面。
  • DS Replicas:对等的注册中心节点。单机只有一个 eurekaserver。
  • Instances currently registered with Eureka:最关键的一段,注册进来的实例列表。Application 列是服务名,后面跟着状态和地址,将来 userservice、orderservice 都会出现在这里。

最后一段里的 UP 表示实例健康,DOWN 表示不可用。地址列在 Windows 上显示的往往是计算机名(本例是机器名 Wang)而不是 IP,这是本机解析行为,不影响使用;换成 IP 部署或调 eureka.instance.prefer-ip-address 后就会显示真实 IP。

常见启动报错排查

现象原因改法
访问首页 404,日志无异常启动类漏了 @EnableEurekaServer补上注解(import 是 org.springframework.cloud.netflix.eureka.server.EnableEurekaServer)
启动后报 com.netflix.discovery.shared.transport.TransportException / Cannot execute request on any known serverdefaultZone 少写 /eureka,注册请求打到了 404 地址地址补成 http://127.0.0.1:10086/eureka
控制台实例名显示 UNKNOWNspring.application.name 没配或写错层级补 spring.application.name: eurekaserver
端口被占用 Port 10086 was already in use上一次进程没退干净,或端口被别的程序占lsof -i:10086(Windows 用 netstat -ano | findstr 10086)杀掉进程,或换端口并同步改 defaultZone
实例状态长时间是 DOWN注册中心和实例地址不通,或 hostname 解析异常检查 defaultZone、hosts 文件,必要时配 eureka.instance.prefer-ip-address: true
依赖拉不下来 / 类找不到spring-cloud.version 与 SpringBoot 版本不匹配参照官方版本对照表,2.3.x 对应 Hoxton.SR10

关于 Eureka 的现状

Eureka 2.x 已经停止维护,Netflix 也不再继续开源版本的演进。课程里用它是因为概念干净、控制台直观,适合把「注册中心」这件事讲透。生产环境新建项目,现在多数会选 Nacos——同时做注册中心和配置中心,还带控制台和权重、命名空间之类的管理能力。迁移时注意一点:Nacos 的地址写法不带 /eureka 这类上下文,spring.cloud.nacos.discovery.server-addr 直接写 127.0.0.1:8848,别把 Eureka 的习惯直接搬过去。

关键配置速览

配置项示例值说明
server.port10086注册中心端口,必须与 defaultZone 一致
spring.application.nameeurekaserver微服务名,不写会在控制台显示 UNKNOWN
eureka.client.service-url.defaultZonehttp://127.0.0.1:10086/eureka注册中心地址,必须带 /eureka 后缀
eureka.client.register-with-eurekatrue(默认)是否注册自身,单节点可设 false
eureka.client.fetch-registrytrue(默认)是否拉取服务列表,单节点可设 false
eureka.instance.prefer-ip-addresstrue需要显示真实 IP 而非主机名时开启

API 速览

Eureka Server 对外就是一组 REST 接口,配置里的 defaultZone 拼的就是它们的前缀。

方法路径说明
POST/eureka/apps/{appName}服务注册,客户端启动时调用
PUT/eureka/apps/{appName}/{instanceId}心跳续约,默认每 30 秒一次
DELETE/eureka/apps/{appName}/{instanceId}服务下线,客户端优雅关闭时调用
GET/eureka/apps查询全部实例,服务发现的核心接口
GET/eureka/apps/{appName}按服务名查询实例列表
GET/Eureka 管理控制台页面

官方文档

总结

搭建 Eureka Server 的动作本身只有三步:引 eureka-server 依赖、启动类加 @EnableEurekaServer、配置文件写端口/服务名/defaultZone。

真正需要记住的是几个判断点:

  • 依赖后缀是 -server 还是 -client,选错不会报错但功能对不上
  • defaultZone 后面那截 /eureka 少不得,这是 404 的头号来源
  • spring.application.name 决定控制台里显示名字还是 UNKNOWN
  • register-with-eureka、fetch-registry 默认是 true,单节点关掉是优化不是必须,集群下必须保留
  • 控制台里的实例列表,就是整个注册中心的产物,也是后面服务注册与服务发现的验证入口

下一步就是把 user-service 用 eureka-client 注册进来,再让 order-service 按服务名拉取并完成负载均衡调用。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/Tyro_java/article/details/167168336

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--