[关闭]
@Seymour 2018-08-02T19:07:36.000000Z 字数 7419 阅读 1254

Spring Cloud网关技术

SpringCloud


1.引言
1.1背景
智慧消防综合平台采用前后端分离架构,业务层面拆分为WebApp API项目、SignalR Server项目、ReportWeb API项目等,客户端为Web浏览器访问静态资源。该方案中,没有达到微服务的要求,没有具备服务治理、断路、负载均衡等特性。

1.2项目改善目的
通过使用微服务架构将单一的应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,如我们的WebApp API、 SignaR Server、 ReportWeb API独立运行。基于业务功能,使用合理的粒度划分服务,每个服务或API只关注一个特定的功能,使其业务逻辑更加清晰,开发和维护相对简单。
围绕业务能力构建并且可通过全自动部署机制独立部署,对于其中的某一个API而言,若对其进行了修改,只需要重新部署这个服务即可,降低对其他服务的依赖性。同时若其中的某个服务遇到了瓶颈,可以结合该服务的特点来适当增加内存,升级CPU或增加节点。
使用集中式的管理,现阶段我们开发的不同API对应不同的网络地址,由前端中的配置文件统一管理,如下图左所示,当给其中某个服务备份或增加新的服务时,配置文件都需要重新修改,这样增加了客户端的复杂性,降低了程序的灵活性。我们引入微服务网关来封装应用程序的内部结构,配置文件只需要配置网关的属性即可,客户端只与网关交互,而无须直接调用特定微服务的接口,使开发更加简化,如下图右所示。同时为提高程序的稳定性,防止某个服务不可用,可对每个服务设置多个副本,此时就需要引入负载均衡器来实现合理的分配调度,而在网关上加入负载均衡也较容易实现。

图1-1:加入网关前后的比较

1.3功能与优势
服务网关是微服务架构中一个不可或缺的部分。服务网关为微服务架构提供了前门保护的作用,使得服务集群主体能够具备更高的可复用性和可测试性。
1.4内容简介
Spring Cloud是java平台提供的一套解决方案,目前市面上来说可能不是最好的微服务解决方案,但是一定是功能最齐全最全的解决方案。提供了微服务的基础功能,包括服务治理、负载均衡、断路器、配置中心、API网关等。
2.搭建服务组件
使用Eureka搭建注册服务中心。
使用zuul搭建服务路由网关 。
使用客户端组件升级.NET CORE项目,工程添加 Pivotal.Discovery.Client 组件,添加注册方法和配置。

3.服务发现
服务注册与发现对于微服务系统来说非常重要,有了服务发现与注册,就不需要经常更改服务调用的配置文件,只需要使用服务的标识符,就可以访问到服务。
1.各个微服务在启动时,将自己的网络地址等信息注册到服务发现组件中,服务发现组件会存储这些信息。
2.服务消费者可以从服务发现组件查询服务提供者的网络地址,并使用该地址调用服务提供者的接口。
3.各个微服务与服务发现组件使用一定机制通信,服务发现组件若长时间无法与微服务实例通信,就会注销该实例。

3.1服务注册中心
服务注册中心是服务发现的关键部分,它是一个包含了服务实例网络位置的数据库。服务注册中心必须是高可用和最新的,虽然客户端可以缓存从服务注册中心获得的网络位置,但该信息最终会过期,客户端将无法发现服务实例。因此服务注册中心由使用了复制协议来维护一致性的服务器集群组成。

3.2Eureka简介及原理
Eureka是Netflix开源的服务发现组件,本身是一个基于REST的服务。它包含了Server和Client两部分,Spring Cloud将它集成在子项目Spring Cloud Netflix中,从而实现微服务的注册与实现。

图1-2:eureka 的基本原理
Eureka Server 提供服务发现的能力,各个微服务启动时,会向Eureka Server注册自己的信息(例如IP,端口,微服务名等),Eureka Server会存储这些信息。
Eureka Client 是一个Java客户端,用于简化与Eureka Server的交互。
微服务启动后,会周期性的(默认30秒)向Eureka Server发送心跳以续约自己的“租期”。
eureka.instance.leaseRenewalIntervalInSeconds
如果Eureka Server在一定时间内没有接受到某个微服务的心跳,Eureka Server将会注销该实例(默认90秒)。
eureka.instance.leaseExpirationDurationInSeconds
默认情况下,Eureka Server同时也是Eureka Client。相互注册,互相之间通过复制的方式,来实现服务注册表中数据的同步。

3.3Eureka集群高可用配置
Eureka Server间已经相互注册,则eureka的客户端添加service-url时,只需要写一个server就可以,倘若client端配置了所有server的地址,则每当server增加或删除了一个服务后,client就需要随之改变。
微服务只配置到Eureka Server 集群中的单个节点与多个节点,经过测试,启动后效果是一样的,并且当被注册的Server节点发生故障时,其他节点能够正常提供服务。但若将服务重新启动注册时,会出现问题。避免极端情况,应配置多个Server节点,这样当其中的一个server挂掉之后,其他server还能继续提供注册发现的服务,这样就避免了单点故障后的整体服务发现的瘫痪。

