上次我们讲了Spring Cloud Eureka
服务端,这次来说下客户端。客户端简单来说就是把服务注册到服务端
Eureka客户端
主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。在应用程序启动时,Eureka客户端向服务注册中心注册自身提供的服务,并周期性的发送心跳来更新它的服务租约。同时,他也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期行的刷新服务状态。
服务注册
服务提供者在启动的时候会通过REST
请求的方式将自己注册到Eureka Server
上,同时带上自身服务的一些元数据信息。Eureka Server
接收到这个Rest
请求之后,将元数据信息存储在一个双层结构的Map
中,其中第一层的key
是服务名。第二层的key
是具体服务的实例名。
在服务注册时,需要确认一下eureka.client.register-with-eureka=true
参数是否正确,该值默认为true
。若设置为fasle
将不会启动注册操作。一般Eureka Server
才设置为false
,Eureka Client
都设为true
服务同步
不同的服务提供者可以注册在不同的服务注册中心上,它们的信息被不同的服务注册中心维护。由于多个服务注册中心互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现服务注册中心之间的服务同步。通过服务同步,提供者的服务信息就可以通过集群中的任意一个服务注册中心获得。
创建并注册服务提供者
SpringCloud
和SpringBoot
的版本在上一篇文章有,这里我就不多说了
在微服务项目中,在同一个项目中应该创建多个模块,每个模块对应不同的服务
引入Spring Cloud Eureka Client
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
开启Eureka客户端
只需要在启动类中加入@EnableEurekaClient
注解
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudEurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEurekaClientApplication.class, args);
}
}
在配置文件中加入Eureka Client
相关配置
需要指定服务注册中心的地址
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:9090/eureka
server.port
指定服务的端口号
eureka.client.service-url.defaultZone
指定注册中心的地址
获取服务
消费者服务启动时,会发送一个Rest请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server
会维护一份只读的服务注册清单来返回给客户端,同时该缓存清单默认会每隔30秒更新一次。
eureka.client.registery-fetch-interval-seconds
:从Eureka
服务器端获取注册信息的间隔时间,单位:秒,默认是30秒(对于api-gateway
,如果要迅速获取服务注册状态,可以缩小该值,比如5秒)
eureka.client.eureka-server-connect-timeout-seconds
:连接 Eureka Server
的超时时间,单位:秒,默认是5秒
eureka.client.eureka-server-read-timeout-seconds
:读取 Eureka Server
信息的超时时间,单位:秒,默认是8秒
eureka.client.filter-only-up-instances
:获取实例时是否过滤,只保留UP
状态的实例,默认为true
eureka.client.eureka-connection-idle-timeout-seconds
:Eureka 服务端连接空闲关闭时间,单位:秒,默认是30秒
eureka.client.eureka-server-total-connections
:从Eureka
客户端到所有Eureka
服务端的连接总数,默认是200
eureka.client.eureka-server-total-connections-per-host
:从Eureka
客户端到每个Eureka
服务主机的连接总数,默认是50
服务调用
服务消费者在获取服务清单后,通过服务名可以获取具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon
中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。
服务下线
在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭操作时,会触发一个服务下线的Rest
服务请求给Eureka Server
,告诉服务注册中心该服务下线了。服务端在接收到该请求后,将该服务状态置位下线(DOWN)
,并把该下线事件传播出去。
服务启动
一定要先启动Eureka Server
再启动Eureka Client
不然会报com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
意思就是找不到服务端
注:在测试的时候没加web
依赖同样是报找不到服务端,所以还是加上吧
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
成功启动之后,在浏览器输入http://localhost:9090/就可以进入服务注册中心,如果设了安全验证就需要用户密码,上一篇文章有说到
在服务注册中心中可以看到服务中有一个名为
unknown
的应用服务,开放的端口是8081
,证明我们的服务成功注册了
来改下应用名吧,unknown
是默认名
只需要在配置文件中配置spring.application.name
就可以了
spring:
application:
name: springcloud-eureka-client
下面重新启动下Eureka Client
,刷新下服务注册中心页面
可以看到名为springcloud-eureka-client
的服务已经注册上去了,但是之前的unknown
服务还没下线,所以报了上面红色的一段话
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 Server的首页看到这段提示,则说明Eureka已经进入了保护模式,一般出现此模式时,服务返回错误。即如果真实的服务已经Down掉,但在注册中心界面服务却一直存在,且显示为UP状态。
产生原因:Eureka Server
在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server
会将当前的实例注册信息保护起来,同时提示这个警告。保护模式主要用于一组客户端和Eureka Server
之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server
将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。
解决方法:
1.重新启动客户端和服务端(不推荐,如果太多服务的话会很麻烦)
2.关闭注册中心自我保护机制
在Eureka Server
配置文件中把eureka.server.enable-self-preservation
设置为false
不过设置了之后只是看不到上面那段红色的提示,并且还多了一条新的提示THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
告诉我们自我保护机制被关闭了
当你再次进入服务注册中心时,可能还是有两个相同的服务,这个是正常的
因为默认情况下,如果Eureka Server
在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server
将会移除该实例。
在客户端的配置文件中加入
eureka:
instance:
lease-renewal-interval-in-seconds: 1
lease-expiration-duration-in-seconds: 2
lease-renewal-interval-in-seconds
每间隔1s,向服务端发送一次心跳,证明服务依然”存活“
lease-expiration-duration-in-seconds
告诉服务端,如果我2s之内没有给服务端发心跳,就代表服务down
掉了,将服务踢出掉
但是还是隔了几十秒才把down
掉的服务移除,不知道是不是我网络问题
所以我觉得在注册服务时写好服务名,最好不改,改了也没多大问题,就是要等一会注册中心才会把down
掉的服务移除,自我保护机制我是推荐不关闭的。
所以正常的是这样的
官方对于自我保护机制的说明
自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka
集群更加的健壮、稳定的运行。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka
就认为客户端与注册中心出现了网络故障,Eureka Server
自动进入自我保护机制,
此时会出现以下几种情况:
1、Eureka Server
不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
2、Eureka Server
仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server
新的注册信息会被同步到其它节点中。
因此Eureka Server
可以很好的应对因网络故障导致部分节点失联的情况,
而不会像Zookeeper
那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。
关于开启Eureka客户端
上面我们使用的是@EnableEurekaClient
注解
其实@EnableDiscoveryClient
与@EnableEurekaClient
都是可以的
SpringCloud
中发现服务有许多种实现(eureka、consul、zookeeper等等)。
@EnableDiscoveryClient
基于spring-cloud-commons
,
@EnableEurekaClient
基于spring-cloud-netflix
。
如果选用的注册中心是eureka
,那么就推荐@EnableEurekaClient
,
如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient
。