冒着被开除的风险也要给你们看看看这份Spring Cloud 总结

2021年09月15日 阅读数:3
这篇文章主要向大家介绍冒着被开除的风险也要给你们看看看这份Spring Cloud 总结,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

 

做者:FrancisQphp

最近项目忙,时间少,偷偷摸摸抽时间给你们整理了一份SpringCloud总结。前端

 

首先我给你们看一张图,若是你们对这张图有些地方不太理解的话,我但愿大家看完我这篇文章会恍然大悟。git

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_客户端

什么是Spring cloud

构建分布式系统不须要复杂和容易出错。Spring Cloud 为最多见的分布式系统模式提供了一种简单且易于接受的编程模型,帮助开发人员构建有弹性的、可靠的、协调的应用程序。Spring Cloud 构建于 Spring Boot 之上,使得开发者很容易入手并快速应用于生产中。github

官方果真官方,介绍都这么有板有眼的。web

我所理解的 Spring Cloud 就是微服务系统架构的一站式解决方案,在平时咱们构建微服务的过程当中须要作如 服务发现注册配置中心消息总线负载均衡断路器数据监控 等操做,而 Spring Cloud 为咱们提供了一套简易的编程模型,使咱们能在 Spring Boot 的基础上轻松地实现微服务项目的构建。算法

Spring Cloud 的版本

固然这个只是个题外话。spring

Spring Cloud 的版本号并非咱们一般见的数字版本号,而是一些很奇怪的单词。这些单词均为英国伦敦地铁站的站名。同时根据字母表的顺序来对应版本时间顺序,好比:最先 的 Release 版本 Angel,第二个 Release 版本 Brixton(英国地名),而后是 Camden、 Dalston、Edgware、Finchley、Greenwich、Hoxton。编程

Spring Cloud 的服务发现框架——Eureka

Eureka是基于REST(表明性状态转移)的服务,主要在AWS云中用于定位服务,以实现负载均衡和中间层服务器的故障转移。咱们称此服务为Eureka服务器。Eureka还带有一个基于Java的客户端组件Eureka Client,它使与服务的交互变得更加容易。客户端还具备一个内置的负载平衡器,能够执行基本的循环负载平衡。在Netflix,更复杂的负载均衡器将Eureka包装起来,以基于流量,资源使用,错误条件等多种因素提供加权负载均衡,以提供出色的弹性。后端

总的来讲,Eureka 就是一个服务发现框架。何为服务,何又为发现呢?缓存

举一个生活中的例子,就好比咱们平时租房子找中介的事情。

在没有中介的时候咱们须要一个一个去寻找是否有房屋要出租的房东,这显然会很是的费力,一你找凭一我的的能力是找不到不少房源供你选择,再者你也懒得这么找下去(找了这么久,没有合适的只能将就)。这里的咱们就至关于微服务中的 Consumer ,而那些房东就至关于微服务中的 Provider 。消费者 Consumer 须要调用提供者 Provider 提供的一些服务,就像咱们如今须要租他们的房子同样。

可是若是只是租客和房东之间进行寻找的话,他们的效率是很低的,房东找不到租客赚不到钱,租客找不到房东住不了房。因此,后来房东确定就想到了广播本身的房源信息(好比在街边贴贴小广告),这样对于房东来讲已经完成他的任务(将房源公布出去),可是有两个问题就出现了。第1、其余不是租客的都能收到这种租房消息,这在现实世界没什么,可是在计算机的世界中就会出现资源消耗的问题了。第2、租客这样仍是很难找到你,试想一下我须要租房,我还须要东一个西一个地去找街边小广告,麻不麻烦?

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_spring_02 那怎么办呢?咱们固然不会那么傻乎乎的,第一时间就是去找 中介 呀,它为咱们提供了统一房源的地方,咱们消费者只须要跑到它那里去找就好了。而对于房东来讲,他们也只须要把房源在中介那里发布就好了。 冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_客户端_03

那么如今,咱们的模式就是这样的了。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_04

可是,这个时候还会出现一些问题。

  1. 房东注册以后若是不想卖房子了怎么办?咱们是否是须要让房东按期续约?若是房东不进行续约是否是要将他们从中介那里的注册列表中移除

  2. 租客是否是也要进行注册呢?否则合同乙方怎么来呢?

  3. 中介可不能够作连锁店呢?若是这一个店由于某些不可抗力因素而没法使用,那么咱们是否能够换一个连锁店呢?

