前言
在上篇文章我讲到如何搭建SpringCloud
微服务基础环境,本次我将介绍Netflix
的Eureka
,并整合到SpringCloud
中
什么是Eureka?
Eureka
是Netflix
的一个子模块,也是核心模块之一。Eureka
是一个基于REST
的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo
的注册中心,比如Zookeeper
。
Netflix在设计Eureka时遵守的就是AP原则
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得
下面我们就来撸代码啦~
建立Eureka注册中心(spring-cloud-eureka)
首先建立一个Eureka
父工程(spring-cloud-eureka)
)(此父工程非必需,看个人的工程层次结构的划分),此处建立是便于知识点划分
选中父工程(spring-cloud-examples
`)鼠标点击右键File → Module → Maven
不用勾选任务任何选项,直接Next → Finish
创建好后,删除src
目录,并选中spring-cloud-eureka
工程,创建此工程的子模块eureka
选中父工程(spring-cloud-eureka
)鼠标点击右键File → Module → Maven
不用勾选任务任何选项,直接Next → Finish
创建好后,修改eureka
工程的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>spring-cloud-eureka</artifactId>
<groupId>com.chaytech</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka</artifactId>
<dependencies>
<!--eureka-server服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
创建application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
启动类
@SpringBootApplication
// EurekaServer服务器端启动类,接受其它微服务注册进来
@EnableEurekaServer
public class EurekaServer7001_Application {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7001_Application.class, args);
}
}
启动eureka
工程,测试
浏览器中访问:http://localhost:7001/
显示页面
ok,eureka
注册中心已成功搭建!
但是细心的人可以发现页面中显示No application available
翻译成中文的意思是:没有服务被发现
因为没有注册服务进来当然不可能有服务被发现,下面将介绍如何将服务注册到eureka
中
上面步骤完成后看看结构是不是和我这一样呢?
最终工程展现
将已有的(spring-cloud-provider-user)用户微服务注册进eureka
不要慌,服务注册不是很复杂,只需小改代码和配置文件即可
修改spring-cloud-provider-user
的pom文件
增加如下内容
<!-- 将微服务provider侧注册进eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
修改后的完整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>spring-cloud-examples</artifactId>
<groupId>com.chaytech</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-provider-user</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.chaytech</groupId>
<artifactId>spring-cloud-model</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 将微服务provider侧注册进eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</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-test</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
修改application.yml
文件
增减如下内容
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
修改后的完整application.yml
文件
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis-config.xml # mybatis配置文件所在路径
type-aliases-package: com.chaytech.model.* # 所有Entity别名类所在包
mapper-locations:
- classpath:mybatis/mapper/**/*.xml # mapper映射文件
spring:
application:
name: user-provider
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://127.0.0.1:3306/spring_cloud_db01 # 数据库名称
username: root
password: root
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
修改spring-cloud-provider-user
服务启动类,增加@EnableEurekaClient
注解,此注解代表此服务是eureka客户端,并将此服务注册进eureka服务中
@SpringBootApplication
// 本服务启动后会自动注册进eureka服务中
@EnableEurekaClient
public class UserProvider8001_Application {
public static void main(String[] args) {
SpringApplication.run(UserProvider8001_Application.class,args);
}
}
测试
要先启动EurekaServer
也是前面建立的eureka
工程,再启动spring-cloud-provider-user
再次访问:http://localhost:7001/
可以看到此时没有No application available
提示了,有服务注册进来了
此处注意了,列表Application
列显示的名称就是我们在配置文件中配置的spring.application.name
然后再看列表最后面的Status
列,数据是带超链接的,点击可以跳转,但此时点击显示Error Page
这个info是SpringBoot
内置的restful api请求,用来显示任意的应用信息,因为没有配置所以会跳转到Error Page
页面,下面咱们来配置一下。
在spring-cloud-provider-user
pom文件中引入actuaotr
jar包,新增如下内容
<!-- actuaotr服务监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
如果需要通过info接口来获取maven中的属性内容需要在父工程(spring-cloud-examples
)添加如下配置
<build>
<finalName>spring-cloud-examples</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
修改application.yml
文件,增加info信息
info:
app.name: user-provider
build.artifactId: $project.artifactId$
build.version: $project.version$
重新build整个微服务工程 ,重启服务,再次访问
可以看到返回了一个json串,内容就是我们在application.yml
中配置的
eureka自我保护
在前面我们介绍eureka的时候有说到eureka是AP的,那就说明他又一定的容错机制,也就是指的eureka有自我保护机制。
下面我们来做一下实验,启动eureka服务端和服务提供者,然后将服务提供者停掉,等几分钟访问http://localhost:7001/ 看看会出现什么
如果不出意外的话,会出现如下图所示
这是eureka给的警告提示,由于spring-cloud-provider-user
服务注册到eureka之后,我们将服务停掉了,也就没有再给eureka发送心跳了,这个时候eureka不会立刻清理,依旧会对该微服务的信息进行保存。
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false
配置禁用自我保护模式。