Spring Cloud Gateway 之限流 *** 作

Spring Cloud Gateway 之限流 *** 作,第1张

高并发系统常用三板斧来保护系统: 缓存 降级 限流 ,API网关作为所有请求的入口,请求量大,可以通过对并发访问的请求进行限速来保护系统的可用性。

常用的限流算法比如有令牌桶算法,漏桶算法,计数器算法等,在Zuul中我们可以自己去实现限流的功能,Spring Cloud Gateway的出现本身就是用来替代Zuul的,要想替代那肯定得有强大的功能,除了性能上的优势之外,Spring Cloud Gateway还提供了很多新功能,比如限流 *** 作,使用起来非常简单。

目前限流提供了基于Redis的实现,首先引入依赖,

然后就可以以通过KeyResolver来指定限流的Key,比如我们需要根据用户来做限流,IP来做限流等等。

通过exchange对象可以获取到请求信息,这边用了HostName。

通过exchange对象可以获取到请求信息,获取当前请求的用户ID或者用户名,使用这种方式限流,请求路径中必须携带userId参数。

获取请求地址的uri作为限流key。

配置好后就可以进行限流测试了,注意观察redis中的数据。

获取请求类型

在很多情况下面,我们需要判断当前 *** 作的请求类型是GET、POST、PUT、DELETE或者HEAD,一方面可以针对请求类型作出不同的逻辑处理,另外一方面有些情况下面需要验证安全性,过滤不安全的请求。

ThinkPHP50 取消了用于判断请求类型的系统常量(如IS_GET,IS_POST等),统一采用think\Request类 处理请求类型。

用法如下

// 是否为 GET 请求

if (Request::instance()->isGet()) echo "当前为 GET 请求";

// 是否为 POST 请求

if (Request::instance()->isPost()) echo "当前为 POST 请求";

// 是否为 PUT 请求

if (Request::instance()->isPut()) echo "当前为 PUT 请求";

// 是否为 DELETE 请求

if (Request::instance()->isDelete()) echo "当前为 DELETE 请求";

// 是否为 Ajax 请求

if (Request::instance()->isAjax()) echo "当前为 Ajax 请求";

// 是否为 Pjax 请求

if (Request::instance()->isPjax()) echo "当前为 Pjax 请求";

// 是否为手机访问

if (Request::instance()->isMobile()) echo "当前为手机访问";

// 是否为 HEAD 请求

if (Request::instance()->isHead()) echo "当前为 HEAD 请求";

// 是否为 Patch 请求

if (Request::instance()->isPatch()) echo "当前为 PATCH 请求";

// 是否为 OPTIONS 请求

if (Request::instance()->isOptions()) echo "当前为 OPTIONS 请求";

// 是否为 cli

if (Request::instance()->isCli()) echo "当前为 cli";

// 是否为 cgi

if (Request::instance()->isCgi()) echo "当前为 cgi";

助手函数

// 是否为 GET 请求

if (request()->isGet()) echo "当前为 GET 请求";

……

通过注入请求对象的功能,可以更简单的实现。请参考后面的注入请求对象一节的内容。