针对上面的问题咱们来从新构建一下上面的模式图

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_05

 

好了,举完这个????咱们就能够来看关于 Eureka 的一些基础概念了,你会发现这东西理解起来怎么这么简单。????????????

服务发现:其实就是一个“中介”,整个过程当中有三个角色:服务提供者(出租房子的)、服务消费者(租客)、服务中介(房屋中介)

服务提供者:就是提供一些本身可以执行的一些服务给外界。

服务消费者:就是须要使用一些服务的“用户”。

服务中介:其实就是服务提供者和服务消费者之间的“桥梁”,服务提供者能够把本身注册到服务中介那里,而服务消费者如须要消费一些服务(使用一些功能)就能够在服务中介中寻找注册在服务中介的服务提供者。

服务注册 Register

官方解释:当 Eureka 客户端向 Eureka Server 注册时,它提供自身的元数据,好比IP地址、端口,运行情况指示符URL,主页等。

结合中介理解:房东 (提供者 Eureka Client Provider)在中介 (服务器 Eureka Server) 那里登记房屋的信息,好比面积,价格,地段等等(元数据 metaData)。

服务续约 Renew

官方解释:Eureka 客户会每隔30秒(默认状况下)发送一次心跳来续约。经过续约来告知 Eureka ServerEureka 客户仍然存在,没有出现问题。正常状况下,若是 Eureka Server 在90秒没有收到 Eureka 客户的续约,它会将实例从其注册表中删除。

结合中介理解:房东 (提供者 Eureka Client Provider) 按期告诉中介 (服务器 Eureka Server) 个人房子还租(续约) ,中介 (服务器Eureka Server) 收到以后继续保留房屋的信息。

获取注册列表信息 Fetch Registries

官方解释:Eureka 客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其余服务,从而进行远程调用。该注册列表信息按期(每30秒钟)更新一次。每次返回注册列表信息可能与 Eureka 客户端的缓存信息不一样, Eureka 客户端自动处理。若是因为某种缘由致使注册列表信息不能及时匹配,Eureka 客户端则会从新获取整个注册表信息。Eureka 服务器缓存注册列表信息,整个注册表以及每一个应用程序的信息进行了压缩,压缩内容和没有压缩的内容彻底相同。Eureka 客户端和 Eureka 服务器可使用JSON / XML格式进行通信。在默认的状况下 Eureka 客户端使用压缩 JSON 格式来获取注册列表的信息。

结合中介理解:租客(消费者 Eureka Client Consumer) 去中介 (服务器 Eureka Server) 那里获取全部的房屋信息列表 (客户端列表 Eureka Client List) ,并且租客为了获取最新的信息会按期向中介 (服务器 Eureka Server) 那里获取并更新本地列表。

服务下线 Cancel

官方解释:Eureka客户端在程序关闭时向Eureka服务器发送取消请求。发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它须要调用如下内容:DiscoveryManager.getInstance().shutdownComponent();

结合中介理解:房东 (提供者 Eureka Client Provider) 告诉中介  (服务器 Eureka Server) 个人房子不租了,中介以后就将注册的房屋信息从列表中剔除。

服务剔除 Eviction

官方解释:在默认的状况下,当Eureka客户端连续90秒(3个续约周期)没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除,即服务剔除。

结合中介理解:房东(提供者 Eureka Client Provider) 会按期联系 中介  (服务器 Eureka Server) 告诉他个人房子还租(续约),若是中介  (服务器 Eureka Server) 长时间没收到提供者的信息,那么中介会将他的房屋信息给下架(服务剔除)。

下面就是 Netflix 官方给出的 Eureka 架构图,你会发现和咱们前面画的中介图别无二致。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_服务器_06Eureka架构图

 

固然,能够充当服务发现的组件有不少:ZookeeperConsulEureka 等。

更多关于 Eureka 的知识(自我保护,初始注册策略等等)能够本身去官网查看,或者查看个人另外一篇文章 深刻理解 Eureka。

负载均衡之 Ribbon

什么是 RestTemplate?

不是讲 Ribbon 么?怎么扯到了 RestTemplate 了?你先别急,听我慢慢道来。

