服务发现
在任何分布式架构中,都需要找到机器所在的物理地址,这个概念子分布式计算开始出现就已经存在,并且正式成为服务发现。
服务发现对于微服务的好处
1.可以快速对在环境中运行的服务实例数量进行水平伸缩。通过服务发现服务消费者能将服务的物理位置抽象出来。由于服务消费之不知道实际服务实例的物理位置,因此可以从可用服务中添加或者移除服务实例。
水平伸缩:增加服务器数量 垂直伸缩:提高硬件性能
2.有助于提高程序的弹性。 当微服务实例变的不健康或者不可用时,大多数服务发现引擎姜葱内部可用服务列表中移除该实例。由于服务发现引擎会在路由服务是绕过不可用服务因此能够使不可用服务造成的伤害降到最小。
服务位置定位方式对比
非云服务
位置服务解析通常由DNS和网络负载均衡器的组合来实现。
- 应用程序使用通过DNS和特定于服务的路径来调用服务
- 负载均衡器查找托管服务的服务器地址 为了实现高可用通常会设置辅助负载均衡器监控主负载均衡器的状态,在主负载均衡器发生故障时进行接管。
- 服务的实例被部署到一个或者多个应用服务器。这些应用程序服务器的数量往往是静态的(托管服务的应用程序服务器的数量并没有增加和减少)和持久的(将崩溃的服务器恢复,会有和崩溃之前相同的IP配置)。
对于基于云的微服务应用程序来说,这模型并不适用,主要原因:
- 单点故障 负载均衡器是应用程序基础设施中的集中式阻塞点,如果负载均衡器出现故障,那么依赖它的每个应用程序将不可用
- 有限的水平可伸缩性 在服务集中到单个负载均衡器集群(主备)的情况下,跨多个服务器水平伸缩负载均衡基础设施的能力有限
- 静态管理 大多数传统的负载均衡器不是为快速注册和注销服务设计的。使用集中式数据库来储存规则来储存规则的路由。
- 复杂 新服务实例的注册是手动完成的,不是在新服务实例启动时完成的。
云中的服务发现
基于云的微服务环境的解决方案是使用服务发现机制,这一机制具有以下特点:
- 高可用 支持“热”集群环境,在服务发现集群中可以跨多个节点共享服务查找。如果一个节点变得不可用,集群中的其他节点能够接管工作。
- 点对点 服务发现集群中的每个节点共享服务实例的状态。
- 负载均衡 服务发现需要在所有服务实例之间动态地对请求进行负载均衡,以确保服务调用分布(均匀)在由它管理的所有服务实例上。
- 有弹性 服务发现客户端在本地“缓存”信息。本地缓存允许服务发现能够逐步降级,这样服务发现服务不可用是,应用程序仍可以基于本地缓存维护的信息来运行和定位服务。
- 容错 对服务实例检测,在没有人为干预的情况下,处理故障节点。
服务发现架构
- 服务注册
- 服务地址的客户端查找
- 信息共享
- 健康检测
客户端应用程序从来不直接知道服务的 IP 地址。它们从一个服务发现代理获取
- 服务位置可以由服务发现代理的逻辑名称查找。
- 当一个服务上线时,它会用一个服务发现代理注册它的 IP 地址。
- 服务发现节点彼此共享服务实例健康信息.。
- 服务向服务发现代理发送一个心跳。如果服务死亡,服务发现层将删除“死”实例的 IP。
更健壮的客户端负载均衡
![](https://i-blog.csdnimg.cn/blog_migrate/a6924b3b47b26d4820875f61765d1973.png)
在服务消费者需要调用一个服务时:
- 检查本地缓存的服务实例 IP。服务实例之间的负载均衡将发生在服务上。
- 如果客户端在缓存中找到服务 IP,它将使用它。否则,它将定位到服务发现。通常服务端缓存使用简单的“轮询”负载均衡算法,以确保夫妇调用分布在多个服务实例之间。
- 客户端缓存将周期性地被服务发现层刷新。
如果在调用服务的过程中,服务调用失败,那么本地的服务发现缓存失效,服务发现客户端将尝试从服务发现代理刷新数据。
使用服务发现查找服务
- Spring DiscoveryClient ——使用DiscoveryClient标准和SpringRestTemplate类来调用组织服务。
- 启用了RestTemplate的Spring DiscoveryClient——使用增强的Spring RestTemplate来调用基于Ribbon的服务。
- NetFlix Feign——使用Fegin客户端来通过Ribbon调用服务。
可以通过上述三个库(级别由低到高)和Ribbon交互
DiscoveryClient与实际运用
- 在实际运用中,只有在服务需要查询Ribbon以了解那些服务和服务实例已经通过它注册是,才应该直接使用DiscoveryClient。没有利用Ribbon客户端负载均衡——尽管通过直接调用DiscoveryClient可以获得服务列表,但是调用哪些返回的实例就成了开发人员的责任。
- 开发人员必须构建一个来调用服务的URL。尽管这是一件小事,但是编写的代码越少就意味着需要调试的代码越少。
Eureka Server配置文件
Eureka服务注册的细节 来源参考:baike.renwuyi.com/2016-12/18938.html
1、在Eureka平台中,如果某台服务器宕机,Eureka不会有类似于ZooKeeper的选举leader的过程;客户端请求会自动切换到新的Eureka节点;当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中;而对于它来说,所有要做的无非是同步一些新的服务注册信息而已。所以,再也不用担心有“掉队”的服务器恢复以后,会从Eureka服务器集群中剔除出去的风险了。Eureka甚至被设计用来应付范围更广的网络分割故障,并实现“0”宕机维护需求。(多个zookeeper之间网络出现问题,造成出现多个leader,发生脑裂)当网络分割故障发生时,每个Eureka节点,会持续的对外提供服务(注:ZooKeeper不会):接收新的服务注册同时将它们提供给下游的服务发现请求。这样一来,就可以实现在同一个子网中(same side of partition),新发布的服务仍然可以被发现与访问。
2、正常配置下,Eureka内置了心跳服务,用于淘汰一些“濒死”的服务器;如果在Eureka中注册的服务,它的“心跳”变得迟缓时,Eureka会将其整个剔除出管理范围(这点有点像ZooKeeper的做法)。这是个很好的功能,但是当网络分割故障发生时,这也是非常危险的;因为,那些因为网络问题(注:心跳慢被剔除了)而被剔除出去的服务器本身是很”健康“的,只是因为网络分割故障把Eureka集群分割成了独立的子网而不能互访而已。
幸运的是,Netflix考虑到了这个缺陷。如果Eureka服务节点在短时间里丢失了大量的心跳连接(注:可能发生了网络故障),那么这个Eureka节点会进入”自我保护模式“,同时保留那些“心跳死亡“的服务注册信息不过期。此时,这个Eureka节点对于新的服务还能提供注册服务,对于”死亡“的仍然保留,以防还有客户端向其发起请求。当网络故障恢复后,这个Eureka节点会退出”自我保护模式“。所以Eureka的哲学是,同时保留”好数据“与”坏数据“总比丢掉任何”好数据“要更好,所以这种模式在实践中非常有效。
3、Eureka还有客户端缓存功能(注:Eureka分为客户端程序与服务器端程序两个部分,客户端程序负责向外提供注册与发现服务接口)。所以即便Eureka集群中所有节点都失效,或者发生网络分割故障导致客户端不能访问任何一台Eureka服务器;Eureka服务的消费者仍然可以通过Eureka客户端缓存来获取现有的服务注册信息。甚至最极端的环境下,所有正常的Eureka节点都不对请求产生相应,也没有更好的服务器解决方案来解决这种问题
时;得益于Eureka的客户端缓存技术,消费者服务仍然可以通过Eureka客户端查询与获取注册服务信息,这点很重要。
4、Eureka的构架保证了它能够成为Service发现服务。它相对与ZooKeeper来说剔除了Leader节点的选取或者事务日志机制,这样做有利于减少使用者维护的难度也保证了Eureka的在运行时的健壮性。而且Eureka就是为发现服务所设计的,它有独立的客户端程序库,同时提供心跳服务、服务健康监测、自动发布服务与自动刷新缓存的功能。但是,如果使用ZooKeeper你必须自己来实现这些功能。Eureka的所有库都是开源的,所有人都能看到与使用这些源代码,这比那些只有一两个人能看或者维护的客户端库要好。
5、维护Eureka服务器也非常的简单,比如,切换一个节点只需要在现有EIP下移除一个现有的节点然后添加一个新的就行。Eureka提供了一个web-based的图形化的运维界面,在这个界面中可以查看Eureka所管理的注册服务的运行状态信息:是否健康,运行日志等。Eureka甚至提供了Restful-API接口,方便第三方程序集成Eureka的功能。
关于使用Spring和Netflix Eureka实现服务注册
参见史上最简单的 SpringCloud 教程 | 第一篇: 服务的注册与发现(Eureka)(Finchley版本)
总结
- 服务发现模式用于抽象服务的物理位置。
- 注入Eureka这样的服务发现引擎可以在不影响客户端的情况下,无缝地向环境中添加和从环境中移除服务的实例。
- 通过在服务调用的客户端中缓存服务的物理位置,客户端负载均衡可以提供额外的性能和弹性。
- Eureka是Netflix项目,在与SpringCloud一起使用时,很容易对Eureka进行建立和配置。