毕业工作5年被裁,什么是Spring-Cloud、需要掌握哪些知识点

// 指定了后备方法调用 
@HystrixCommand(fallbackMethod = "getHystrixNews") 
@GetMapping("/get/news") 
public News getNews(@PathVariable("id") int id) { 
	// 调用新闻系统的获取新闻api 代码逻辑省略 
}
//
public News getHystrixNews(@PathVariable("id") int id) { 
	// 做服务降级 
	// 返回当前人数太多,请稍后查看 
}

2.什么是Hystrix之其他

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

具体其原理我推荐大家自己去了解一下,本篇文章中对 舱壁模式 不做过多解释。当然还有 Hystrix 仪表盘,它是用来实时监控 Hystrix 的各项指标信息的,这里我将这个问题也抛出去,希望有不了解的可以自己去搜索一下。

二、微服务网关——Zuul

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

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

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

大家对网关应该很熟吧,简单来讲网关是系统唯一对外的入口,介于客户端与服务器端之间,用于对请求进行鉴权限流路由监控等功能。
image
没错,网关有的功能, Zuul 基本都有。而 Zuul 中最关键的就是 路由和过滤器 了,在官方文档中 Zuul 的标题就是

Router and Filter : Zuul

1.Zuul 的路由功能

1)简单配置

本来想给你们复制一些代码,但是想了想,因为各个代码配置比较零散,看起来也比较零散,我决定还是给你们画个图来解释吧。

比如这个时候我们已经向 Eureka Server 注册了两个 Consumer 、三个 Provicer ,这个时候我们再加个 Zuul 网关应该变成这样子了。
image
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 注解就行了。没错,就是那么简单。

2)统一前缀

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

zuul: 
	prefix: /zuul

这样我们就需要通过 localhost:9000/zuul/consumer1/studentInfo/update 来进行访问了。

3)路由策略配置

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

zuul: 
	routes: 
		consumer1: /FrancisQ1/** 
		consumer2: /FrancisQ2/**

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

4)服务名屏蔽

这个时候你别以为你好了,你可以试试,在你配置完路由策略之后使用微服务名称还是可以访问的,这个时候你需要将服务名屏蔽。

zuul: 
	ignore-services: "*"

5)路径屏蔽

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

zuul: 
	ignore-patterns: **/auto/**

这样关于 auto 的请求我们就可以过滤掉了。

** 代表匹配多级任意路径
*代表匹配一级任意路径

6)敏感请求头屏蔽

默认情况下,像 CookieSet-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,我们可以将这些默认屏蔽去掉,当然,也可以添加要屏蔽的请求头。

2.Zuul 的过滤功能

如果说,路由功能是 Zuul 的基操的话,那么 过滤器 就是 Zuul 的利器了。毕竟所有请求都经过网关 (Zuul),那么我们可以进行各种过滤,这样我们就能实现 限流灰度发布权限控制 等等。

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

要实现自己定义的 Filter 我们只需要继承 ZuulFilter 然后将这个过滤器类以 @Component 注解加入 Spring 容器中就行了。

在给你们看代码之前我先给你们解释一下关于过滤器的一些注意点。
image
过滤器类型: PreRoutingPost 。前置 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 过滤功能的强大了呢?

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

2)令牌桶限流

当然不仅仅是令牌桶限流方式, Zuul 只要是限流的活它都能干,这里我只是简单举个栗子。
image
我先来解释一下什么是 令牌桶限流 吧。

首先我们会有个桶,如果里面没有满那么就会以一定 固定的速率 会往里面放令牌,一个请求过来首先要从桶中获取令牌,如果没有获取到,那么这个请求就拒绝,如果获取到那么就放行。

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

package com.lgq.zuul.filter; 

import com.google.common.util.concurrent.RateLimiter; 
import com.netflix.zuul.ZuulFilter; 
import com.netflix.zuul.context.RequestContext; 
import com.netflix.zuul.exception.ZuulException; 
import lombok.extern.slf4j.Slf4j; 
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; 
import org.springframework.stereotype.Component; 

@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; 
	} 


#### 线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

![](https://img-blog.csdnimg.cn/img_convert/d72c5fcd551bed3dcc88aa90997ce2f4.png)

#### 一线互联网P7面试集锦+各种大厂面试集锦

![](https://img-blog.csdnimg.cn/img_convert/979e1218d00e54e716cd2c4463b2912e.png)

**[资料领取方式:戳这里](https://gitee.com/vip204888/java-p7)**

#### 学习笔记以及面试真题解析



#### 线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

[外链图片转存中...(img-Y7exw6TC-1628153646194)]

#### 一线互联网P7面试集锦+各种大厂面试集锦

[外链图片转存中...(img-DwPbZnhK-1628153646195)]

**[资料领取方式:戳这里](https://gitee.com/vip204888/java-p7)**

#### 学习笔记以及面试真题解析

![](https://img-blog.csdnimg.cn/img_convert/d662e1552f020b07de57f811efe1f0f9.png)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值