我不听我不听我不听????????????。

我就说一句!RestTemplateSpring提供的一个访问Http服务的客户端类,怎么说呢?就是微服务之间的调用是使用的 RestTemplate 。好比这个时候咱们 消费者B 须要调用 提供者A 所提供的服务咱们就须要这么写。如我下面的伪代码。

@Autowired
private RestTemplate restTemplate;
// 这里是提供者A的ip地址,可是若是使用了 Eureka 那么就应该是提供者A的名称
private static final String SERVICE_PROVIDER_A = "http://localhost:8081";

@PostMapping("/judge")
public boolean judge(@RequestBody Request request) {
    String url = SERVICE_PROVIDER_A + "/service1";
    return restTemplate.postForObject(url, request, Boolean.class);
}

若是你对源码感兴趣的话,你会发现上面咱们所讲的 Eureka 框架中的 注册续约 等,底层都是使用的 RestTemplate

为何须要 Ribbon?

Ribbon  是 Netflix 公司的一个开源的负载均衡 项目,是一个客户端/进程内负载均衡器,运行在消费者端

咱们再举个????,好比咱们设计了一个秒杀系统,可是为了整个系统的 高可用 ,咱们须要将这个系统作一个集群,而这个时候咱们消费者就能够拥有多个秒杀系统的调用途径了,以下图。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_07

若是这个时候咱们没有进行一些 均衡操做 ,若是咱们对 秒杀系统1 进行大量的调用,而另外两个基本不请求,就会致使 秒杀系统1 崩溃,而另外两个就变成了傀儡,那么咱们为何还要作集群,咱们高可用体现的意义又在哪呢?

因此 Ribbon 出现了,注意咱们上面加粗的几个字——运行在消费者端。指的是,Ribbon 是运行在消费者端的负载均衡器,以下图。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_spring_08

其工做原理就是 Consumer 端获取到了全部的服务列表以后,在其内部使用负载均衡算法,进行对多个系统的调用。

Nginx 和 Ribbon 的对比

提到 负载均衡 就不得不提到大名鼎鼎的 Nignx 了,而和 Ribbon 不一样的是,它是一种集中式的负载均衡器。

何为集中式呢?简单理解就是 将全部请求都集中起来,而后再进行负载均衡。以下图。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_服务器_09

咱们能够看到 Nginx 是接收了全部的请求进行负载均衡的,而对于 Ribbon 来讲它是在消费者端进行的负载均衡。以下图。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_10

请注意 Request 的位置,在 Nginx 中请求是先进入负载均衡器,而在 Ribbon 中是先在客户端进行负载均衡才进行请求的。

Ribbon 的几种负载均衡算法

负载均衡,无论 Nginx 仍是 Ribbon 都须要其算法的支持,若是我没记错的话 Nginx 使用的是 轮询和加权轮询算法。而在 Ribbon 中有更多的负载均衡调度算法,其默认是使用的 RoundRobinRule 轮询策略。

  • RoundRobinRule:轮询策略。Ribbon 默认采用的策略。若通过一轮轮询没有找到可用的 provider,其最多轮询 10 轮。若最终尚未找到,则返回 null。

  • RandomRule: 随机策略,从全部可用的 provider 中随机选择一个。

  • RetryRule: 重试策略。先按照 RoundRobinRule 策略获取 provider,若获取失败,则在指定的时限内重试。默认的时限为 500 毫秒。

???????????? 还有不少,这里不一一举????了,你最须要知道的是默认轮询算法,而且能够更换默认的负载均衡算法,只须要在配置文件中作出修改就行。

providerName:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
复制代码

固然,在 Ribbon 中你还能够自定义负载均衡算法,你只须要实现 IRule 接口,而后修改配置文件或者自定义 Java Config 类。

什么是 Open Feign

有了 EurekaRestTemplateRibbon 咱们就能够????愉快地进行服务间的调用了,可是使用 RestTemplate 仍是不方便,咱们每次都要进行这样的调用。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_spring_11

 

这样每次都调用 RestRemplateAPI 是否太麻烦,我能不能像调用原来代码同样进行各个服务间的调用呢?

????????????聪明的小朋友确定想到了,那就用 映射 呀,就像域名和IP地址的映射。咱们能够将被调用的服务代码映射到消费者端,这样咱们就能够 “无缝开发”啦。

