前言:
在项目的搭建过程,你会发现无论什么时候都离不开Nginx和Gateway的支持,我们用Nginx实现了反向代理及静态资源映射,在服务器(代码块层面)我们使用了Gateway作为第二层网关实现统一授权、信息认证及路由,那么这时候问题来了,两者都叫网关,它们之间的区别是什么呢?我们能不能只用一个而不用另外一个呢?
目录
2.过滤器Filter和网关的区别
3.Zuul和Gateway的区别
一:什么是网关
1.网关简介
网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能,提供路由请求、鉴权、监控、缓存、限流等功能。无论你查看任何一个微服务项目架构,你都会发现在客户端和服务器端之间有一个网关,移动端的任何请求都必须经过网关才能到达服务端,见下图:
2.使用网关的意义
试想这样的情景,小崩同学要在一个网站上面购买东西,首先他输入了网址A访问了网站首页,然后小崩需要登录进行购买,但是这时候网站并不会自动跳转登录页面,因为这时候小崩需要访问的是登录微服务,需要另外输入新的网址B来进入登录界面。这时候小崩说,我只知道www.jd.com啊,我哪里知道京东的登录网址是什么。这时候小崩进行了一番搜索,终于获得了京东的登录界面网址,然后小崩成功登录了京东账号,点击结算,这时候需要访问的是订单微服务,而系统又提示小崩需要输入网址C进入订单微服务,这时候小崩实在蚌埠住了,一怒之下放弃了剁手,直接省下999。
假如没有网关,你就可能会遇到像小崩那样的情景,相信这样你也会绷不住的,因为每一个微服务都有自己的访问地址,我们完成一个业务需求可能需要调用多个微服务,没有网关的场景是这样的:
这样的结构存在如下问题:
- 我们完成一个业务需求需要访问很多个微服务,而这些全部都要我们自己一个个手动完成,增加了客户端的复杂性。
- 存在跨域请求问题,处理相对复杂。
- 订单微服务需要依赖于用户已经登录的情况,这时候就存在一个认证问题,因为每个微服务都需要单独进行认证。
这时候引入网关,场景发生了变化:
这时候我们有业务需求我们只需要直接访问网关即可,然后网关会根据实际请求再去访问不同的微服务,这样我们只需要与网关进行交互,只需要记住网关的地址,这样就解决了用户交互复杂问题;同时所有的认证请求都统一在网关进行认证,这时候就解决了认证困难问题;最后,我们还能通过网关对所有微服务进行监控,实时掌握各个微服务的运行状况,便于管理。
二:Nginx
1.Nginx简介
- Nginx 是高性能的 HTTP 和反向代理的web服务器,处理高并发能力是十分强大的,能经受高负 载的考验,有报告表明能支持高达 50,000 个并发连接数。
- 其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
2.Nginx功能
(1)反向代理
通过Nginx我们可以实现反向代理,这也是我在项目中使用到的一个功能,那么什么是反向代理呢?我们用户对代理是无感知的,因为我们不需要进行任何配置就可以进行访问。我们只需要将请求发送至反向代理服务器,由反向代理服务器帮我们决定需要访问哪个资源并且将资源返回给我们。此时反向代理服务器和目标服务器对外就是服务器,但是只对外暴露了代理服务器的地址,目标服务器的地址是隐藏的。
可能上面的文字你没理解,没关系,下面我举一个简单的例子加以说明。就比如你和你的一堆朋友刚到一个地方,你想知道附近有什么推荐的火锅店,这时候你并不知道附近有什么好的火锅店。你只认识当地的一个朋友,这时候你问他附近有什么火锅店推荐的,这时候你朋友就会告诉你“ 赵四火锅店YYDS ”。这时候你朋友就充当了一个反向代理服务器,你一开始并不知道真实的火锅店名称,当然代理服务器返回资源给你后你也还是不知道你访问的是哪个目标,就好像你并不知道赵四火锅店的背景,你只知道你只是实现了吃火锅这一需求。
(2)正向代理
Nginx不仅可以实现反向代理,还能实现正向代理,那么什么是正向代理呢?前面说到反向代理我们是无感知的,我们并不知道我们需要访问的目标,我们只是知道代理的地址。而正向代理则不同,我们是很清楚我们需要访问的目标的,但是访问过程中出现了一个代理去帮我们完成这个请求并将结果返回。 此时服务器只知道请求来自哪个代理服务器,而不知道是哪个客户端发起的请求,正向代理模式屏蔽或者隐藏了真实客户端的信息。
可能上面的文字理解起来有点干涩,没关系,我还是举火锅的例子。这时候你的需求并不是问火锅店了,而是你想要打包赵四火锅店的火锅,这时候就出现了一个人去帮你打包并带回来,这时候赵四只知道是谁来买的,并不知道买的人是谁,隐藏了客户端的信息,这就是正向代理。
(3)负载均衡
理解代理模式之后,我们了解到反向代理就是将用户请求分发给不同的服务器进行处理,那么分发规则是什么呢?我们能不能改变这个规则呢?这里提到的用户发送的请求量,反向代理服务器接收到的处理量就是负载量,而反向代理服务器需要根据一定的规则来将请求分发给不同的目标服务器,依据一定的规则将请求分发给不同的服务器进行处理的过程就是在进行负载均衡。Nginx提供了六种不同的负载均衡策略,分别为:
- 轮询(默认):最基本的配置方法,它是upstream模块默认的负载均衡默认策略。每个请求会按时间顺序逐一分配到不同的后端服务器。
- weight(权重):权重方式,在轮询策略的基础上指定轮询的几率。
- ip_hash:指定负载均衡器按照基于客户端IP的分配方式,这个方法确保了相同的客户端的请求一直发送到相同的服务器,以保证session会话。这样每个访客都固定访问一个后端服务器,可以解决session不能跨服务器的问题。
- least_conn:把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
- fair(第三方):按照服务器端的响应时间来分配请求,响应时间短的优先分配。
- url_hash(第三方):按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。
为了能更简单地理解这些知识,我们继续用赵四火锅的例子。这时候场景变成了很多人点了赵四的火锅外卖,这时候外卖小哥(更准确点应该是点餐系统)就是一个反向代理服务器,而赵四开了很多家火锅分店,这时候外卖小哥就需要根据不同的策略来选择去哪家分店取餐,这就是负载均衡策略,因为总不能全部订单都安排给一个分店做,这样资源利用率很低,而且客户的体验会很差。这时候有六种分发规则:
- 轮询:来了一个订单会按照时间顺序来分发,比如现在是A分店接的单,再来一个订单就将订单交给B分店,这样循环。
- weight:这种方式会按照每个分店的权重来分发订单,比如A分店最大,能够处理的订单最多,这时候就应该将A分店的权重设置大一些,分发的订单就多一点。
- ip_hash:这种方式可以理解成根据用户的地址信息来选择将订单分发给哪家店,当然这并不意味着哪个地址近我就将这个订单分发给哪家店,因为在实际情况中我们是无法通过IP地址来判定客户端离目标服务器的距离的,你可以理解成外卖小哥也不知道这个地址离哪个分店近,他只是按照一定的规则按照订单地址分发,比如有四家分店,我可以按照地址最后一个字的音调来决定选择哪家,第一声我就选择A分店,以此类推。
- least_conn:这种方式选择的是订单数最少(连接数最少)的店来分配订单,轮询方案是将订单均匀分发给不同的店,但是不同的订单制作时间不一样,比如分店A接到的订单全是要加葱的,这时候分店A刚好没有葱了,还得花时间准备葱,这样采用轮询方案会导致订单在分店A堆积。这时候假如来了个订单按照轮询应该给A分店,但是我选择了最少订单的分店B来处理这个订单就会达到更好的负载效果。
- fair:这种方式可以理解成按照店的处理速度来选择,哪家店能够最快处理这笔订单就交给谁。
- url_hash:这种方式要和ip_hash理解分开,ip_hash确保的是同一个用户的订单是交给固定的分店处理的,而url_hash虽然也是按照某一信息来决定分发,但是却跟ip_hash有很大的区别,可以理解成url_hash是根据点的火锅种类来分发的。试想这样一个场景,分店A做了很多汤卤火锅,分店B做了很多清炖火锅,分店C做了很多清水火锅,这时候假如来了一个订单是点汤卤火锅的,假如按照ip_hash是将该订单交给分店B,这样显然不太合适,而且假如分店B做了这份订单,但是一天下来分到的订单就只有这笔订单是汤卤火锅的,这样就会造成时间和资源上的浪费,这时候url_hash的优势就出来了,我可以根据客户请求的资源来决定要分发到哪个位置。
三:Gateway
1.Gateway简介
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Zuul,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
2.过滤器Filter和网关的区别
- 过滤器用于拦截单个服务
- 网关用于拦截整个微服务
- 可以理解成网关是小区门口的保安,拦截的是所有到访者;过滤器则是每户人家的门,拦截的是单个人,而且要想到达过滤器必须先经过网关。
3.Zuul和Gateway的区别
- Zuul网关属于netfix公司开源的产品,属于第一代微服务网关。
- Gateway属于SpringCloud自研发的第二代微服务网关。
- Zuul基于Servlet实现的,阻塞式的Api,不支持长连接。
- Spring Cloud Gateway基于Spring5构建,能够实现响应式非阻塞式的Api,支持长连接,能够更好整合Spring体系的产品。
- Spring Cloud Gateway可以看做是一个Zuul 1.x的升级版和替代品,比Zuul 2更早使用Netty实现异步IO,从而实现了一个简单、比Zuul 1.x更高效的、与Spring Cloud紧密配合的API网关。
- Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
四:Nginx和Gateway
1.区别
- 相同点:都是可以实现对api接口的拦截,负载均衡、反向代理、请求过滤等。
- 不同点:Nginx是用C语言写的,而Gateway是用Java写的,能够更好对微服务实现拓展功能,而Nginx想要实现拓展功能需要结合Lua语言等。此外Nginx实现负载均衡原理是属于服务器端负载均衡器,而Gateway则是采用本地负载均衡的形式。
2.请求转发方式
首先Nginx会抵御第一波的并发流量,是用户最前端的访问,可以把它当做第一层网关。可以看到项目中我都是通过Nginx来实现静态资源映射的,这时候输入的url是Nginx中配置的url。经过Nginx之后,Nginx通过反向代理再将请求转发到不同的网关系统,这是第二层网关,网关系统是根据不同的微服务来整合的,比如移动端网关,自媒体端网关,管理员端网关等。
3.Gateway的使用
前面我已经介绍过了怎么搭建网关,不熟悉的可以查看环境搭建那篇文章,这里我会讲解一下Spring Cloud GateWay 内置几种 Predicate 的使用。
在讲解之前我们先了解一下网关路由可以配置的内容有哪些:
- 路由id:路由唯一标识
- uri:路由目的地,支持lb和http两种
- predicates:路由断言,判断是否符合请求,符合则转发到路由目的地
- filters:路由过滤器,处理请求或响应
Spring提供了11种基本的Predicate工厂,见下表(图片来源于黑马教程):
4.跨域问题
所谓跨域,就是指域名不一致,而域名不一致有包括域名不同和域名相同但是端口不同,跨域问题是指浏览器禁止请求的发起者与服务端发生跨ajax请求,请求被浏览器拦截的问题,解决方案就是CORS,在网关中只需要做如下配置即可:
spring:n cloud:n gateway:n globalcors: #全局的跨域处理n add-to-simple-url-handler-mapping: true #解决options请求被拦截问题n corsConfigurations:n '[/**]': n allowedHeaders: "*" # 允许在请求头中携带的头信息n allowedOrigins: "*"n maxAge: 360000 # 这次跨域检测有效期n allowedMethods: n - GETn - POSTn - DELETEn - PUTn - OPTION
这里需要说明两点,一是解决options请求被拦截那项配置,我们的ajax是采用CORS的请求方案,CORS是浏览器去询问服务器你让不让这个请求跨域,这个询问是会被网关拦截的,而添加了这项配置表示不拦截这个询问。二是maxAge配置,假如没有这项配置,将来发送Ajax请求时候每次都要询问一次,这样服务器压力呈双倍增加,而添加这一项配置之后可以给跨域设置有效信息,有效期内可以让浏览器不发送跨域请求即可完成跨域,减轻了服务器压力。