微服务:SpringCloud zuul网关

一、存在的问题

在之前的文章中,微服务架构已经初具雏形。但还有一些问题:不同的微服务一般会有不同的网 络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客户端方来说太复杂也难以维护。如下图:
 
前端应用程序调用我们消费者提供的接口会有以下几个问题:
  • 客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度 (各个消费者ip不同)
  • 在某些场景下存在跨域请求的问题
  • 加大身份认证的难度,每个微服务需要独立认证(关于微服务认证,可以看我之前的文章,深入的讲解了分布式的授权与认证)
那我们想,能否用同一个ip来解决呢?这样就出现了我们网关的姿势!
 
通过网关,前端应用程序,只需要调用网关的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 CloudZuul进行了整合和增强。

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

(1)一个基础工程

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringCloudDemo</artifactId>
        <groupId>com.springcloud.demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>zuul_server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>
</project>
server:
  port: 8080 #端口

spring:
  application:
    name: api-zuul-server
package com.springcloud.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class,args);
    }
}

其他服务目录:

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

(2)路由配置

# 路由选择配置
zuul:
  routes:
    service-order:
      path: /order-service/**
      url: http://127.0.0.1:9001
    service-person:
      path: /person-service/**
      url: http://127.0.0.1:9002
只需要在 application.yml 文件中配置路由规则即可:
  • product-service:配置路由id,可以随意取名
  • url:映射路径对应的实际url地址 
  • path:配置映射路径,这里将所有请求前缀为/product-service/的请求,转发到http://127.0.0.1:9002处理

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

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

添加注册中心依赖:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
添加注册中心配置
 
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册
# 路由选择配置
zuul:
  routes:
    service-order:
      path: /order-service/**
#      url: http://127.0.0.1:9001
      serviceId: service-order
    service-person:
      path: /person-service/**
#      url: http://127.0.0.1:9002
      serviceId: service-person

 

依然是没有任何问题的!!!
 
简化配置
zuul:
  routes:
     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 提供的接口
 
public abstract ZuulFilter implements IZuulFilter{ 
    abstract public String filterType(); 

    abstract public int filterOrder(); 

    boolean shouldFilter();// 来自IZuulFilter 
    
    Object run() throws ZuulException;// IZuulFilter 
}
ZuulFilter 是过滤器的顶级父类。在这里我们看一下其中定义的 4 个最重要的方法。
 
  • shouldFilter :返回一个 Boolean 值,判断该过滤器是否需要执行。返回 true 执行,返回 false不执行。
  •  
    run :过滤器的具体业务逻辑。
  •  
    filterType :返回字符串,代表过滤器的类型。包含以下4种:
    •  
      pre :请求在被路由之前执行
    •  
      routing :在路由请求时调用
    • post :在routingerrror过滤器之后调用
    • error :处理请求时发生错误调用
  • filterOrder :通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

生命周期:

 

4、自定义过滤器

package com.springcloud.demo.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @ClassName LoginFilter
 * @Description
 * @Author 戴书博
 * @Date 2020/5/28 16:24
 * @Version 1.0
 **/
@Component
public class LoginFilter extends ZuulFilter {

    /**
     * 类型:
     *      pre
     *      routing
     *      post
     *      error
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 指定过滤器的执行顺序
     * 返回值越小,执行顺序越靠前
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 当前过滤器是否生效
     * true:使用此过滤器
     * false:不使用此过滤器
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 执行过滤器的方法
     */
    @Override
    public Object run() throws ZuulException {
        System.out.println("================进入过滤器=================");
        //获取上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        //获取request对象
        HttpServletRequest req = ctx.getRequest();
        //从请求中获取token
        String token = req.getParameter("access-token");
        //判断
        if(token == null || token.equals("")){
            // 没有token,登录校验失败,拦截
            ctx.setSendZuulResponse(false);
            // 返回401状态码。也可以考虑重定向到登录页。
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        // 校验通过,可以考虑把用户信息放入上下文,继续向后执行
        return null;
    }
}

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

zuul出现的问题:

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

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

 

 

 

 

 

 

 

 

 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值