跳转到内容

eureka 服务治理

服务发现的由来

从架构部署的角度

单体架构应用的服务自成一体,大多不需要以来其他外部服务,但是有些也需要依赖外部服务,此时使用配置域名的方式,直接访问即可。

到了soa架构时代,服务化的架构内部依赖比较多,主要通过两种方式实现服务发现:

  1. 服务消费者配置服务生产者的 upstream。这样的缺点是服务消费者耦合了服务生产者的实现细节,例如,服务生产者需要添加一台主机,那么就需要服务消费者修改配置。
  2. 服务生产者提供统一的内网域名。这样,如果服务生产者需要添加一台主机,只需要在自己的前置机上添加一个 ip 地址即可。

再往后发展,到了微服务时代,随着 docker 的流行,底层运维方式发生了巨大变化,业务不在部署在固定的虚拟机上,ip 也不会一成不变。这时候,前面的方案就有些捉襟见肘了。但针对这个问题,不同的思考方式提供了不同的解决方案,下面列举几个:

  1. 以 ng 为例,直接手工或通过脚本方式,在部署的时候直接更新 ng 的配置文件,然后在 reload。或者是使用 ngx_http_dyups_module 通过 rest api 在运行时直接更新 upstream,而不需要 reload。
  2. 直接把服务注册中心作为一个标配的分布式服务组件引入系统,网关组件从服务注册中心获取相关服务的示例信息,从而达到动态路由。

从开发实现的角度

随着架构的发展,单体应用逐步过渡为微服务应用,服务之间的依赖会越来越多。假设团队 b、c、d 的服务需要团队 a 的服务提供接口,那么团队 a 中的服务就需要提供给团队 b、c、d 一个接口地址,此时如果团队 b 需要团队 a 提供一个新的接口地址,那么团队 a 就需要修改代码,同时团队 c 或 d 也需要提供一个新的接口地址,则团队 a 同样需要修改代码。就会出现这样的情况:就是不管团队 b、c、d 哪一个消费者需要增加一个接口或修改一个接口甚至弃用一个接口,抑或是团队 a 的项目需要进行扩容,都需要团队 a 修改自己的代码,这就造成了核心系统频繁修改代码。这其实是一个强耦合的关系,但是如果引入服务发现组件,团队 b、c、d 只需要与服务发现组件进行连接,即可获取团队 a 的代码,这样就可以达到解耦的目的。同时,不论团队 a 的服务扩容还是缩容,对 b、c、d 都不会产生过多影响。

总结

服务发现组件出现的主要目的是为了解决服务与服务间过多依赖形成强耦合关系的问题。随着技术不断演进,服务发现组件的功能也在不断增强,服务组册、服务监测、服务路由、负载均衡、自我保护等功能被引进来,也就逐步形成了服务治理组件的全部功能。

SpringCloud Eureka 简介

产生

由 netflix 公司开源,是为了解决 aws 不提供中间服务层的负载均衡问题而设计开发的。可以提供负载均衡、failover 等支持。之所以产生 eureka 组件,而不使用原有的 AWS Elastic Load Balancer,是因为 WS Elastic Load Balancer 需要暴露地址给外网,这样造成不安全的问题。另外一方面是因为,WS Elastic Load Balancer 是基于代理的负载均衡,无法直接基于服务元数据信息定制负载均衡算法。由此就产生了 eureka。

技术选型

主要介绍 consul 与 eureka 的区别。eureka 服务端采用的是 p2p 的复制模式,不能保证复制操作一定能成功,它提供的是最终一致性的服务实例视图;客户端在服务端的注册信息有一个带期限的租约信息,一旦服务端在指定期限内没有收到客户端的心跳,则服务端就认为客户端组册的服务是不健康的,定时任务就会把客户端组册的服务剔除。consul 采用的是 raft 算法,可以提供强一致性保证,并且 consul 的 agent 相当于 ribbon 和 eureka 客户端,对应用相对透明,同时相对 eureka 的集中式心跳检测机制,consul 的 agent 可以参与到基于 gossip 协议的健康检查,这样分散了服务端的心跳检测压力。此外,eureka 是由 java 编写,consul 由 go 编写;eureka 支持 ap,consul 支持 cp。