3.4Eureka的自我保护模式
默认情况下,Eureka Server 在一定时间内没有接受到某个微服务实例的心跳,Eureka将会注销该实例,但若是网络分区故障时,微服务与Eureka Server 之间无法正常通信,这种行为就很危险,因为此时微服务本身是很健康的。
Eureka 通过“自我保护模式”来解决这个问题,当Eureka Server节点在短时间内丢失过多client时,那么这个节点就会进入自我保护模式,此时Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(即不注销任何服务),当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
1、Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
2、Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

4.负载均衡
4.1服务端负载均衡
负载均衡是我们处理高并发,缓解网络压力和进行服务端扩容的重要手段,但一般情况下我们所说的负载均衡通常都是指服务端负载均衡,服务端负载均衡主要分为两种,一种是硬件负载均衡,另一种是软件负载均衡。
硬件负载均衡主要通过在服务节点间安装专门用于负载均衡的设备
软件负载均衡主要在服务器上安装一些具有负载均衡功能的软件来完成请求分发进而实现负载均衡,常见的是Nginx。
无论是硬件负载均衡还是软件负载均衡都会维护一个可用的服务端清单,然后通过心跳机制来删除故障的服务端点以保证清单中都是可以正常访问的服务端节点,此时当客户端的请求到达负载均衡服务器时,负载均衡服务器按照某种配置好的规则从可用服务端清单中选出一台服务器去处理客户端的请求。
4.2客户端负载均衡
首先要指出的是此处的“客户端”并不是通常的终端(如浏览器等),而是一个微服务,但该微服务需要调用其他的微服务。客户端负载均衡与服务端负载均衡最大的区别在于服务清单所存储的位置。在客户端负载均衡中,所有的客户端节点都有一份自己要访问的服务端清单,这些清单统统都是从Eureka服务注册中心获取。Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当我们将Ribbon和Eureka一起使用时[负载],Ribbon会从Eureka注册中心去获取服务端列表,然后进行轮询访问以达到负载均衡的作用。

4.3Ribbon
Ribbon是Netflix发布的负载均衡器,有助于控制HTTP和TCP客户端的行为,当我们为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多的负载均衡算法,如轮询,随机等。

5.微服务的容错处理
5.1容错的必要性及处理方式
微服务架构的应用系统通常包含多个服务层,微服务之间通过网络进行通信,从而支撑起整个应用系统,因此,微服务之间难免存在依赖关系。网络往往很脆弱,因此难免有些请求会失败。我们常把“基础服务故障”导致“级联故障”的现象称为雪崩效应,即提供者不可用导致消费者不可用,并将不可用逐渐放大的过程。
为防止雪崩效应,必须有一个强大的容错机制,主要实现以下两点:
为网络请求设置超时:正常情况下,一个远程调用一般在几十毫秒内就能得到响应,如果依赖的服务不可用或者网络有问题,那么响应时间就会变得很长。同时,一次远程调用对应着一个线程/进程,如果响应太慢,这个线程/进程就得不到释放,而线程/进程又对应着系统资源,如果得不到释放的线程/进程越积越多,资源就会逐渐被耗尽,最终导致服务崩溃。
使用短路器模式:如果对某个微服务的请求有大量超时,再去让新的请求访问该服务已经没有任何意义,只会无谓消耗资源。设置了超时时间为1秒,如果短时间内有大量的请求无法在1秒内得到响应,就没有必要再去请求依赖的服务了。断路器也可自动诊断依赖的服务是否已经恢复正常,如果发现依赖的服务已经恢复正常,就会恢复请求该服务。
5.2Hystrix的主要作用
Hystrix是一个实现了超时机制和断路器模式的工具类库,主要作用有:
跳闸机制:当某服务的错误率超过一定阈值时,Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功,失败,超时以及被拒绝的请求。
回退机制:当请求失败,超时,被拒绝或当断路器打开时,执行回退逻辑。回退逻辑可由开发人员自行提供,例如返回一个缺省值。
自我修复:断路器打开一段时间后,会自动进入“半开”状态。

5.3Hystrix的断路,回退机制
以某个微服务为例,可在Controller中添加一个回退方法,该回退方法与原方法具有相同的参数和返回值类型。具体操作是在原方法的上方使用@HystrixCommand的fallbackMethod属性,即指定回退方法名。
当请求失败,被拒绝,超时或者断路器打开时,都会进入回退方法,但进入回退方法并不意味着断路器已经被打开。 断路器的状态会暴露在Actuator提供的/health中,我们可通过查看程序的健康指标来直观的了解断路器的状态。
在我们添加了回退方法时,同时访问请求失败,此时程序能够执行回退方法,但此时Hystrix中断路器状态依然是Up, 这是因为失败率还没有达到阈值(默认是5秒20次失败)当我们持续快速刷新页面时,再次打开健康指标栏可看到hystrix的状态为CIRCUIT_OPEN。
6.微服务网关
微服务网关是介于客户端和服务端之间的中间层,所有外部请求都会先经过微服务网关。

图4-1:通过微服务网关请求不同的服务

