前言
HI 大家好,这是我第一次记录自己的学习内容,从各个角度来说,可能会有很多问题或不完整的地方或描述不清晰的地方,欢迎大家指出,我会及时修正,希望大家能从文章中获取到自己想要的内容
什么是Eureka
在了解Eureka之前,我们先熟悉下以下几个概念:
可以先了解微服务的概念
1. 什么是服务治理?
2. 什么是服务注册?
3. Eureke 和 Dubbo 架构对比
明白了服务治理以及服务注册与发现,再来看Eureka
github地址:github.com/Netflix/eur…
在Eureka官网上有对Eureka进行描述,说人话就是:Eureka是一项基于Rest的服务,主要用于服务的发现,以实现负载均衡和中间服务器的故障转移,我们称此为Eureka服务。
Eureka有什么
本次学习使用的是Spring Cloud Hoxton.SR1版本 SpringBoot 2.2.2.RELEASE 在新版本中Eureka包含两个模块,Eureka Server 和 Eureka Client
1. Eureka Server 提供服务注册服务
各个微服务节点通过配置启动后,会在 EurekaServer中进行注册,这样 EurekaServer中的服务注册表中将会存储所有可用服务节点的信息。
2. Eureka Client通过注册中心进行访问
是一个Java客户端,用于简化与 Eureka Server的交互,客户端也同时具备一个内置的,使用 轮询负载算法的负载均衡器。在应用启动后,将会向Eureka Server 发送心跳(默认周期30秒)。如果Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中将这个服务节点移除(默认90秒)
单机版怎么玩
单机使用步骤
使用IEDA创建父工程
创建好父工程
cloud-study后可删除生成的SRC文件夹
修改POM
由于是父工程,因此需要修改POM的打包方式为POM
<packaging>pom</packaging>
Eureka依赖新老版本对比:
然后父工程需要对jar包进行统一的管理,以及配置阿里私服和MAVEN插件,完整POM如下:
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cloud</groupId>
<artifactId>springcloud-study</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!--统一管理jar包版本-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<spring.boot.version>2.2.2.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>
<!--子模块继承后,提供作用:锁定版本+子module不用groupId和version-->
<dependencyManagement>
<dependencies>
<!--springboot 2.2.2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring cloud Hoxton.SR1-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
<!--第三方maven私服-->
<repositories>
<repository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
`
创建服务注册中心
名称取为
cloud-eureka-server7001
修改 Eureka Server POM文件 加入依赖
<?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>springcloud-study</artifactId>
<groupId>com.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--devtools 为热加载工具,即修改完代码后自动加载,无需重启-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--lombok为可通过注解生成get/set方法 构造器,toString方法等 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
编写配置文件application.yml
在resource目录下新建配置文件application.yml,并填写端口号7001
server:
port: 7001
spring:
application:
name: cloud-eureka-server
eureka:
instance:
hostname: eureka7001 # eureka服务端实例名称
client:
#false表示不向注册中心注册自己
register-with-eureka: false
#false表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 设置与 eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://localhost:7001/eureka #或使用http://${eureka.instance.hostname}:${server.port}/eureka/
编写主启动类EurekaMain7001
package com.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //开启Eureka服务端
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
启动应用并访问http://localhost:7001/
浏览器进入 http://localhost:7001/ 看能不能看到 eureka 的服务页面,如下图图代表Eureka Server 创建成功
创建服务提供者提供服务
Eureka Client端应用cloud-provider-payment8001应用,并将注册进 Eureka Server 成为服务提供者 provider
根据上面创建Eureka Server 步骤可总结出,创建应用分四步:
创建module
改POM
写yml
建启动类
下面的测试都将使用以上步骤进行学习
创建module
改POM
<?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>springcloud-study</artifactId>
<groupId>com.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8001</artifactId>
<dependencies>
<!--eureka-client:此处为Client端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热加载工具,修改代码后无需手动重启服务器,可百度如何配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
复制代码
`
改YML
server:
port: 8001
spring:
application:
# 应用程序名称,显示在Eureka Server中的名称
name: cloud-provider-payment
eureka:
client:
# 表示将自己注册进注册中心
register-with-eureka: true
# 表示自己将会从注册成中心中获取服务列表
fetch-registry: true
service-url:
# 将自己注册进注册中心的地址
defaultZone: http://localhost:7001/eureka/
建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //开启Eureka客户端
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
测试
- 先启动注册中心7001
- 再启动服务提供者8001
- 打开服务端页面查看是否注册成功
启动成功,如下图所示