OpenFeign 也是运行在消费者端的,使用 Ribbon 进行负载均衡,因此 OpenFeign 直接内置了 Ribbon。

在导入了 Open Feign 以后咱们就能够进行愉快编写  Consumer 端代码了。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_12

而后咱们在 Controller 就能够像原来调用 Service 层代码同样调用它了。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_服务器_13

必不可少的 Hystrix

什么是 Hystrix之熔断和降级

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_客户端_14

在分布式环境中,不可避免地会有许多服务依赖项中的某些失败。Hystrix是一个库,可经过添加等待时间容限和容错逻辑来帮助您控制这些分布式服务之间的交互。Hystrix经过隔离服务之间的访问点,中止服务之间的级联故障并提供后备选项来实现此目的,全部这些均可以提升系统的总体弹性。

整体来讲 Hystrix 就是一个能进行 熔断降级 的库,经过使用它能提升整个系统的弹性。

那么什么是 熔断和降级 呢?再举个????,此时咱们整个微服务系统是这样的。服务A调用了服务B,服务B再调用了服务C,可是由于某些缘由,服务C顶不住了,这个时候大量请求会在服务C阻塞。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_客户端_15

服务C阻塞了还好,毕竟只是一个系统崩溃了。可是请注意这个时候由于服务C不能返回响应,那么服务B调用服务C的的请求就会阻塞,同理服务B阻塞了,那么服务A也会阻塞崩溃。

请注意,为何阻塞会崩溃。由于这些请求会消耗占用系统的线程、IO 等资源,消耗完你这个系统服务器不就崩了么。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_ide_16

这就叫 服务雪崩妈耶,上面两个 熔断降级 你都没给我解释清楚,你如今又给我扯什么 服务雪崩????????????

别急,听我慢慢道来。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_ide_17

不听我也得讲下去!

所谓 熔断 就是服务雪崩的一种有效解决方案。当指定时间窗内的请求失败率达到设定阈值时,系统将经过 断路器 直接将此请求链路断开。

也就是咱们上面服务B调用服务C在指定时间窗内,调用的失败率到达了必定的值,那么 Hystrix 则会自动将 服务B与C 之间的请求都断了,以避免致使服务雪崩现象。

其实这里所讲的 熔断 就是指的 Hystrix 中的 断路器模式 ,你可使用简单的 @HystrixCommand 注解来标注某个方法,这样 Hystrix 就会使用 断路器 来“包装”这个方法,每当调用时间超过指定时间时(默认为1000ms),断路器将会中断对这个方法的调用。

固然你能够对这个注解的不少属性进行设置,好比设置超时时间,像这样。

@HystrixCommand(
    commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1200")}
)
public List<Xxx> getXxxx() {
    // ...省略代码逻辑
}

 

可是,我查阅了一些博客,发现他们都将 熔断降级 的概念混淆了,以个人理解,降级是为了更好的用户体验,当一个方法调用异常时,经过执行另外一种代码逻辑来给用户友好的回复。这也就对应着 Hystrix后备处理 模式。你能够经过设置 fallbackMethod 来给一个方法设置备用的代码逻辑。好比这个时候有一个热点新闻出现了,咱们会推荐给用户查看详情,而后用户会经过id去查询新闻的详情,可是由于这条新闻太火了(好比最近什么*易对吧),大量用户同时访问可能会致使系统崩溃,那么咱们就进行 服务降级 ,一些请求会作一些降级处理好比当前人数太多请稍后查看等等。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_ide_18

什么是Hystrix之其余

我在阅读 《Spring微服务实战》这本书的时候还接触到了一个舱壁模式的概念。在不使用舱壁模式的状况下,服务A调用服务B,这种调用默认的是使用同一批线程来执行的,而在一个服务出现性能问题的时候,就会出现全部线程被刷爆并等待处理工做,同时阻塞新请求,最终致使程序崩溃。而舱壁模式会将远程资源调用隔离在他们本身的线程池中,以即可以控制单个表现不佳的服务,而不会使该程序崩溃。

具体其原理我推荐你们本身去了解一下,本篇文章中对舱壁模式不作过多解释。固然还有 Hystrix 仪表盘,它是用来实时监控 Hystrix 的各项指标信息的,这里我将这个问题也抛出去,但愿有不了解的能够本身去搜索一下。

