Spring
在 2017 年下半年迎来了Webflux
,Webflux
的出现填补了Spring
在响应式编程上的空白,Webflux
的响应式编程不仅仅是编程风格的改变,而且对于一系列的著名框架,都提供了响应式访问的开发包,比如Netty、Redis
等等。 SpringCloud Gateway
使用的Webflux
中的reactor-netty
响应式编程组件,底层使用了Netty
通讯框架。
SpringCloud Zuul 的 IO 模型
SpringCloud
中所集成的Zuul
版本,采用的是Tomcat
容器,使用的是传统的Servlet IO
处理模型。 大家知道,Servlet
由Servlet Container
进行生命周期管理。 Container
启动时构造Servlet
对象并调用Servlet init()
进行初始化; Container
关闭时调用Servlet Destory()
销毁Servlet
;Container
运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service()
。 弊端:Servlet
是一个简单的网络 IO 模型,当请求进入Servlet Container
时,Servlet Container
就会为其绑定一个线程,在并发不高的场景下这种模型是适用的,但是一旦并发上升,线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单的业务场景下,不希望为每个Request
分配一个线程,只需要 1 个或几个线程就能应对极大并发的请求,这种业务场景下servlet
模型没有优势。 所以Springcloud Zuul
是基于Servlet
之上的一个阻塞式处理模型,即 Spring 实现了处理所有Request
请求的一个Servlet(DispatcherServlet)
,并由该Servlet
阻塞式处理处理。所以Springcloud Zuul
无法摆脱servlet
模型的弊端。虽然Zuul 2.0
开始,使用了Netty
,并且已经有了大规模Zuul 2.0
集群部署的成熟案例,但是,Springcloud
官方已经没有集成改版本的计划了。
Webflux 服务器
Webflux
模式替换了旧的Servlet
线程模型。用少量的线程处理request
和response io
操作,这些线程称为Loop
线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work
线程中执行,而不阻塞的操作依然可以在Loop
线程中进行处理,大大提高了Loop
线程的利用率。官方结构图: Webflux
虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Nett
y,毕竟Netty
是目前业界认可的最高性能的通信框架。而Webflux
的Loop
线程,正好就是著名的Reactor
模式IO
处理模型的Reactor
线程,如果使用的是高性能的通信框架Netty
,这就是Netty
的EventLoop
线程。
Spring Cloud Gateway 的处理流程
客户端向 Spring Cloud Gateway
发出请求。然后在 Gateway Handler Mapping
中找到与请求相匹配的路由,将其发送到 Gateway Web Handler
。Handler
再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(pre)
或之后post
执行业务逻辑。