一、Eureka(服务注册与发现)
作用:实现服务治理(服务注册与发现)
简介:Spring Cloud Eureka是Spring Cloud Netflix项目下的服务治理模块。
由两个组件组成:Eureka Server(服务注册中心,服务端)和Eureka Client(客户端)。
- 最左边的 Client(即服务提供者,为Server提供一些功能服务)会向us-east-1c(Server)发起注册请求;做 Register(服务注册)、Renew(服务续约)、Cancel(服务下线)等操作
- Eureka Server 集群中的其他两个 Server(us-east-1d 和 us-east-1e)会做注册服务的 Replicate(复制),从而保证状态一致
- 图下方的前两个Client(即服务消费者)也会向 Server 注册自己,做服务注册、续约、等操作。注册完成后可以通过访问服务注册中心(Eureka Server) 获取注册服务列表(Get Registry),并远程调用(Make Remote Call)消费服务
1、Eureka Server
是服务注册中心,支持集群部署。
在服务治理框架中,通常都会构建一个注册中心(server)。每个服务单元(client)向注册中心(server)登记自己提供的服务,包括服务的主机与端口号、服务版本号、通讯协议等一些附加信息。注册中心按照服务名分类组织服务清单,同时还需要以心跳检测的方式去监测清单中的服务是否可用,若不可用需要从服务清单中剔除,以达到排除故障服务的效果。
Eureka服务端,即服务注册中心。它同其他服务注册中心一样,支持高可用配置。依托于强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。
Eureka服务端支持集群模式部署,当集群中有分片发生故障的时候,Eureka会自动转入自我保护模式。它允许在分片发生故障的时候继续提供服务的发现和注册,当故障分配恢复时,集群中的其他分片会把他们的状态再次同步回来。集群中的的不同服务注册中心通过异步模式互相复制各自的状态,这也意味着在给定的时间点每个实例关于所有服务的状态可能存在不一致的现象。
2、Eureka Client
客户端是一个java客户端,用来处理服务注册与发现(客户端向 Eureka Server 注册的时候会提供一系列的元数据信息,例如:主机,端口,健康检查url等)
客户端分为:提供者和消费者两种
- 提供者:提供功能
- 消费者:调用功能
Eureka客户端,主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。在应用程序启动时,Eureka客户端向服务注册中心注册自身提供的服务,并周期性的发送心跳来更新它的服务租约。同时,他也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期行的刷新服务状态。
注意:在应用启动时,Eureka客户端向服务端注册自己的服务信息,同时将服务端的服务信息缓存到本地。客户端会和服务端周期性的进行心跳交互,以更新服务租约和服务信息
在 SpringCloud 之中使用了大量的Netflix 的开源项目,而其中 Eureka 就属于Netflix 提供的发现服务组件,所有的微服务在使用之中全部向 Eureka 之中进行注册,而后客户端直接利用 Eureka 进行服务信息的获取。
<!--spring cloud的eureka服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--spring cloud的eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
二、案例学习准备工作(搭建父模块)
创建父模块maven项目,此处省略创建过程,下面是项目结构和pom.xml信息,之后的子模块都继承自这个父模块,所以父模块这里只需要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.imooc.homepage</groupId>
<artifactId>imooc-homepage</artifactId>
<version>1.0-SNAPSHOT</version>
<!--对于集合模块来说父模块必须是POM-->
<packaging>pom</packaging>
<name>imooc_homepage_springCloud_demo</name>
<!--因为springCloud是基于springBoot的所以要引用springBoot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<!--
添加spring Cloud
由于springcloud是基于springboot的,所以需要注意版本兼容问题,所以请选择对应支持的版本
-->
<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>
<dependencies>
<!--引入lombok,在案例中我使用了@Slf4j来记录LOG信息-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--springboot 测试用例依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!--本地maven配置仓库如果下载不到所需依赖,就去下面这个配置spring官方仓库下载-->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
三、Eureka Server(服务注册中心搭建)
服务端的创建有以下操作
- 创建服务端模块
- 添加服务端依赖
- 创建启动类添加服务端注解
- 添加服务端配置文件
1、创建EurekaServer子模块,并添加依赖
我们练习的结构中,子模块继承了父模块的一些依赖,这样可以减少所有子模块中重复配置的信息。当然你也可以不选择这种方式,没有任何影响。
homepage-eureka(这里名字可以随便起,我只是为了学习好区分),结构和pom文件依赖如下
在pom文件中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<?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>imooc-homepage</artifactId>
<groupId>com.imooc.homepage</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>homepage-eureka</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>homepage-eureka</name>
<dependencies>
<!--spring cloud的eureka服务-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--配置boot运行插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、创建EurekaServer启动类
1、添加@SpringBootApplication注解变为,boot的启动类
2、使用@EnableEurekaServer 注解就可以让应用变为Eureka服务端
package com.imooc.homepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* 1、pom文件中对应到spring-cloud-starter-netflix-eureka-server
* 2、只需要使用@EnableEurekaServer 注解就可以让应用变为Eureka
*/
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}
3、添加配置资源文件(单节点Eureka Server)
这里我们使用的是单节点Eureka Server
注意:在默认配置下,Eureka Server会将自己也作为客户端(clinet)来尝试注册自己,我们需要禁用它的客户端禁用行为。
设置application.yml
spring:
application:
#这个spring应用的名字(之后调用会用到)
name: homepage-eureka
server:
#服务注册中心端口号
port: 8000
eureka:
instance:
#服务注册中心实例的主机名
hostname: localhost
client:
# 表示是否从 eureka server 中获取注册信息(检索服务),默认是true
fetch-registry: false
# 表示是否将自己注册到 eureka server(向服务注册中心注册自己),默认是true
register-with-eureka: false
service-url:
#服务注册中心的配置内容,指定服务注册中心的位置,eureka 服务器的地址(注意:地址最后面的 /eureka/ 这个是固定值)
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动服务端(eureka server)
右键运行启动类
在浏览器访问localhost:8000
出现如下界面说明成功了
这个界面记录了:状态信息、注册节点信息、实例信息等
由当前只有自己,没有注册其他实例,所以标注的区域没有其他的信息。后面有客户端注册进来后就会出现实例信息
四、多节点Eureka Server 配置(集群Server)
考虑到发生故障的情况,服务注册中心发生故障必将会造成整个系统的瘫痪,因此需要保证服务注册中心的高可用。
Eureka Server在设计的时候就考虑了高可用设计,在Eureka服务治理设计中,所有节点既是服务的提供方,也是服务的消费方,服务注册中心也不例外。
Eureka Server的高可用实际上就是将自己做为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。
说明:由于我们在一台机器一个工程上模拟多个节点,我们需要给springboot应用配置profiles属性用来标识,并且打包成jar包之后,我们启动指定profiles的应用
1、修改hosts文件(单机单应用上模拟多节点所需要)
因为我的练习只有一台主机,所以我要在这台电脑上创建多个 IP 与 主机名(域名)的映射,从而模拟多节点
在我的电脑中进入这个路径可以找到hosts文件
C:\Windows\System32\drivers\etc
我们需要在hosts文件中添加几个服务,修改前为了防止意外建议先将这个文件备份
这个文件一般是只读不可修改的,网上很容易查到解决方法,在此我就不多做解释了。(比如在属性里把只读勾选去掉)
2、创建多节点配置文件
在多节点的配置中,我们只需要修改配置文件就好,其他的都不用动
注意:
在重新配置多节点时,我们要把之前使用的配置文件内容要全部注掉或者删掉文件
这里似乎bootstrap.yml这个文件名的执行优先级高一点,具体还没有仔细研究过优先级
spring:
application:
name: homepage-eureka
profiles: server1
server:
port: 8000
eureka:
instance:
hostname: server1
prefer-ip-address: false
client:
service-url:
#将该eureka注册到server2和server3
defaultZone: http://server2:8001/eureka/,http://server3:8002/eureka/
# 用三个连接符进行profile分割,根据active的profiles选择执行哪一段,上面没有profiles的表示公共执行部分
---
spring:
application:
name: homepage-eureka
profiles: server2
server:
port: 8001
eureka:
instance:
hostname: server2
prefer-ip-address: false
client:
service-url:
defaultZone: http://server1:8000/eureka/,http://server3:8002/eureka/
---
spring:
application:
name: homepage-eureka
profiles: server3
server:
port: 8002
eureka:
instance:
hostname: server3
prefer-ip-address: false
client:
service-url:
defaultZone: http://server1:8000/eureka/,http://server2:8001/eureka/
我在文件中遇到的问题:
- 在配置多个server节点时要添加 “---”来分隔,不然编译器会报红
- “---”横线分隔只能写三个横线,我写多了再启动服务的时候就会报错(没有仔细研究为什么)
- 配置多节点时,启动我是通过java命令直接启动jar包的,因为我有三个server,并且相互间有联系
3、启动多节点服务端
启动多节点和之前有点不同,不是直接右键运行启动类,而是通过java命令运行 打好包的jar文件(如果您有其他的办法也望不吝分享)
(1)命令打包为jar文件
先打包,在工程根目录下执行mvn,运行后我们会在target中发现打好的jar包
mvn clean package -Dmaven.test.skip=true -U
(2)命令运行分别启动每个节点服务
dom命令进入\homepage-eureka\target路径下
分多个窗口分别运行下面命令,启动指定的profiles的server应用(这就是说的多节点)
java -jar homepage-eureka-1.0-SNAPSHOT.jar --spring.profiles.active=server1
java -jar homepage-eureka-1.0-SNAPSHOT.jar --spring.profiles.active=server2
java -jar homepage-eureka-1.0-SNAPSHOT.jar --spring.profiles.active=server3
注意:
在启动过程中,服务可能会抛出错误,因为我们是三个服务是相关联的。在没有全部启动好的情况下,某一个服务在尝试注册另外两个服务的时候可能会报错找不到关联的服务,但是当所有服务全部完成启动后,就会正常了。
比如: 8000端口抛出错误,它在向8001 和8002注册的时候,尝试访问过程中8002还没有完成启动,所以会抛出一些异常
(3)页面访问端口
页面访问8000端口
页面访问8001端口
五、 Eureka Client(客户端,功能提供者搭建)
客户端要将自己注册进服务端,从而可以让其他模块访问自己提供的功能
服务端的创建有以下三个操作
- 创建客户端模块
- 添加客户端依赖
- 创建启动类添加客户端注解
- 添加客户端配置文件
1、创建EurekaClient子模块,并添加依赖
创建一个名字叫homepage-eurekaClient的子模块(名字你可以自己起)
在pom文件中添加依赖
<!--spring cloud的eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--
添加web是为了解决client启动后自动关闭的问题
由于microserver-user 服务是是web项目 所以还需要添加对应的web包
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<?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>imooc-homepage</artifactId>
<groupId>com.imooc.homepage</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>homepage-eurekaClient</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>homepage-eurekaClient</name>
<dependencies>
<!--spring cloud的eureka客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--
添加web是为了解决client启动后自动关闭的问题
由于microserver-user 服务是是web项目 所以还需要添加对应的web包
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--配置boot运行插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、创建EurekaClient启动类
1、添加@SpringBootApplication注解变为,boot的启动类
2、使用@EnableEurekaClient注解就可以让应用变为Eureka客户端
package com.imooc.homepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* 1、pom文件中对应到spring-cloud-starter-netflix-eureka-client
* 2、使用@EnableEurekaClient 注解就可以让应用变为Eureka客户端端
* 3、@SpringBootApplication是启动器
*/
@EnableEurekaClient
@SpringBootApplication
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class,args);
}
}
3、添加客户端配置资源文件
设置application.yml
spring:
application:
name: homepage-eureka-client
server:
port: 8100
eureka:
client:
service-url:
#将自己注册进下面这个地址的服务注册中心
defaultZone: http://localhost:8000/eureka/
注意:
defaultZone:意思是将自己注册进哪个服务,就写对应服务的地址,我这里的地址是上面单节点eureka server的地址
启动服务端 和 客户端(eureka server、eureka client)
这时我们要同时启动服务端和客户端两个服务,启动过程中客户端会将自己注册进服务端
intellij的同时启动多个服务的方法请查看我的另一篇博文Intellij IDEA如何同时启动多个服务
1、先启动服务端
下图控制台中我们可以看出服务注册中心已经启动成功
2、启动提供服务的客户端
客户端启动后我们可以看到服务端的控制台打印了一条注册实例的信息
注册的是homepage-eureka-client:8100(我们的客户端)
3、页面访问服务端查看注册信息
下图中我们可以看到我们访问服务端的 Instances currently registered wit Eureka中已经发现我们客户端注册信息
说明我们已经成功的将client(客户端)注册进了server(服务端)
遇到的问题
服务端启动完成,客户端启动后又自己关闭了
解决方案:可能是没有为客户端添加spring-boot-starter-web依赖,添加完成后在重新启动就好了。
详情可以参考我的博文【issue】SpringCloud eureka Client启动后自动停止
注意:启动后我们会看到界面有红色的信息(我们暂时可以不用管它)
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.
RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST
TO BE SAFE.
分析:是由于 Eureka 进入了保护模式。
在保护模式下,Eureka Server 将会尝试保护其服务注册表中的信息,暂时不会注销服务注册表中的
服务。
六、服务消费端
现在我们有了服务注册中心,也有为我们提供真实服务的客户端,并且该客户端已经将自己注册进了服务注册中心。这样就能为外部提供自己的功能服务。
那么我们现在功能都提供好了,就剩下调用了。(蛋糕都准备好了,还等什么,吃 呗!!!)
那么怎么吃呢?哦,不对。
应该是怎么调用呢?
spring cloud 中为我们提供了两种服务调用组件:
- Eureka Ribbon:客户端负载均衡的服务调用组件
- OpenFeign:基于Ribbon和Hystrix的声明式服务调用组件
在我下一篇博文中会选择其中一个进行讲解(因为作为新手的自己还没有考虑好,应该先从哪个下叉子。。。。。)