创建服务消费者消费服务
创建Module
创建module名称为cloud-consumer-order80

改POM
需要注意引入的Eureka为Client
<?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>springcloud-study</artifactId>
<groupId>com.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-order80</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
// 提供者消费者引入的是client,注册中心引入的是server
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>
改YML
消费者需要配置服务名称,和服务注册地址
server:
# 端口
port: 80
eureka:
client:
#消费者需要把自己注册进注册中心
register-with-eureka: true
#消费者会从注册中心获取服务列表
fetch-registry: true
service-url:
#服务注册地址
defaultZone: http://localhost:7001/eureka
spring:
application:
# 应用程序名称,显示在Eureka中的名称
name: cloud-consumer-order
建启用类
com.cloud.order.OrderMain80
package com.cloud.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //开启Eureka客户端
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
测试
-
先启动注册中心7001
-
再启动服务提供者8001
-
最后启动服务消费者80
-
打开服务端页面查看是否注册成功
如下图:

测试服务调用
服务提供者增加服务
在cloud-provider-payment8001 中创建PaymentController类,并提供rest服务,模拟获取数据服务
package com.cloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController //提供Rest服务 相当于 @controller + @responsebody
@Slf4j // 日志
public class PaymentController {
@GetMapping("/payment/{id}")
public String getPayment(@PathVariable("id") Long id) {
return "请求成功 " + "id 为:" + id + " 获取成功";
}
}
服务提供者自测,在浏览器端访问服务提供者http://localhost:8001/payment/2

服务消费者消费服务
消费者调用服务使用的RestTemplate
RestTemplate是Spring用于同步client端的核心类,简化了与http服务的通信,并满足RestFul原则,程序代码可以给它提供URL,并提取结果。默认情况下,RestTemplate默认依赖jdk的HTTP连接工具。当然你也可以 通过setRequestFactory属性切换到不同的HTTP源,比如Apache HttpComponents、Netty和OkHttp。
springboot配置RestTemplate配置类:
package com.cloud.order.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration //声明这是一个配置类
public class RestTemplateConfig {
@Bean //返回值是一个Bean,类似于XML中配置的<bean>
@LoadBalanced //不添加该注解会报UnknownHostException
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
创建OrderContrroller类:
package com.cloud.order.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderController {
//请求服务器地址,配置服务名称即可
public static final String PAYMENT_URL = "http://cloud-provider-payment";
@Resource //注入依赖
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/{id}")
public String getOrder(@PathVariable("id")Long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/" +id,String.class);
}
}
从浏览器访问消费者服务,返回结果则代表调用成功

集群版怎么玩
Eureka集群原理说明:
这里的集群讲的是Eureka Server的集群,不是Eureka Client的集群

Eureka集群环境搭建
新建cloud-eureka-server7002
cloud-eureka-server7002和cloud-eureka-server7001一致,只有配置需要修改即可

改POM
此处POM和
cloud-eureka-server7001中的POM依赖一致,此处不再重复
改YML
在resource下新建application.yml文件,然后将cloud-eureka-server7001中的文件内容复制进去,然后修改端口号和注册地址,完整配置如下:
server:
port: 7002
spring:
application:
name: cloud-eureka-server
eureka:
instance:
hostname: eureka7002 # eureka服务端实例名称
client:
#false表示不向注册中心注册自己,集群版要设置为true
register-with-eureka: true
#false表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务,集群版要设置为true
fetch-registry: true
service-url:
# 把7002注册进7001
defaultZone: http://localhost:7001/eureka/
== cloud-eureka-server7001 同样需要修改:==
server:
port: 7001
spring:
application:
name: cloud-eureka-server
eureka:
instance:
hostname: eureka7001 # eureka服务端实例名称
client:
#false表示不向注册中心注册自己,集群版要设置为true
register-with-eureka: true
#false表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务,集群版要设置为true
fetch-registry: true
service-url:
# 把7001注册进7002
defaultZone: http://localhost:7002/eureka/
建启动类
在src\main\java下创建com.cloud.EurekaMain7002.java
@SpringBootApplication
@EnableEurekaServer //开启Eureka服务端
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class, args);
}
}
将提供者服务发布到Eureka集群中
修改defaultZone,将服务注册进集群中
server:
port: 8001
spring:
application:
# 应用程序名称,显示在Eureka Server中的名称
name: cloud-provider-payment
eureka:
client:
# 表示将自己注册进注册中心
register-with-eureka: true
# 表示自己将会从注册成中心中获取服务列表
fetch-registry: true
service-url:
# 将自己注册进注册中心的地址
# defaultZone: http://localhost:7001/eureka/ #单机版
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
测试
启动cloud-eureka-server7001和cloud-eureka-server7002两个服务端应用,然后启动服务提供者cloud-provider-payment8001,如下图:
如果没有
services窗口可百度查询如何打开

