这一次给大家分享微服务网关的相关知识,这个也是微服务架构中,相当重要的组件之一,来,下面听我徐徐道来
1,API网关概览
1.1,现有的交互模式存在什么问题?
目前,是客户端会直接跟多个微服务直接交互,这种模式存在什么问题?
1,客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度
2,在某些场景下存在跨域请求的问题,也会降低访问的效率
3,加大身份认证的难度,每个微服务都需要独立认证
因此,我们需要一个微服务网关,介于客户端与服务器之间的中间层,所有的外部请求都会先经过微服务网关处理,之后再交给相关的业务服务进行处理。
客户端只需要与网关交互,只知道一个网关地址即可,这样简化了开发还有以下优点:
1,方便客户端调用
2,方便做统一身份认证
3,减少了客户端与各个微服务之间的交互次数
1.2,什么是微服务网关?
API网关是一个服务器,是系统对外的唯一入口。
API网关封装了系统内部架构,为每个客户端提供一个定制的API。
API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。
API网关提供REST/HTTP的访问API
1.3,网关的实现方案有哪些?
Zuul
Netflix开源,功能丰富,使用JAVA开发,易于二次开发;需要运行在web容器中,如Tomcat。
问题:缺乏管控,无法动态配置;依赖组件较多;处理Http请求依赖的是Web容器,性能不如 Nginx;
Spring Cloud Gateway
SpringCloud提供的网关服务
Nginx
如果只是需要一个基础的具备转发功能的网关,那么使用Ngnix是一个不错的选择。
比如:路由,过滤处理(nginx+lua)
location /api-index { proxy_pass http://127.0.0.1:8081/; }
location /api-product { proxy_pass http://127.0.0.1:8082/; }
2,Zuul
2.1,什么是Zuul
zuul是Netflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用,Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
动态路由:动态将请求路由到不同后端集群
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求。
Spring Cloud对Zuul进行 了整合和增强,让我们可以轻松上手。
2.2,Zuul网关的构成
1,客户端发送一个请求,经过网关,将这个请求转到合适的服务, 这个过程,叫做路由(路由规则,起到映射的作用)
2,核心是一系列过滤器 前置(pre),后置(post),路由(Route),错误(Error)
2.3,搭建Zuul网关服务工程
1,创建网关工程
api-zuul-server
2,引入依赖
<dependency>
3,启动类添加注解
@EnableZuulProxy
2.4,网关核心功能-路由
1,配置
server:port: 8888
eureka:client:service-url:defaultZone: http://localhost:9090/eureka/
spring:application:name: api-zuul-server
2,检验效果
【1】,默认提供的路由规则,可以帮助我们路由到后台的服务,如下:
访问规则:网关地址:端口/微服务服务名称/微服务请求地址
访问案例:http://localhost:8888/product-service/product/list
默认zuul就已经提供了好了路由规则,无需任何配置,就可以实现路由
路由,本质就是映射
【2】,自定义路由规则
#自定义路由规则,默认的规则依然生效
zuul:routes:api-index:path: /index/**serviceId: index-serviceapi-product:path: /product/**serviceId: product-service
注意:原先的路由规则依然有效
新配置的路由规则也生效
【3】,需求 :不想让默认的服务对外暴露接口
zuul:routes:api-index:path: /index/**serviceId: index-serviceapi-product:path: /product/**serviceId: product-service#统一入口为上面的配置,其他入口忽略ignored-patterns: /*-service/**#处理http请求头为空的问题sensitive-headers:#默认zuul会屏蔽cookie,cookie不会传到下游服务,这里设置为空则取消默认的黑名单,表示会传递到下游服务,比如product-service
2.5,网关核心功能-过滤
1,ZuulFilter简介
Zuul中的过滤器跟我们之前使用的 javax.servlet.Filter 不一样,javax.servlet.Filter是通过配置 urlPatterns 来拦截对应的请求。而 Zuul 中的过滤器是分为不同的类型,每种类型都有对应的使用场景。
1,PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、记录访问日志等等。
2,ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient或Netfilx Ribbon请求微服务。 注意,此处的过滤器类型应该写为route
3, POST:这种过滤器在路由到微服务以后执行,可以对响应的信息做处理。
4,ERROR:在其他阶段发生错误时执行该过滤器
过滤器的应用场景:
请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
异常处理:一般会在error类型和post类型过滤器中结合来处理。
服务调用时长统计:pre和post结合使用。
2,ZuulFilter接口说明
/*** @author huangguizhao*/
public class MyZuulFilter extends ZuulFilter{@Overridepublic String filterType() {return null;}
@Overridepublic int filterOrder() {return 0;}
@Overridepublic boolean shouldFilter() {return false;}
@Overridepublic Object run() throws ZuulException {//具体的过滤处理逻辑return null;}
}
方法说明:
filterType返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型pre:路由之前routing:路由之时post: 路由之后error:发生错误调用
filterOrder通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
shouldFilter返回一个 Boolean 值,判断该过滤器是否需要执行。返回true执行,返回false 不执行。
run过滤器的具体逻辑,比如判断当前用户是否有合法权限,没有,则不放行我们假设以请求中的token为例http://localhost:8888/product/product/list?token=666
3,自定义ZuulFilter
@Component
public class MyZuulFilter extends ZuulFilter{@Overridepublic String filterType() {return "pre";}@Overridepublic int filterOrder() {return 0;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() throws ZuulException {//请求上下文RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();System.out.println("--->拦截请求:" + request.getRequestURI());String token = request.getParameter("token");if(token == null){//此处让请求不再往下分发ctx.setSendZuulResponse(false);try {//给客户端响应信息ctx.getResponse().getWriter().print("Token is null!");} catch (IOException e) {e.printStackTrace();}}return null;}
}
4,RequestContext说明
RequestContext:用于在过滤器之间传递消息,它的数据保存在每个请求的ThreadLocal中;它用于存储请求路由到哪里、错误、HttpServletRequest、HttpServletResponse都存储在 RequestContext中。
所有的zuulFilter都可以共享到此块数据。
2.6,搭建高可用的zuul集群架构
配置多个实例,保证下面的配置是一致的即可
spring:application:name: api-zuul-server
SpringCloud让我们非常方便对组件进行水平扩展!
2.7,zuul网关存在的问题
【问题一】
Zuul1x版本本质上就是一个同步Servlet,采用多线程阻塞模型进行请求转发。简单讲,每来 一个请求,Servlet容器要为该请求分配一个线程专门负责处理这个请求,直到响应返回客户端,这个线程才会被释放返回容器线程池。如果后台服务调用比较耗时,那么这个线程就会被阻塞,阻塞期间线程资源被占用,不能干其它事情。我们知道Servlet容器线程池的大小是有 限制的,当前端请求量大,而后台慢服务比较多时,很容易耗尽容器线程池内的线程,造成容器无法接受新的请求。
【问题二】
且不支持websocket这种长连接的方式。
【解决方案】
2018 年 5 月,Zuul 2.x(基于 Netty,也是非阻塞的,支持长连接)发布,但 Spring Cloud 暂时还没有整合计划。所以,我们可以看到,整合的zuul版本还是1X版本。
下期,我们分享SpringCloudGateway,另一款微服务网关的实现,如果对您有帮助,就点个赞吧