服务注册发现之Eureka

Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现,并且也经受住了Netflix自己的生产环境考验。另外和Spring Cloud无缝集成,Spring Cloud还有一套非常完善的开源代码来整合Eureka,所以使用起来非常方便。在认识Eureka时需要理解如下术语,下面是官网提供的Eureka架构图。

服务注册发现之Eureka_第1张图片

Register(服务注册):把自己的IP和端口注册给Eureka。
Renew(服务续约):发送心跳包,每30秒发送一次,告诉Eureka自己还活着。Eureka Server在一定的时间(默认90秒)未收到客户端的心跳,则认为服务宕机,注销该实例。
Cancel(服务下线):当provider关闭时会向Eureka发送消息,把自己从服务列表中删除,防止consumer调用到不存在的服务。
Get Registry(获取服务注册列表):获取其他服务列表。
Replicate(集群中数据同步):eureka集群中的数据复制与同步,eureka服务采用集群部署时涉及
Make Remote Call(远程调用):完成服务的远程调用。

上面是对Eureka的一些基本概念理解,接下来通过实际例子(demo例子来源于bobo微课)看看如何在spring-cloud中使用Eureka和Ribbon完成服务注册、发现以及负载均衡。如果要启动一个Eureka server非常简单,首先在pom.xml文件中引入eureka-server的依赖。

在应用入口加入"@EnableEurekaServer",说明该服务是一个Eureka server。

服务注册发现之Eureka_第2张图片

在application.properties中添加相关配置,其中eureka相关的两个配置都是Eureka-client的配置,现在是启动Eureka-server,所有都设置成false。

spring.application.name=discovery-server
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
server.port=8761

 通过前面三个配置就完成了一个简单的Eureka server,启动后,即可看到Eureka的UI界面。对于Eureka-client,也就是业务应用的服务提供方和服务消费方,如果要使用Eureka完成服务的注册与发现,那么首先也是在pom.xml文件中添加eureka-client的依赖。

在应用启动的入口加入"@EnableDiscoveryClient" 

在application.properties上添加相关配置,后面会专门介绍各个配置项作用。

服务提供方
spring.application.name=time-service
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
server.port=5555
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
服务消费方
spring.application.name=time-client
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.client.register-with-eureka=false

对于服务消费方来说,如果要实现负载均衡,那么还需要添加"@LoadBalanced",Ribbon提供多种负载均衡策略,默认是轮询的负载均衡策略,Ribbon也支持自定义负载均衡策略以及配置其他类型的负载均衡策略。

这样就完成了服务提供方和服务调用方的配置,按demo说明的步骤,启动Eureka service和time-service和time-client后,在Eureka service的UI界面上,就可以看到注册上去的time-service服务信息,之前在配置文件定义的instance-id名称就是Status列下显示的名称。

服务注册发现之Eureka_第3张图片

time-client服务是启动在8080端口,在浏览器上访问time-client服务,会看到轮训调用后端的time-service服务,这说明Ribbon提供的软负载生效。

服务注册发现之Eureka_第4张图片

在客户端访问后端服务的url中,是通过注册在服务中心的服务名称来访问后端服务的。

通过上面这个小例子可以看到要利用Eureka进行服务注册与发现非常简单,上面的例子中涉及了一些配置信息,下面整理了Eureka相关的配置并对每项配置进行简要说明。

除了上面列举的配置,Eureka还有个是否启动自我保护的配置(eureka.server.enable-self-preservation),那么什么是自我保护呢?默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。自我保护机制的工作机制是:如果在15分钟内超过 85% 的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server 自动进入自我保护机制,此时会出现以下几种情况:

Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

前面提到Ribbon在做负载均衡时,默认采用轮询的负载均衡策略,实际Ribbon 还支持如下的负载均衡策略。

  • 轮询策略 RoundRobinRule 
  • 权重轮询策略 WeightedResponseTimeRule:根据每个provider的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。一开始为轮询策略,开启计时器,每隔30s收集一次每个provider的平均响应时间,根据响应时间给每个provider增加权重值,权重越高,被选中的概率越高。
  • 随机策略:RandomRule
  • 最少并发数策略 BestAvailableRule :选择正在请求中的并发数最小的provider,除非这个provider在熔断中。

如果要修改成其他负载均衡策略,那么需要添加新的负载均衡策略的Class