但是如果团队选择的是 ap,不是 cp,并且团队是 java 语言体系,对组件的掌控力较强,则可以使用 eureka。此外,eureka 还提供了 restful 风格的 api,可以针对注册到 eureka 上的服务进行操作。

入门案例

  • 创建 pom 工程,引入 SpringCloud、SpringBoot-starter 的相关依赖。
  • 创建 eureka 服务器端工程。
    • 引入依赖
    • 创建主启动类,并在主启动类中添加@EnableEurekaServer 注解,以打开服务器端服务注册开关
    • 修改配置文件,设置 serviceUrl 路径以及其他信息
  • 创建服务生产者工程。
    • 引入依赖
    • 创建主启动类,并在主启动类中添加@EnableDiscoveryClient 注解,打开客户端服务注册开关
    • 修改配置文件,设置 serviceUrl 路径信息与 eureka 服务器端工程一致
    • 书写业务代码,给服务消费者提供服务
  • 创建服务消费者工程。
    • 引入依赖
    • 创建主启动类,并在主启动类中添加@EnableDiscoveryClient 注解,打开客户端服务注册开关
    • 修改配置文件,设置 serviceUrl 路径信息与 eureka 服务器端工程一致
    • 书写业务代码,调用服务消费者提供的服务

此过程不全,需要进行完善。需要补充服务消费者调用服务生产者的配置和调用代码。

REST API

  • 查询实例
    • 查询所有应用实例信息
    • 根据 appid 查询实例信息
    • 根据 appid 及 instanceid 查询实例信息
    • 根据 instanceid 查询实例信息
  • 操作实例
    • 注册新实例
    • 注销实例
    • 暂停、下线实例
    • 恢复实例
    • 发送应用实例心跳数据
    • 修改实例元数据

源码

核心类

  • InstanceInfo:注册的服务实例
  • LeaseInfo:实例的租约信息
  • ServiceInstance:服务的通用信息
  • InstanceStatus:服务实例的状态信息
  • LeaseManager:此接口定义了应用服务实例在服务中心的几个操作方法。
  • LookupService:此接口定义了客户端从服务中心获取服务实例的查询方法
  • InstanceRegistry:
  • AbstractInstanceRegistry
  • PeerAwareInstanceRegistryImpl
  • 。。。

服务的核心操作

  • register
  • cancel
  • renew
  • evict

Eureka 的设计理念

  • 服务实例如何注册到服务中心
    • 本质是服务启动时,调用 Eureka Server 的 REST api 的 register 方法,去注册该应用实例的信息。有两种方法,对 java 应用程序,可以使用 Netflix 的 Eureka Client 封装的 API 调用注册;对于 SpringCloud 的应用,可以使用 spring-cloud-starter-netflix-eureka-client,基于 SpringBoot 的自动化配置,自动实现服务信息的注册。
  • 服务实例如何从服务中心剔除
    • 正常情况下服务实例在关闭应用时,通过钩子的方法或者生命周期回调方法去调用 EurekaServer 的 RESTApi 的 de-register 方法,来剔除自身服务实例的信息。此外为了解决服务实例挂掉或者其他异常信息导致没有及时剔除自身信息的问题,EurekaServer 会要求 Client 端定时续约,即发送心跳,来证明实例实例是正常的,如果租约超过一定时间没有进行续约操作,Eureakserver 就会进行自动删除。

总结

由架构发展演进过程引入服务发现组件,通过 Netflix 公司开源其自研的服务发现组件 eureka 来介绍服务发现组件的主要实现技术,由此引入 eureka 的应用案例,并简单介绍了 eureka 的其他特性。此外,还添加了 eureka 和其他同类产品的对比。

make it come true