优点:
易于监控:可在微服务网关收集监控数据并将其推送到外部系统进行分析。
易于认证:可在微服务网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
减少了客户端与各个微服务之间的交互次数

6.1Zuul的核心—过滤器的功能
Zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能:
身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求
审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
动态路由:动态地将请求路由到不同的后端集群
压力测试:逐渐增加指向集群的流量,以了解性能
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群。
多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB使用的多样化,以及让系统的边缘更贴近系统的使用者。

Zuul作为网关层,自身也是一个微服务,跟其他服务一样都注册在eureka server上,默认情况下,Zuul会代理所有注册到Eureka Server的微服务。其路由规则如下:http://ZUUL_HOST:ZUUL_POST/微服务在Eureka上的serviceId/ //会被转发到serviceId对应的微服务。

6.2Zuul实现动态路由

图4-2:常见的路由架构

上图是一个没有网关参与的典型的互联网架构。下图加入Zuul作为网关层,自身也是一个微服务,与其他服务Service1,Service2,… ,ServiceN一样,都注册到eureka server上,可以相互发现,zuul能感知到哪些服务在线,同时通过配置路由规则,可以将请求自动转发到指定的后端微服务上,对于一些公用的预处理(如:权限认证,token合法性校检等),可以放在过滤器里,这样后端服务后续如果新增了服务,zuul层几乎不用修改。
图4-2:zuul作为网关访问注册中心上的各个微服务
6.3Zuul中过滤器的类型
Zuul大部分功能都是通过过滤器来实现的。Zuul中定义了四种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期
(1)PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证,在集群中选择请求的微服务,记录调试信息等。
(2)ROUTING: 这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
(3)POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header,收集统计信息和指标,将响应从微服务发送给客户端等。
(4)ERROR:在其他阶段发生错误时执行该过滤器。
6.4Zuul的高可用与负载均衡
1.zuul客户端注册到Eureka Server上:此种情况下,zuul的高可用实现比较简单,只需要将多个zuul节点注册到Eureka Server,就可实现zuul高可用,此时,zuul与其他的微服务高可用没啥区别。zuul客户端会自动从Eureka Server中查询zuul Server的列表,并使用Ribbon负载均衡的请求zuul集群。

图4-3:zuul高可用架构图1
2.Zuul客户端未注册到Eureka上:因为微服务可能被其他微服务调用,也可能直接被终端调用,此种情况下,我们需要借助额外的负载均衡器来实现zuul的高可用,比如Nginx等。

图4-4:zuul高可用架构图2

zuul实现负载均衡比较简单,使用serviceID进行绑定后,如果有多个相同的serviceID,则会进行轮询的方式进行访问。

6.5Zuul的容错与回退
在Spring Cloud中,zuul默认已经整合了Hystrix。zuul的Hystrix监控的粒度是微服务,而不是某个API。当某个服务出现异常时,通过为zuul添加回退机制来直接返回我们预设的信息。
具体实现:想要为zuul添加回退,只需要实现ZuulFallbackProvider接口,在实现类中首先使用getRoute方法来指定为哪个服务提供回退,并使用getBody方法来添加回退内容。还可定义回退状态。

6.6超时处理
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds设置thread和semaphore两种隔离策略的超时时间,默认值1000毫秒。
可以通过CommandKey设置不同微服务的超时时间,对于zuul而言,CommandKey就是service id。
hystrix.command.[CommandKey].execution.isolation.thread.timeoutInMilliseconds
6.7敏感的Header设置
通常来讲,可在同一个系统中的服务之间共享Header,不过应尽量防止让一些敏感的Header外泄,因此,很多场景下,需要通过为路由指定一系列敏感Header列表。例如设置:
zuul.routes.microserviceUser.sensitive-headers: Cookie,Set-Cookie, Authorization
可以为microserviceUser微服务指定敏感Header 了。
也可用zuul.sensitive-headers全局指定敏感Header,例如
zuul.sensitive-headers:Cookie, Set-Cookie, Authorization #默认情况是Cookie, Set-Cookie, Authorization
在这里,我们实际的使用过程中,因为涉及到身份认证。

7.实际配置过程
7.1服务器中搭建的框架
在测试阶段,对于网关,注册中心,微服务,我们在同一台机器上配置如下图所示的伪分布式集群,对应的端口号如图中所示,实际的配置文件上传到git仓库中。

7.2实际搭建时遇到的问题
在Linux上搭建分布式环境时,当注册中心与服务A不在同一台机器上时通过网关不能定位到服务A,后查找原因,服务在注册中心上注册的名称是:服务A所在的主机名+服务A的名称+端口号,正确的显示应该是:服务A所在主机的IP+服务A的名称+端口号,分析原因,可能是服务A注册到注册中心上的名称不能够被识别,然后更改服务A的配置属性eureka.instance.prefer-ip-address=true,该属性目的是让服务在注册中心上注册时使用其真实的IP,而不是主机名。但通过这种方式仍不能解决问题,后续在注册中心所在的机器上添加服务A所在主机的ip和机器名从而解决问题。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注