分别访问http://localhost:7001/和http://localhost:7002/ .在7001应用界面可以看到如下图所示:


服务提供者集群搭建
参考cloud-provider-payment8001 创建cloud-provider-payment8002
改POM 建YML 建主启动类 业务类和8001类似
8002yml配置:
server:
port: 8002 #只需要修改端口为8002
spring:
application:
# 应用程序名称,显示在Eureka Server中的名称
name: cloud-provider-payment
eureka:
client:
# 表示将自己注册进注册中心
register-with-eureka: true
# 表示自己将会从注册成中心中获取服务列表
fetch-registry: true
service-url:
# 将自己注册进注册中心的地址
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/
为了测试出效果,我们改造下controller中的返回值,返回所调用服务的端口号,8001和8002都需要改造
package com.cloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController //提供Rest服务 相当于 @controller + @responsebody
@Slf4j // 日志
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/{id}")
public String getPayment(@PathVariable("id") Long id) {
return "请求成功 " + "id 为:" + id + " 获取成功,服务提供者端口号为:" + serverPort;
}
}
消费者消费提供者服务
第一次访问:

第二次访问:

结果
8001/8002端口交替出现,达到负载均衡的效果
结论
使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
为何会出现这种情况,将会在Ribbon中学习到;
目前只需要知道@LoadBalanced可以达到负载均衡的效果,而且默认是轮询的方式
actuator微服务信息完善
主机名称:服务名称修改
当前存在的问题:
显示的是localhost:服务名称:IP地址

只需要修改YML中的eureka.instance.instance-id即可:
server:
port: 8001
spring:
application:
# 应用程序名称,显示在Eureka Server中的名称
name: cloud-provider-payment
eureka:
client:
# 表示将自己注册进注册中心
register-with-eureka: true
# 表示自己将会从注册成中心中获取服务列表
fetch-registry: true
service-url:
# 将自己注册进注册中心的地址
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/
instance:
#配置Eureka实例ID
instance-id: payment8001

访问信息有IP地址提示
把我们的鼠标放到上图中的payment8001上查看IP地址:

发现并不能看到真实的IP地址,解决办法是添加prefer-ip-address: true配置
server:
port: 8001
spring:
application:
# 应用程序名称,显示在Eureka Server中的名称
name: cloud-provider-payment
eureka:
client:
# 表示将自己注册进注册中心
register-with-eureka: true
# 表示自己将会从注册成中心中获取服务列表
fetch-registry: true
service-url:
# 将自己注册进注册中心的地址
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/
instance:
#配置Eureka实例ID
instance-id: payment8001
# 显示IP地址配置
prefer-ip-address: true
效果如下图,会显示IP地址和端口号:

服务发现Discovery
对于注册eureka里面的微服务,可以通过服务发现来获得该服务的信息
修改cloud-provider-payment8001的Controller


8001的启动类上加上注解@EnableDiscoveryClient
测试
访问http://localhost:8001/payment/discovery 效果如下


Eureka自我保护机制
### 故障现象

导致原因




一句话总结就是:某时刻 一个微服务不可用了,Eureka不会立刻清理,依旧会对该服务的信息进行保存,属于CAP里面的AP分支
怎么禁用自我保护
注册中心端
在Eureka的服务端,默认自我保护机制是开启的eureka.server.enable-self-preservation=true 可以将此设置改为false,即可禁用自我保护

关闭效果:

客户端
有两个默认配置:
eureka.instance.lease-renewal-interval-in-seconds=30 Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
eureka.instance.lease-expiration-duration-in-seconds=90 Eureka服务端在收到最后一次心跳后等待时间上限 ,单位为秒(默认是90秒),超时剔除服务
当服务端修改之后,客户端这两个配置可设置成1,即服务宕机后注册中心中立即剔除此服务