SpringCloud之Eureka服务注册与发现
什么是服务治理?
Spring Cloud封装了Netfix公司开发的Eureka模块来实现服务治理
在传统的rpc远程调用框架中,管理每个服务服务之间的依赖关系比较复杂,管理比较复杂,就像我们之前的基础项目一样,虽然能实现功能,但是一旦服务多了起来就非常难管理,所以需要使用服务治理,管理服务与服务之间的依赖关系,可以实现服务调用,负载均衡,容错等,实现服务发现与注册。
什么是服务注册与发现
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息 比如 服务地址 通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC。远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
Eureka两组件
Eureka Server
Eureka Server提供服务注册服务,各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在页面中直观看到。
Eureka Client
Eureka Client是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)
构建单机版Eureka
Eureka Server
创建新模块cloud-eureka-server7001
pom
1 | <dependencies> |
yml
创建application.yml
配置文件
1 | server: |
- fetch-registry: 检索服务选项,当设置为True(默认值)时,会进行服务检索,注册中心不负责检索服务。
- register-with-eureka: 服务注册中心也会将自己作为客户端来尝试注册自己,为true(默认)时自动生效
- eureka.client.serviceUrl.defaultZone是一个默认的注册中心地址。配置该选项后,可以在服务中心进行注册。
由于这个服务模块自己就是注册中心,职责是维护服务实例,并不需要去检索服务,和在服务中心注册自己
所以一般情况下,当我们设置服务为注册中心时,需要关闭eureka.client.fetch-registry与eureka.client.register-with-eureka,在做注册中心集群的时候,register-with-eureka必须打开,因为需要进行相互注册,不然副本无法可用
主启动类
使用@EnableEurekaServer
开启Eureka服务
1 |
|
测试
接着启动主启动类,访问http://localhost:7001/
进行测试
配置eureka.client.service-url.defaultZone为什么要加eureka做后缀。而在访问eureka服务的时候却不加这个内容到url中,通过localhost:7001就可以访问控制台?这是因为在eureka server的实现中存在一个web请求过滤器,其url模式就是[/eureka/*]
。
Eureka Client Provider
EurekaClient端cloud-provider-payment8001
将注册进EurekaServer成为服务提供者provider
pom
修改pom.xml文件,导入Eureka Client依赖。
1 | <dependency> |
yml
配置文件添加Eureka配置
1 | eureka: |
register-with-eureka: true 由于我们是服务的提供者所以要注册进注册中心
fetch-registry: true 是否从EurekaServer抓取已有的注册信息 ,默认为true。 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
注册的名字就是spring.application.name
配置的名字
主启动类
添加@EnableEurekaClient
注解开启
测试
启动测试,先启动Eureka Server在启动Eureka Client
输入地址http://localhost:7001/
访问页面,成功
Eureka的自我保护机制
Eureka Client Consumer
EurekaClient端cloud-consumer-order80
将注册进EurekaServer成为服务消费者consumer
pom
修改pom.xml文件,导入Eureka Client依赖。
1 | <dependency> |
yml
添加服务名称和eureka配置
1 | server: |
主启动类
添加@EnableEurekaClient
注解开启
测试
启动项目进行测试,成功
单机版Eureka代建成功!
构建集群版Eureka Server
为什么要使用集群版?
微服务RPC远程服务调用最核心的是什么?高可用,当我们的注册中心只有一个only one时,它如果出现了故障会导致整个服务环境不可用,所以要搭建Eureka注册中心集群,实现负载均衡+故障容错
7001在7002中注册,7002在7001注册,互相注册,相互守望。
在单机版的基础之上进行修改和添加
Eureka Server
创建新模块cloud-eureka-server7002
pom
与cloud-eureka-server7001
一样
1 | <dependencies> |
yml
新建application.yml
编写配置文件
由于defaultZone中都是使用的localhost所以配置host文件进行一下区分(可以不用配置,为了好看)
作用就是当输入eureka7001.com
或者eureka7002.com
时实际代表的还是127.0.0.1
也就是localhost
1 | server: |
同时修改7001的Eureka Server配置文件
1 | server: |
从而达到相互注册,互相守望!
主启动类
使用@EnableEurekaServer
开启Eureka服务
测试
分别启动7001,和7002。分别访问各自的页面查看效果http://eureka7001.com:7001/
和http://eureka7001.com:7002/
成功!
Eureka Client Provider
将支付服务8001微服务发布到上面2台Eureka集群配置中
yml
修改8001,yml配置文件的Eureka服务地址
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com/eureka #集群版
Eureka Client Consumer
将订单服务80微服务发布到上面2台Eureka集群配置中
yml
修改80,yml配置文件的Eureka服务地址
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com/eureka #集群版
启动8001,和80端口。(7001,7002已启动)
7001
7002
搭建成功!
构建集群版Eureka Client
同样当我们代建好了集群本的Eureka注册中心后,我们的服务提供者还是只有一个,当服务提供者出现故障,同样会导致整个服务受到影响,所以我们还要搭建集群版的服务提供者
支付服务提供者集群环境构建
新建cloud-provider-payment8002
参考8001
pom
pom.xml与8001一样
1 | <dependencies> |
Mapper和各种类
把8001中的controller,service,dao,mapper都复制一份到8002中
yml
yml也与8001一致,唯一的不同点在于端口号修改为8002
主启动类
PaymentMain8002
controller
由于我们配置了服务提供者的集群,当我们使用服务的时候无法分辨我们正在使用那台服务提供者,不知道是8001还是8002,所以我们要修改一下controller,方便我们查看测试效果~
将8001,和8002的controller进行同样的修改
1 |
|
会把当前的服务端口号一起展示出来,方便我们知道当前调用的是哪个服务提供者
测试
启动7001,7002,80,8001,8002
7001
7002
首先我们各自不同端口的访问服务提供者的服务是否正常
8001
8002
一起正常。接着查看我们的consumer是否能正常使用服务提供者的服务
80
访问正常,但是当我们不断刷新它使用的还是8001服务提供者提供的服务,而没有使用一次8002的,这是不符合我们的初衷的!这是为什么呢?
这是因为我们80中的controller的url地址是写死的
我们将地址修改为我们在注册中心注册的服务名称
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
重新启动80,重新访问80.直接报错
这是为什么呢?
这是因为我们此时访问的是一个整体的CLOUD-PAYMENT-SERVICE
我们访问时不知道应该调用这个整体中的哪一个?是调用8001,还是8002我们不知道,所以报错。
负载均衡
使用@LoadBalanced注解赋予RestTemplate负载均衡的能力,在RestTemplate配置文件中加上注解
重新启动80,测试。成功实现集群的效果!
actuator微服务信息完善
主机名称
想对这个名称进行规范统一的修改配置
只需要通过配置eureka.instance.instance-id
即可。分别修改8001,8002的配置文件
8001
8002
修改成功!
ip信息提示
点击实例名称,左下角是没有ip提示的,这样不方便我们进行调试。
我们需要让其显示ip信息提示
添加配置eureka.instance.prefer-ip-address
为true即可
8001
8002
重启查看效果,成功显示ip
服务发现Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
以cloud-provider-payment8001
为例
controller
首先注入一个DiscoveryClient对象
接着添加一个请求映射
1 |
|
discoveryClient.getServices()
获取微服务名称
discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
获取此微服务实例对象
主启动类
主启动类上加上@EnableDiscoveryClient
开启服务发现
测试
重启8001服务,访问http://localhost:8001/payment/discovery
控制台结果
Eureka自我保护
理论知识
自我保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式。
Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务
如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入保护模式:
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 Client可以正常运行,但是与Eureka Server网络不通情况下,Eureka Server不会立刻将Eureka Client服务剔除
什么是自我保护模式?
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当在网络分区故障发生(延时,卡顿,拥挤)时,微服务与Eureka Server之间无法正常通信,以上行为就可能会变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过‘自我保护模式’来解决这个问题。当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入到自我保护模式。
在自我保护模式中,Eureka Server会保存服务注册表中的信息,不再注销任何服务实例。
它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着
综上,自我保护模式是一中应对网络异常的安全保护措施。它的架构哲学是宁可保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮,稳定。属于CAP里面的AP分支
结果体现
我们把正在运行的cloud-provider-payment8001
先关掉
在修改一下8001的配置文件,将前文配置的主机名称注释,使用默认的名称注册到注册中心
重新启动8001,查看Eureka Server页面
7001
7002
可以发现默认的名称已经注册到了注册中心,但是payment8001
还是存在!这就是自我保护模式
关闭自我保护
一般生产环境中不会禁止自我保护
由于使用集群版Eureka Server太费时间所以修改7001为单机版,和只使用8001
出厂默认,自我保护机制是开启的
eureka.server.enable-self-preservation = true
修改为false
eureka.server.eviction-interval-timer-in-ms
eureka server清理无效节点的时间间隔,默认90000毫秒,即90秒,修改为两秒
启动查看Eureka Server界面
THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
提示自我保护模式已经被关闭
生产者客户端eureakeClient端8001修改配置
eureka.instance.lease-renewal-interval-in-seconds=30
修改为1。Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
eureka.instance.lease-expiration-duration-in-seconds=90
修改为 2。Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
加快我们查看测试效果,不用进行较长等待才能看到效果。
启动8001,注册成功
关闭8001
查看效果,马上剔除
成功关闭自我保护!