高并发系统常用三板斧来保护系统: 缓存 、 降级 和 限流 ,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请求处理过程(二) 请求处理过程总览等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)