微服务网关——Zuul

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_ide_19

ZUUL 是从设备和 web 站点到 Netflix 流应用后端的全部请求的前门。做为边界服务应用,ZUUL 是为了实现动态路由、监视、弹性和安全性而构建的。它还具备根据状况将请求路由到多个 Amazon Auto Scaling Groups(亚马逊自动缩放组,亚马逊的一种云计算方式) 的能力

在上面咱们学习了 Eureka 以后咱们知道了 服务提供者消费者 经过 Eureka Server 进行访问的,即 Eureka Server服务提供者 的统一入口。那么整个应用中存在那么多 消费者 须要用户进行调用,这个时候用户该怎样访问这些 消费者工程 呢?固然能够像以前那样直接访问这些工程。但这种方式没有统一的消费者工程调用入口,不便于访问与管理,而 Zuul 就是这样的一个对于 消费者 的统一入口。

若是学过前端的确定都知道 Router 吧,好比 Flutter 中的路由,Vue,React中的路由,用了 Zuul 你会发如今路由功能方面和前端配置路由基本是一个理。???? 我偶尔撸撸 Flutter。

你们对网关应该很熟吧,简单来说网关是系统惟一对外的入口,介于客户端与服务器端之间,用于对请求进行鉴权限流路由监控等功能。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_20

 

没错,网关有的功能,Zuul 基本都有。而 Zuul 中最关键的就是 路由和过滤器 了,在官方文档中 Zuul 的标题就是

Router and Filter : Zuul

Zuul 的路由功能

简单配置

原本想给大家复制一些代码,可是想了想,由于各个代码配置比较零散,看起来也比较零散,我决定仍是给大家画个图来解释吧。

请不要由于我这么好就给我点赞 ???? 。疯狂暗示。

好比这个时候咱们已经向 Eureka Server 注册了两个 Consumer 、三个 Provicer ,这个时候咱们再加个 Zuul 网关应该变成这样子了。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_ide_21

 

emmm,信息量有点大,我来解释一下。关于前面的知识我就不解释了???? 。

首先,Zuul 须要向 Eureka 进行注册,注册有啥好处呢?

你傻呀,Consumer 都向 Eureka Server 进行注册了,我网关是否是只要注册就能拿到全部 Consumer 的信息了?

拿到信息有什么好处呢?

我拿到信息我是否是能够获取全部的 Consumer 的元数据(名称,ip,端口)?

拿到这些元数据有什么好处呢?拿到了咱们是否是直接能够作路由映射?好比原来用户调用 Consumer1 的接口 localhost:8001/studentInfo/update 这个请求,咱们是否是能够这样进行调用了呢?localhost:9000/consumer1/studentInfo/update 呢?你这样是否是恍然大悟了?

这里的url为了让更多人看懂因此没有使用 restful 风格。

上面的你理解了,那么就能理解关于 Zuul 最基本的配置了,看下面。

server:
  port: 9000
eureka:
  client:
    service-url:
      # 这里只要注册 Eureka 就好了
      defaultZone: http://localhost:9997/eureka
复制代码

而后在启动类上加入 @EnableZuulProxy 注解就好了。没错,就是那么简单????。

统一前缀

这个很简单,就是咱们能够在前面加一个统一的前缀,好比咱们刚刚调用的是 localhost:9000/consumer1/studentInfo/update,这个时候咱们在 yaml 配置文件中添加以下。

zuul:
  prefix: /zuul
复制代码

这样咱们就须要经过 localhost:9000/zuul/consumer1/studentInfo/update 来进行访问了。

路由策略配置

你会发现前面的访问方式(直接使用服务名),须要将微服务名称暴露给用户,会存在安全性问题。因此,能够自定义路径来替代微服务名称,即自定义路由策略。

