微服务:SpringCloud zuul网关

骑猪看日落 2023-02-13 05:41 190阅读 0赞

一、存在的问题

在之前的文章中,微服务架构已经初具雏形。但还有一些问题:不同的微服务一般会有不同的网 络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客户端方来说太复杂也难以维护。如下图:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70

前端应用程序调用我们消费者提供的接口会有以下几个问题:

  • 客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度 (各个消费者ip不同)
  • 在某些场景下存在跨域请求的问题
  • 加大身份认证的难度,每个微服务需要独立认证(关于微服务认证,可以看我之前的文章,深入的讲解了分布式的授权与认证)

那我们想,能否用同一个ip来解决呢?这样就出现了我们网关的姿势!

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70 1

通过网关,前端应用程序,只需要调用网关的ip就可以了。在网关就可以找到对应的微服务。

二、网关的概念

什么是微服务网关:

API 网关是一个服务器,是系统对外的唯一入口。 API 网关封装了系统内部架构,为每个客户端提供一个定制的API 。 API 网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP 的访问 API 。服务端通过 API-GW 注册和管理服务。

作用和应用场景:

网关具有的职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。当然,最主

要的职责还是与 “ 外界联系 ” 。

常见的 API 网关实现方式

  • Kong:基于Nginx+Lua 开发,性能高,稳定,有多个可用的插件 ( 限流、鉴权等等 ) 可以开箱即用。问题:只支持Http 协议;二次开发,自由扩展困难;提供管理 API ,缺乏更易用的管控、配置方式。
  • Zuul:Netflflix开源,功能丰富,使用 JAVA 开发,易于二次开发;需要运行在 web 容器中,如 Tomcat 。 问题:缺乏管控,无法动态配置;依赖组件较多;处理Http 请求依赖的是 Web 容器,性能不如Nginx;

  • Traefifik:Go语言开发;轻量易用;提供大多数的功能:服务路由,负载均衡等等;提供WebUI。问题:二进制文件部署,二次开发难度大;UI更多的是监控,缺乏配置、管理能力;

  • Spring Cloud Gateway:SpringCloud提供的网关服务

  • Nginx+lua实现:使用Nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用问题:自注册的问题和网关本身的扩展性。

三、zuul实现网关

1、Zuul**简介**

ZUUL 是 Netflflix 开源的微服务网关,它可以和 Eureka 、 Ribbon 、 Hystrix 等组件配合使用, Zuul 组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:

  • 动态路由:动态将请求路由到不同后端集群
  • 压力测试:逐渐增加指向集群的流量,以了解性能
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
  • 静态响应处理:边缘位置进行响应,避免转发到内部集群
  • 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求。Spring Cloud对Zuul进行了整合和增强。

2、搭建一个Zuul网关服务器

(1)一个基础工程

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70 2

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>SpringCloudDemo</artifactId>
  7. <groupId>com.springcloud.demo</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>zuul_server</artifactId>
  12. <dependencies>
  13. <dependency>
  14. <groupId>org.springframework.cloud</groupId>
  15. <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  16. </dependency>
  17. </dependencies>
  18. </project>
  19. server:
  20. port: 8080 #端口
  21. spring:
  22. application:
  23. name: api-zuul-server
  24. package com.springcloud.demo;
  25. import org.springframework.boot.SpringApplication;
  26. import org.springframework.boot.autoconfigure.SpringBootApplication;
  27. import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
  28. @SpringBootApplication
  29. @EnableZuulProxy
  30. public class ZuulApplication {
  31. public static void main(String[] args) {
  32. SpringApplication.run(ZuulApplication.class,args);
  33. }
  34. }

其他服务目录:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70 3

person-sevice是9002端口,order-service是9001端口,这两个是对外提供的接口。product-service是9010端口,是微服务。