请求处理过程总览(FacesServlet#service)

这总览 很明显是看FacesServlet的service方法 在FacesServlet的初始化过程中 构造出了全局的FacesContextFactory对象和LifeCycle对象 可以把FacesContextFactory看做是一个 请求包装工厂 于是很明显 每当一个请求到达FacesServlet的时候 第一步便是拿着请求 到包装工厂里面包装一下 而包装的结果就是一个FacesContext 代码如下

FacesContext context = facesContextFactory getFacesContext(servletConfig getServletContext() request response lifecycle)

在包装过程中 实际上是创建了一个ntext FacesContextImpl对象 FacesContextImpl类继承了jsf api项目中的ntext FacesContext FacesContextImpl的构造方法的第一个参数是一个叫做ExternalContext的接口的实现 查看其源代码 可以看到ExternalContextImpl类耦合了Servlet API 而FacesContextImpl与Servlet API无关 实际上 在这里 做到了JSF可以不仅仅使用在Servlet环境中 正如ExternalContext接口的注释中所说 在Servlet环境中使用JSF和在Portlet环境中使用JSF的不同 实际上就是使用了不同的ExternalContext 在FacesContextFactoryImpl中构造FacesContextImpl的代码如下   FacesContext ctx = new FacesContextImpl(new ExternalContextImpl((ServletContext) sc (ServletRequest) request (ServletResponse) response) lifecycle);

    FacesContextImpl的构造方法中 还做了另外一件事情 就是根据配置确定了RenderKitFactory 显然不同的RenderKitFactory可以产生不同的RenderKit 而不同RenderKit对象是针对不同客户端的 所以对于浏览器 移动设备等等 会有不同的RenderKit FacesContextImpl的构造方法中代码如下   this externalContext = ec; setCurrentInstance(this); this rkFactory = (RenderKitFactory)FactoryFinder getFactory(FactoryFinder RENDER_KIT_FACTORY);

在代码中我们经常使用FacesContext getCurrentInstance()这个静态方法来获取与当前请求对应的FacesContext对象 实际上是在FacesContext类里面有一个静态的ThreadLocal对象用来存放了当前请求线程对应的FacesContext对象 于是上面的代码中setCurrentInstance(this)就是把当前构造出来的这个FacesContext对象放到了ThreadLocal里面

FacesContext创建出来以后 正如上面所说 要让他经过LifeCycle这个 Filter Chain 的逐步处理了 那么 Filter Chain里面放的是一个一个Filter 那么LifeCycle这个Chain里面放的是什么呢?答案是Phases

FacesServlet让FaceContext通过LifeCycle的处理 分成了两个部分 一个部分是调用LifeCycle的execute方法 执行逻辑 第二个部分是调用LifeCycle的render方法 呈现响应 FacesServlet service中代码如下   lifecycle execute(context); lifecycle render(context);

在LifeCycleImpl这个实现中 存放了一个Phase对象的数组 存放了 个Phase 其中第一个是null 然后依次是视图重建 应用请求值 验证 更新模型值 执行应用程序 呈现响应 在execute方法中 调用了从视图重建开始到执行应用程序为止的 个Phase 而在render方法中 调用了最后一个Phase 也就是呈现响应 在LifeCycleImpl类中 代码如下

//The Phase instance for the render() method    private Phase response = new RenderResponsePhase();

// The set of Phase instances that are executed by the execute() method    // in order by the ordinal property of each phase    private Phase[] phases = {        null // ANY_PHASE placeholder not a real Phase        new RestoreViewPhase()         new ApplyRequestValuesPhase()         new ProcessValidationsPhase()         new UpdateModelValuesPhase()         new InvokeApplicationPhase()         response    };

在Servlet Filter中 可以由每一个Filter来决定是否要调用下一个Filter 从而决定是否让请求继续通过Filter Chains中的后续Filter 是链式调用的过程 而在LifeCycle的execute方法中 是用一个for循环顺序执行几个Phase 在每一个Phase执行完之后 都会检查FaceContext对象中是否设置了停止后续处理直接呈现响应的标志(renderResponse)或者已经完成了响应无需后续处理也不需要经过呈现响应阶段了(responseComplete) 如果标志为true 那么就不再执行后续Phase

LifeCycleImpl的execute方法主要代码如下   for (int i = len = phases length ; i < len; i++) { // Skip ANY_PHASE placeholder                 if (context getRenderResponse() ||                   context getResponseComplete()) {                   break;               }                 phases[i] doPhase(context this listeners listIterator());    }

    在LifeCycle的render方法中 也会检查FacesContext的responseComplete状态 如果为true 那么就不再执行render Phase 于是我们此刻知道了在我们自己所写的一些代码或者JSF库里面的一些代码中 调用FacesContext的responseComplete方法和renderResponse得作用原理 render方法主要代码如下   if (!context getResponseComplete()) {        response doPhase(context this listeners listIterator()); }

另外注意 Phase这个概念 接口 以及几个实现 都是jsf ri项目中的 而在jsf api中不存在Phase这个概念 所以 LifeCycle是JSF标准的内容 而通过几个Phase来处理请求这种实现是sun的参考实现的做法

lishixinzhi/Article/program/Java/hx/201311/25717

以上就是关于Spring Cloud Gateway 之限流 *** 作全部的内容,包括:Spring Cloud Gateway 之限流 *** 作、请求类型的判断、JSF请求处理过程(二) 请求处理过程总览等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9307860.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-27
下一篇 2023-04-27

发表评论

登录后才能评论

评论列表(0条)

保存