网关的概念

API Gateway 网关,是系统的唯一入口,处理非业务功能、统一过滤请求,提供路由、权限验证、监控、缓存、限流等功能。

统一接入

  • 路由转发 /api/v1/user,/api/v1/order,....路由到不同的服务

  • AB测试、灰度测试

  • 负载均衡 网关自带负载均衡器均衡功能,可根据负载均衡算法转发该服务的某个节点,因为要从服务中心拿节点列表,所以网关也要注册到注册中心上

  • 容灾处理 某个下级服务集群不可用时,可以直接切断对该服务的请求

  • 日志记录

流量监控

  • 限流处理

  • 服务降级

安全防护

  • 权限验证

  • 服务监控

  • 网络隔离 网关可以将内网、外网隔开,服务节点在内网中,通过内网调用服务,速度快;用户通过外网(公网ip)访问网关

网关可以调用服务,是一个特殊的消费者,消费者的负载均衡、容错保护、服务监控、限流降级它都能做到。

如果网关进行了集群,需要Nginx进行负载均衡,来确定调用哪个网关节点。

主流网关

  • zuul   和eureka、ribbon、hystrix一样,都是Netflix旗下的项目
  • kong   基于nginx的网关
  • nginx+lua    nginx是一个高性能的HTTP和反向代理服务器,lua是脚本语言,让Nginx执行Lua脚本实现网关

使用Zuul进行路由转发

(1)新建子模块api-gateway作为网关服务,创建时只需勾选Spring Cloud Discovery -> Eureka Discovery Client ,Spring Cloud Routing -> Routing[Maintenance]

也可以手动加依赖:

    <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

网关要从Eureka Server获取服务节点列表,使用Eureka Client内置的Ribbon进行负载均衡,所以要添加Eureka Client的依赖,并进行Eureka Client相关配置

Zuul的依赖中已经包含了Hystrix的依赖。

(2)引导类

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy //也可以使用@EnableZuulServer
public class ApiGatewayApplication { public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
} }

@EnableZuulProxy中已经包含了Hystrix的注解@EnableCircuitBreaker。

默认使用轮询,如果要使用其它负载均衡策略,设置方式和Eureka Client的完全相同。

(3)配置文件

server:
port: 9000 spring:
application:
#服务名称
name: api-gateway eureka:
client:
#注册中心地址
serviceUrl:
defaultZone: http://127.0.0.1:8761/eureka/

127.0.0.1:9000/user-service/api/v1/user/order/1    通过网关来访问服务,后面是服务名、服务接口

需要指定路由规则:

zuul:
routes:
#指定路由规则,key是服务名,value是映射地址
user-service: /api-gateway/user-service/**
#取消原来的映射
ignored-patterns: /*-service/**

127.0.0.1:9000/api-gateway/user-service/api/v1/user/order/1     使用网关作为唯一入口,127.0.0.1:9000/api-gateway可以统一拦截处理所有的请求。

根据服务接口/api/v1/user/order/{user_id}来识别服务,所以api-gateway后面不一定要是服务名,比如可以是user。

如果不取消原来的映射方式,原来的映射方式也可以访问。

也可以使用下面的方式指定:

zuul:
prefix: /api-gateway/

这种方式只是加一个前缀,127.0.0.1:9000/api-gateway/user-service/api/v1/user/order/1 ,后面依然是服务名。


Zuul  过滤请求

新建一个包filter,包下新建一个类,继承ZuulFilter

package com.chy.mall.apigateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import java.io.IOException; @Component //放到spring容器中
public class ValidateFilter extends ZuulFilter { //ZuulFilter是抽象类,需要实现里面的方法 /*
指定过滤类型(时机),"pre"是路由转发之前,"routing"是路由转发之时,"post"是返回响应给浏览器之前,"error"是发生错误时
前处理用pre,后处理用post
*/
@Override
public String filterType() {
return "pre";
} /*
要执行多个拦截器,需要指定这些拦截器调用的先后顺序,数值越小,优先级越高、越先执行
可以在FilterConstants类中查看Zuul自带的拦截器的Order,自定义拦截器的Order要参考它们进行设置,不能想设置多大就设置多大
前处理一般设置为0~9
*/
@Override
public int filterOrder() {
return 0;
} /*
是否要使用此过滤器,默认为false,需要改为true
如果需要关闭此拦截器,改为false即可
*/
@Override
public boolean shouldFilter() {
return true;
} /*
核心方法,用来过滤请求
*/
@Override
public Object run() {
RequestContext currentContext = RequestContext.getCurrentContext();
//前处理,获取request
HttpServletRequest request = currentContext.getRequest();
//获取参数
String token = request.getParameter("token");
//token要和数据库查到的进行比较,此处随便写一个代替
if (token==null || !token.equals("123456")) {
//如果token错误,直接返回响应,不转发给服务。只是不转发给服务,此方法后面部分的代码还是会执行
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(400);
//输出信息到浏览器
try {
currentContext.getResponse().getWriter().write("token is invalid");
} catch (IOException e) {
e.printStackTrace();
}
} // 有时候可能要对指定的url进行拦截处理
// ip:port后面的部分,示例 /api-gateway/user-service/api/v1/user/order/1
String requestURI = request.getRequestURI();
if (requestURI.contains("/api-gateway/user-service/......")){
//......
}
if (requestURI.equals("/api-gateway/user-service/.....")){
//......
} return null;
} }