(2)路由配置

  1. # 路由选择配置
  2. zuul:
  3. routes:
  4. service-order:
  5. path: /order-service/**
  6. url: http://127.0.0.1:9001
  7. service-person:
  8. path: /person-service/**
  9. url: http://127.0.0.1:9002

只需要在 application.yml 文件中配置路由规则即可:

  • product-service:配置路由id,可以随意取名
  • url:映射路径对应的实际url地址
  • path:配置映射路径,这里将所有请求前缀为/product-service/的请求,转发到http://127.0.0.1:9002处理

20200528151306692.png

20200528151338610.png

都是可以的,他们都调用了一个微服务。

(3)面向服务的路由配置(从注册中心拿到服务)

添加注册中心依赖:

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  4. </dependency>

添加注册中心配置

  1. eureka:
  2. client:
  3. service-url:
  4. defaultZone: http://localhost:9000/eureka/
  5. instance:
  6. prefer-ip-address: true #使用ip地址注册
  7. # 路由选择配置
  8. zuul:
  9. routes:
  10. service-order:
  11. path: /order-service/**
  12. # url: http://127.0.0.1:9001
  13. serviceId: service-order
  14. service-person:
  15. path: /person-service/**
  16. # url: http://127.0.0.1:9002
  17. serviceId: service-person

20200528152359201.png

依然是没有任何问题的!!!

简化配置

  1. zuul:
  2. routes:
  3. service-order: /service-order/**

3、过滤器

zuul有两个核心功能:请求过滤

ZuulFilter 简介

Zuul 中的过滤器跟我们之前使用的 javax.servlet.Filter 不一样, javax.servlet.Filter 只有一种类型,可

以通过配置 urlPatterns 来拦截对应的请求。而 Zuul 中的过滤器总共有 4 种类型,且每种类型都有对

应的使用场景。

  • PRE :这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请

    求的微服务、记录调试信息等。

  • ROUTING :这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用

    Apache HttpClient 或 Netfifilx Ribbon 请求微服务。

  • POST :这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP

    Header 、收集统计信息和指标、将响应从微服务发送给客户端等。

  • ERROR:在其他阶段发生错误时执行该过滤器。

Zuul 提供了自定义过滤器的功能实现起来也十分简单,只需要编写一个类去实现 zuul 提供的接口

  1. public abstract ZuulFilter implements IZuulFilter{
  2. abstract public String filterType();
  3. abstract public int filterOrder();
  4. boolean shouldFilter();// 来自IZuulFilter
  5. Object run() throws ZuulException;// IZuulFilter
  6. }

ZuulFilter 是过滤器的顶级父类。在这里我们看一下其中定义的 4 个最重要的方法。

  • shouldFilter :返回一个 Boolean 值,判断该过滤器是否需要执行。返回 true 执行,返回 false不执行。
  • run :过滤器的具体业务逻辑。

  • filterType :返回字符串,代表过滤器的类型。包含以下4种:

    • pre :请求在被路由之前执行

    • routing :在路由请求时调用

    • post :在routing和errror过滤器之后调用
    • error :处理请求时发生错误调用
  • filterOrder :通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

生命周期:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70 4

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70 5

4、自定义过滤器

  1. package com.springcloud.demo.filter;
  2. import com.netflix.zuul.ZuulFilter;
  3. import com.netflix.zuul.context.RequestContext;
  4. import com.netflix.zuul.exception.ZuulException;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.stereotype.Component;
  7. import javax.servlet.http.HttpServletRequest;
  8. /**
  9. * @ClassName LoginFilter
  10. * @Description
  11. * @Author 戴书博
  12. * @Date 2020/5/28 16:24
  13. * @Version 1.0
  14. **/
  15. @Component
  16. public class LoginFilter extends ZuulFilter {
  17. /**
  18. * 类型:
  19. * pre
  20. * routing
  21. * post
  22. * error
  23. */
  24. @Override
  25. public String filterType() {
  26. return "pre";
  27. }
  28. /**
  29. * 指定过滤器的执行顺序
  30. * 返回值越小,执行顺序越靠前
  31. */
  32. @Override
  33. public int filterOrder() {
  34. return 0;
  35. }
  36. /**
  37. * 当前过滤器是否生效
  38. * true:使用此过滤器
  39. * false:不使用此过滤器
  40. */
  41. @Override
  42. public boolean shouldFilter() {
  43. return true;
  44. }
  45. /**
  46. * 执行过滤器的方法
  47. */
  48. @Override
  49. public Object run() throws ZuulException {
  50. System.out.println("================进入过滤器=================");
  51. //获取上下文对象
  52. RequestContext ctx = RequestContext.getCurrentContext();
  53. //获取request对象
  54. HttpServletRequest req = ctx.getRequest();
  55. //从请求中获取token
  56. String token = req.getParameter("access-token");
  57. //判断
  58. if(token == null || token.equals("")){
  59. // 没有token,登录校验失败,拦截
  60. ctx.setSendZuulResponse(false);
  61. // 返回401状态码。也可以考虑重定向到登录页。
  62. ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
  63. }
  64. // 校验通过,可以考虑把用户信息放入上下文,继续向后执行
  65. return null;
  66. }
  67. }

在我们之前写的授权与认证中,使用了一个微服务认证。这里简单写一下。

20200528164417203.png

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU4ODQ5NQ_size_16_color_FFFFFF_t_70 6

zuul出现的问题:

  • 性能问题 :Zuul1x版本本质上就是一个同步Servlet,采用多线程阻塞模型进行请求转发。简单讲,每一个请求,Servlet容器要为该请求分配一个线程专门负责处理这个请求,直到响应返回客户端这个线程才会被释放返回容器线程池。如果后台服务调用比较耗时,那么这个线程就会被阻塞,阻塞期间线程资源被占用,不能干其它事情。我们知道Servlet容器线程池的大小是有限制的,当前端请求量大,而后台慢服务比较多时,很容易耗尽容器线程池内的线程,造成容器无法接受新的请求。
  • 不支持任何长连接,如websocket

源码:git@gitee.com:Zesystem/springclouddedemowangguan.git

发表评论

表情:
评论列表 (有 0 条评论,190人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SpringCloud-zuul

    网关的作用:就相当于整个微服务体系的入口,所有的外部请求都应该通过zuul进行处理,zuul会通过请求url分析应该将请求分发给哪个微服务处理,微服务处理完毕之后,会将结果返回

    相关 服务SpringCloud zuul

    一、存在的问题 在之前的文章中,微服务架构已经初具雏形。但还有一些问题:不同的微服务一般会有不同的网 络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客

    相关 springcloud zuul

    网关可以对请求进行过滤拦截,转发等,这种跟过滤器不一样,它可以拦截入口,而不是单独一个服务。 业务场景,会员服务和订单服务,用户必须登录才能调用相关接口(即含有userTok