zuul:
  routes:
    consumer1: /FrancisQ1/**
    consumer2: /FrancisQ2/**
复制代码

这个时候你就可使用 localhost:9000/zuul/FrancisQ1/studentInfo/update 进行访问了。

服务名屏蔽

这个时候你别觉得你好了,你能够试试,在你配置完路由策略以后使用微服务名称仍是能够访问的,这个时候你须要将服务名屏蔽。

zuul:
  ignore-services: "*"
复制代码

路径屏蔽

Zuul 还能够指定屏蔽掉的路径 URI,即只要用户请求中包含指定的 URI 路径,那么该请求将没法访问到指定的服务。经过该方式能够限制用户的权限。

zuul:
  ignore-patterns: **/auto/**
复制代码

这样关于 auto 的请求咱们就能够过滤掉了。

** 表明匹配多级任意路径

*表明匹配一级任意路径

敏感请求头屏蔽

默认状况下,像 Cookie、Set-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,咱们能够将这些默认屏蔽去掉,固然,也能够添加要屏蔽的请求头。

Zuul 的过滤功能

若是说,路由功能是 Zuul 的基操的话,那么过滤器就是 Zuul的利器了。毕竟全部请求都通过网关(Zuul),那么咱们能够进行各类过滤,这样咱们就能实现 限流灰度发布权限控制 等等。

简单实现一个请求时间日志打印

要实现本身定义的 Filter 咱们只须要继承 ZuulFilter 而后将这个过滤器类以 @Component 注解加入 Spring 容器中就好了。

在给大家看代码以前我先给大家解释一下关于过滤器的一些注意点。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_spring_22

过滤器类型:Pre、Routing、Post。前置Pre就是在请求以前进行过滤,Routing路由过滤器就是咱们上面所讲的路由策略,而Post后置过滤器就是在 Response 以前进行过滤的过滤器。你能够观察上图结合着理解,而且下面我会给出相应的注释。

// 加入Spring容器
@Component
public class PreRequestFilter extends ZuulFilter {
    // 返回过滤器类型 这里是前置过滤器
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
    // 指定过滤顺序 越小越先执行,这里第一个执行
    // 固然不是只真正第一个 在Zuul内置中有其余过滤器会先执行
    // 那是写死的 好比 SERVLET_DETECTION_FILTER_ORDER = -3
    @Override
    public int filterOrder() {
        return 0;
    }
    // 何时该进行过滤
    // 这里咱们能够进行一些判断,这样咱们就能够过滤掉一些不符合规定的请求等等
    @Override
    public boolean shouldFilter() {
        return true;
    }
    // 若是过滤器容许经过则怎么进行处理
    @Override
    public Object run() throws ZuulException {
        // 这里我设置了全局的RequestContext并记录了请求开始时间
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.set("startTime", System.currentTimeMillis());
        return null;
    }
}
复制代码
// lombok的日志
@Slf4j
// 加入 Spring 容器
@Component
public class AccessLogFilter extends ZuulFilter {
    // 指定该过滤器的过滤类型
    // 此时是后置过滤器
    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }
    // SEND_RESPONSE_FILTER_ORDER 是最后一个过滤器
    // 咱们此过滤器在它以前执行
    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    // 过滤时执行的策略
    @Override
    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        // 从RequestContext获取原先的开始时间 并经过它计算整个时间间隔
        Long startTime = (Long) context.get("startTime");
        // 这里我能够获取HttpServletRequest来获取URI而且打印出来
        String uri = request.getRequestURI();
        long duration = System.currentTimeMillis() - startTime;
        log.info("uri: " + uri + ", duration: " + duration / 100 + "ms");
        return null;
    }
}

上面就简单实现了请求时间日志打印功能,你有没有感觉到 Zuul 过滤功能的强大了呢?

没有?好的、那咱们再来。

令牌桶限流

固然不只仅是令牌桶限流方式,Zuul 只要是限流的活它都能干,这里我只是简单举个????。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_服务器_23

我先来解释一下什么是 令牌桶限流 吧。

首先咱们会有个桶,若是里面没有满那么就会以必定 固定的速率 会往里面放令牌,一个请求过来首先要从桶中获取令牌,若是没有获取到,那么这个请求就拒绝,若是获取到那么就放行。很简单吧,啊哈哈、

下面咱们就经过 Zuul 的前置过滤器来实现一下令牌桶限流。

@Component
@Slf4j
public class RouteFilter extends ZuulFilter {
    // 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -5;
    }

    @Override
    public Object run() throws ZuulException {
        log.info("放行");
        return null;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        if(!RATE_LIMITER.tryAcquire()) {
            log.warn("访问量超载");
            // 指定当前请求未经过过滤
            context.setSendZuulResponse(false);
            // 向客户端返回响应码429,请求数量过多
            context.setResponseStatusCode(429);
            return false;
        }
        return true;
    }
}

 

这样咱们就能将请求数量控制在一秒两个,有没有以为很酷?

关于 Zuul  的其余

Zuul 的过滤器的功能确定不止上面我所实现的两种,它还能够实现 权限校验,包括我上面提到的 灰度发布 等等。

固然,Zuul 做为网关确定也存在 单点问题 ,若是咱们要保证 Zuul 的高可用,咱们就须要进行 Zuul 的集群配置,这个时候能够借助额外的一些负载均衡器好比 Nginx

Spring Cloud配置管理——Config

为何要使用进行配置管理?

当咱们的微服务系统开始慢慢地庞大起来,那么多 ConsumerProviderEureka ServerZuul 系统都会持有本身的配置,这个时候咱们在项目运行的时候可能须要更改某些应用的配置,若是咱们不进行配置的统一管理,咱们只能去每一个应用下一个一个寻找配置文件而后修改配置文件再重启应用

首先对于分布式系统而言咱们就不该该去每一个应用下去分别修改配置文件,再者对于重启应用来讲,服务没法访问因此直接抛弃了可用性,这是咱们更不肯见到的。

那么有没有一种方法既能对配置文件统一地进行管理,又能在项目运行时动态修改配置文件呢?

那就是我今天所要介绍的 Spring Cloud Config

能进行配置管理的框架不止 Spring Cloud Config 一种,你们能够根据需求本身选择(disconf,阿波罗等等)。并且对于 Config 来讲有些地方实现的不是那么尽人意。

Config 是什么

Spring Cloud Config 为分布式系统中的外部化配置提供服务器和客户端支持。使用 Config 服务器,能够在中心位置管理全部环境中应用程序的外部属性。

简单来讲,Spring Cloud Config 就是能将各个 应用/系统/模块 的配置文件存放到 统一的地方而后进行管理(Git 或者 SVN)。

你想一下,咱们的应用是否是只有启动的时候才会进行配置文件的加载,那么咱们的 Spring Cloud Config 就暴露出一个接口给启动应用来获取它所想要的配置文件,应用获取到配置文件而后再进行它的初始化工做。就以下图。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_负载均衡_24

固然这里你确定还会有一个疑问,若是我在应用运行时去更改远程配置仓库(Git)中的对应配置文件,那么依赖于这个配置文件的已启动的应用会不会进行其相应配置的更改呢?

答案是不会的。

什么?那怎么进行动态修改配置文件呢?这不是出现了 配置漂移 吗?你个渣男????,你又骗我!

别急嘛,你可使用 Webhooks ,这是  github 提供的功能,它能确保远程库的配置文件更新后客户端中的配置信息也获得更新。

噢噢,这还差很少。我去查查怎么用。

慢着,听我说完,Webhooks 虽然能解决,可是你了解一下会发现它根本不适合用于生产环境,因此基本不会使用它的。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_服务器_25

而通常咱们会使用 Bus 消息总线 + Spring Cloud Config 进行配置的动态刷新。

引出 Spring Cloud Bus

用于将服务和服务实例与分布式消息系统连接在一块儿的事件总线。在集群中传播状态更改颇有用(例如配置更改事件)。

你能够简单理解为 Spring Cloud Bus 的做用就是管理和广播分布式系统中的消息,也就是消息引擎系统中的广播模式。固然做为 消息总线Spring Cloud Bus 能够作不少事而不只仅是客户端的配置刷新功能。

而拥有了 Spring Cloud Bus 以后,咱们只须要建立一个简单的请求,而且加上 @ResfreshScope 注解就能进行配置的动态修改了,下面我画了张图供你理解。

 

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_ide_26

 

总结

这篇文章中我带你们初步了解了 Spring Cloud 的各个组件,他们有

  • Eureka 服务发现框架

  • Ribbon 进程内负载均衡器

  • Open Feign 服务调用映射

  • Hystrix 服务降级熔断器

  • Zuul 微服务网关

  • Config 微服务统一配置中心

  • Bus 消息总线

若是你能这个时候能看懂下面那张图,也就说明了你已经对 Spring Cloud 微服务有了必定的架构认识。

冒着被开除的风险也要给你们看看看这份Spring Cloud 总结_服务器_27