服务注册发现之Eureka_第5张图片

在application.properties文件中设置新的负载均衡策略

这样再通过time-client访问time-service的时候就会发现是随机模式了。上面的例子演示的是一个Eureka服务的情况,接下来看看如果是部署多个Eureka服务,如何进行配置,因为只有电脑本机,所有通过配置host文件来模拟启动了多台Eureka服务,demo地址。如果是多个Eureka服务,那么在Eureka client的application.properties上用逗号隔开多个Eureka服务信息。

 在Eureka的UI上也可以看到有两个Eureka服务。

服务注册发现之Eureka_第6张图片

 上一个例子服务消费方是通过@LoadBalanced获取服务信息,调用服务的,实际还可以直接使用discoveryClient获取服务信息列表,然后调用服务。

服务注册发现之Eureka_第7张图片

在实际项目中使用Ribbon时,需要注意一点Ribbon存在感知延迟的情况,具体的延迟主要发送在:注册延迟(30s),Eureka服务响应延迟(30s),Eureka客户端更新延迟(30s),Ribbon服务列表更新延迟(30s)。最大的延迟可能达到2分钟,在调试过程中遇到这种情况是正常现象。

另外,如果采用Eureka+Ribbon来做蓝绿部署或者滚动发布等,因为Ribbon对服务感知有延迟,所以如果强行将服务实例拉出,因为Ribbon感知延迟,可能会继续将请求往已经下线的服务上发送,如何解决这个问题,这里需要使用Eureka提供的服务拉出和拉入的接口来平滑的将服务从注册中心拉出。具体如下所示:PUT是将服务从注册中心拉出的接口,DELETE是将拉出的服务重新注册到服务注册中心的接口。

 上面例子介绍了Eureka和Ribbon如何配置使用,接下来看看如何引入Zuul,demo地址。最后一个例子涉及的服务如下图所示:

服务注册发现之Eureka_第8张图片

后端服务hello client和Hello service都注册到了Eureka服务上,因为Hello client要被zuul调用,而hello server要被hello client调用。Eureka服务的UI上注册的服务如下所示:

下面是zuul的配置,因为zuul需要通过服务注册中心发现hello-client,所以配置了Eureka的serviceUrl等信息。另外配置了zuul的路由规则routes。

服务注册发现之Eureka_第9张图片

zuul启动后的端口是8079,通过zuul访问hello-client,调用hello/client的过程实际是zuul调用hello-client,hello-client再调用hello-server服务。/hello/server是直接配置的url实现的调用。

服务注册发现之Eureka_第10张图片

以上就是zuul+Eureka+Ribbion的例子。接下来我们总结下微服务架构中服务发现和负载均衡的不同方式(备注以下的总结来自bobo微课)

方式一:集中代理模式,搭建代理服务器,代理服务器负责服务发现和负载均衡。例如可以使用f5+nginx配合作为集中代理,nginx上配置路由规则等完成负载均衡。

方式二:服务注册中心+客户端嵌入式代理,需要独立的服务注册中心服务,例如使用Eureka,由服务消费方完成服务发现和负载均衡,例如使用Ribbon,服务消费方和负载均衡在同一个进程上

方式三:主机独立进程代理,服务发现和负载均衡在服务消费方完成,但是和服务消费方不在同一个进程,是由单独的进程来完成,例如使用Istio。

以下是对三种模式的简单比较,具体项目中还需结合实际情况选择具体采用那种方式完成服务发现与负载均衡。

服务注册发现之Eureka_第11张图片

 另外,对于模式一集中式代理方式,也有一些变体使用。例如如下所示,有集中代理服务,也引入了服务注册中心,这种模式和上面的演示例子三比较像,zuul+Eureka+Ribbon结合使用的例子。

服务注册发现之Eureka_第12张图片

上面这种变体为了实现服务的自注册,如果是已有的应用,需要对应用代码进行修改,对代码有侵入性,所以有些项目也会采用第二种变体。调用服务注册中心提供的接口将服务注册中注册中心,而不是自注册方式,这种方式的优点是无需对原有服务代码进行任何修改。

服务注册发现之Eureka_第13张图片

以上就是对微服务中服务注册发现与负载均衡的理解。

你可能感兴趣的:(微服务,eureka,spring,cloud)