不建议使用大量的过滤器,因为会加大时间开销,拉低性能。

网关中一般写通用的过滤,比如校验用户是否登录;如果是对部分服务进行过滤,最好在shouldFilter()中就判断请求地址。

如果只是个别服务的过滤,写在服务自身中。


zuul  限流

系统性能都是有限的,过多的请求|访问量会冲垮应用,所以一般都要做限流。

hystrix是服务层的限流,zuul可以使用谷歌的guava框架对请求进行限流,zuul的限流是网关层的限流,也可以在nginx上进行限流。

示例:zuul -> 服务A -> 服务B ,zuul使用guava对服务A进行限流,服务A使用hystrix限流A本身对服务B的调用请求

zuul本身已经集成了guava,直接用即可

package com.chy.mall.apigateway.filter;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; @Component
public class UserServiceLimitFilter extends ZuulFilter {
//RateLimiter是com.google.common.util.concurrent.RateLimiter,不要导错了
//指定最大访问量,数值一般是压测得到的qps上限,此处设置为1000
private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000); @Override
public String filterType() {
return "pre";
} @Override
public int filterOrder() {
//限流的过滤器放在自定义前处理的最前面
return -4;
} @Override
public boolean shouldFilter() {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String requestURI = request.getRequestURI();
//设置要要限流的服务,此处限流的服务是user-service,通过zuul请求user-service的qps不能超过1000
     //如果多个服务的qps上限都一样,可以一起设置
if (requestURI.contains("/api-gateway/user-service/")){
return true;
}
return false;
} @Override
public Object run() {
RequestContext currentContext = RequestContext.getCurrentContext();
//如果超过设置的上限,直接返回响应,不转发给服务
if (!RATE_LIMITER.tryAcquire()){
//直接返回响应,不转发给服务
currentContext.setSendZuulResponse(false);
//返回给浏览器的状态码是429 过多请求,可以使用常量,也可以直接写int型的状态码
currentContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
} return null;
} }

zuul  请求头过滤

Zuul默认会对请求头进行过滤处理:

    private Set<String> sensitiveHeaders = new LinkedHashSet(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));

默认会将请求头中的这3部分剔除,再将请求转发给服务,所有在服务中是取不到cookie的。

需要设置一下:

zuul:
routes:
#指定路由规则,前面是服务名,后面是映射地址
user-service: /api-gateway/user/**
#取消原来的映射
ignored-patterns: /*-service/**
#取消对请求头的默认处理
sensitive-headers:

配置文件中设置了此字段,会调用setter方法设置此字段。

不设置值,即为null,用null覆盖默认值。


zuul  上传文件限制

zuul默认对请求大小、上传文件的大小有限制,需要设置一下

spring:
application:
#服务名称
name: api-gateway
servlet:
multipart:
#设置请求的最大尺寸,单位M,默认10
max-request-size: 1024
#上传文件允许的单个文件的最大尺寸,单位M,默认1
max-file-size: 1024

zuul  集群

使用网关之后,ajax的url、<a>链接的href、<form>的action、服务调用地址,都要写成网关地址,通过网关统一访问,不再直接访问服务。

zuul集群之后,使用nginx做负载均衡,由nginx确定将请求转发到哪个网关节点,所有的请求都向nginx发起,上面的那些地址也都要写成nginx的地址。

如果只有一台nginx服务器,这台nginx挂了之后系统就不可用了,所以往往要用 nginx+lvs+keepalive  实现nginx的高可用。

SpringCloud Netflix Zuul的更多相关文章

  1. SpringCloud学习笔记(七、SpringCloud Netflix Zuul)

    目录: springcloud整合eureka.config.zuul zuul源码分析 springcloud整合eureka.config.zuul: 1.架构图 2.GitHub:https:/ ...

  2. 关于SpringCloud配置网关转发时出现一下啊错误:“com.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.handleException”

    com.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud.netflix.zuul ...

  3. springcloud初次zuul超时报错com.netflix.zuul.exception.ZuulException:Forwarding error

    报错如下 com.netflix.zuul.exception.ZuulException:Forwarding error Caused by: com.netflix.hystrix.except ...

  4. SpringCloud系列——Zuul 动态路由

    前言 Zuul 是在Spring Cloud Netflix平台上提供动态路由,监控,弹性,安全等边缘服务的框架,是Netflix基于jvm的路由器和服务器端负载均衡器,相当于是设备和 Netflix ...

  5. java框架之SpringCloud(6)-Zuul路由网关

    介绍 Zuul 包含了对请求的路由和过滤两个最重要的功能: 其中路由功能服务将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础.而过滤的功能则负责对请求的处理过程进行干预,是实现请求校验 ...

  6. SpringCloud之Zuul:服务网关

    Zuul在Web项目中的使用见上文<SpringBoot中使用Zuul>,下面例子为Zuul在Spring Cloud的使用. 开发工具:IntelliJ IDEA 2019.2.3 一. ...

  7. Spring-Cloud之Zuul路由网关-6

    一.为什么需要Zuul? Zuul 作为微服务系统的网关组件,用于构建边界服务( Edge Service ),致力于动态路由.过滤.监控.弹性伸缩和安全.Zuul 作为路由网关组件,在微服务架构中有 ...

  8. SpringCloud之Zuul 自定义filter

    实现过滤器很简单,只需要继承ZuulFilter,并实现ZuulFilter中的抽象方法. filterType():定义过滤器的类型,它有4种类型,分别是pre.post.routing和error ...

  9. 第九章 SpringCloud之Zuul路由

    ############Zuul简单使用################ 1.pom.xml <?xml version="1.0" encoding="UTF-8 ...

随机推荐

  1. JavaScript九九乘法表

    JavaScript九九乘法表 <script> for (var i = 1; i < 10; i++) { for (var j = 1; j <= i; j++) { d ...

  2. 为什么你SQL Server中SQL日期转换出错了呢?

    开发人员有时候使用类似下面SQL将字符串转换为日期时间类型,乍一看,这样的SQL的写法是没有什么问题的.但是这样的SQL其实有时候就是一个定时炸弹,随时可能出现问题(),下面简单对这种情况进行一个简单 ...

  3. 剑指offer-面试题58_2-左旋转字符串-字符串

    /* 题目: 将字符串的前sep个字符转移到字符串尾部. */ /* 思路: 更好的方法: 先翻转前sep个字符,再翻转后面的字符,最后全体翻转. */ #include<iostream> ...

  4. 【python基础语法】模块和包管理,文件的操作(第8天课堂笔记)

    ''' 模块和包管理 模块和包的定义: 模块:模块是一个Python文件,以.py结尾,包含了Python对象定义和Python语句 包:Python中的包就是一个包含__init__.py文件的目录 ...

  5. MongoDB initial sync过程

    initial sync过程大致如下: (1)T1时间,从Primary同步所有数据库的数据,但不包括local的数据,复制时Mongo会扫描每个源数据库中的每个集合,并将所有数据插入对应的集合.通过 ...

  6. C# MVC Api无法获得参数

    在MVC中写API时,没有收到参数如何解决? 通过jQuery.POST测试成功.后来又通过F12发送,发现始终无法收到参数. 注:我的接口接收参数是一个类对象,没有写[FromBody]) [Htt ...

  7. 斯坦福发布2019全球AI报告:中国论文数量超美国,自动驾驶汽车领域获投资最多

    近日,斯坦福联合MIT.哈佛.OpenAI等院校和机构发布了一份291页的<2019年度AI指数报告>. 这份长达291页的报告从AI的研究&发展.会议.技术性能.经济.教育.自动 ...

  8. Qt获取当前屏幕大小

    1.头文件 #include<QScreen> 2.代码 QScreen *screen = QGuiApplication::primaryScreen (); QRect screen ...

  9. Pikachu-目录遍历

    目录遍历漏洞概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量,从而让前端的功能便的更加灵活. 当用户发起一个前端的请求时,便会将请求的这个文件的值(比如文件名称)传递到后台,后台再 ...

  10. gulp常用插件之cssnano使用

    更多gulp常用插件使用请访问:gulp常用插件汇总 cssnano这是一款将你的 CSS 文件做 多方面的的优化,以确保最终生成的文件 对生产环境来说体积是最小的插件. 更多使用文档请点击访问cha ...