初识API网关
使用API网关有点
- 统一访问出入口,微服务对前台透明
- 安全,过滤,流控等API管理功能
- 利于监控、方便管理
API网关产品
- Netflix Zuul
- Zuul 是Netflix开源的一个API网关, 核心实现是Servlet
- Spring Cloud内置Zuul 1.x
- Zuul 1.x 核心实现是Servlet,采用同步方式通信
- Zuul 2.x 基于Netty Server,提供异步通信
- Spring Cloud Gateway
- Spring Cloud Gateway,是Spring自己的项目
- Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式
- Gateway基于Spring 5.0与Spring WebFlux开发,采用Reactor响应式设计
一、Zuul入门使用
1.1、pom.xml
添加依赖
代码语言:javascript复制<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.15.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codesofun</groupId>
<artifactId>zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2、启动类添加注解@EnableZuulProxy
网管Zulul
也是一个微服务客户端,所以入口类上也需要添加@EnableEurekaClient
或@EnableDiscoveryClient
package com.codesofun.zuul;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
1.3、添加application.properties
配置
代码语言:javascript复制spring.application.name=zuul-proxy
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#微服务实例接口映射路径
zuul.routes.book-service-api.path=/bs/**
#微服务实例ID
zuul.routes.book-service-api.service-id=book-service
zuul.routes.member-service-api.path=/ms/**
zuul.routes.member-service-api.service-id=member-service
zuul.routes.message-service-api.path=/sms/**
zuul.routes.message-service-api.service-id=message-service
#端口一般为80 或 443
server.port=443
二、Zuul负载均衡与服务降级
2.1、负载均衡
Spring Cloud Zuul内置Ribbon,与标准配置相同,局部配置如下:
代码语言:javascript复制#局部设置网关与 book-service 微服务通信负载均衡策略
book-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
全局配置可以放在bean 配置类中交给IOC容器管理,主要配置如下:
代码语言:javascript复制 @Bean
public IRule ribbonRule(){
return new RandomRule();
}
2.2、配置服务降级
Spring Cloud Zuul内置Hystrix,服务降级需要实现接口FallbackProvider
,如下:
package com.codesofun.zuul.fallback;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @ClassName BookServiceFallBack
* @Description Book-service 服务降级
* @Author mozhijun
* @Date 2020/7/8 15:43
* @Version 1.0
**/
@Component
public class BookServiceFallBack implements FallbackProvider {
/**
* 设置为哪个微服务提供降级
*/
@Override
public String getRoute() {
return "book-service";
}
/**
* 描述: 降级处理逻辑
* @Author mozhijun
* @Date 15:45 2020/7/8
* @param route 服务ID
* @param cause 抛出的异常信息
* @return org.springframework.http.client.ClientHttpResponse 服务降级response
*/
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/**
* 响应状态码
*/
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
/**
* 数字状态
*/
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
/**
* 状态文本说明
*/
@Override
public String getStatusText() throws IOException {
return "ok";
}
/**
* 关闭的回收触发,一般用于资源的释放
*/
@Override
public void close() {
}
/**
* 响应给客户端的内容
*/
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("Book Service is unavailable".getBytes());
}
/**
* 响应头信息
*/
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_HTML);
return headers;
}
};
}
}
getRoute()
中返回指定微服务的实例名称,设置所有微服务默认降级回调,这里只需要返回*
即可
/**
* 设置为哪个微服务提供降级
*/
@Override
public String getRoute() {
return "book-service";
}
三、基于RateLimit实现网关限流
微服务网关流量控制
- 微服务网关是应用入口,必须对入口流量进行控制
- RateLimit是Spring Cloud Zuul的限流组件
开源网站地址
https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit
- RateLimit采用
令牌桶
算法实现限流
RateLimit使用步骤
3.1、pom.xml
添加依赖
代码语言:javascript复制<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.15.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codesofun</groupId>
<artifactId>zuul-ratelimit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul-ratelimit</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2、配置存储组件
这里存储使用关系型数据库mysql
,orm框架使用jpa
,添加配置如下:
spring.application.name=zuul-proxy
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
############ zuul ############
#微服务实例接口映射路径
zuul.routes.book-service-api.path=/bs/**
#微服务实例ID
zuul.routes.book-service-api.service-id=book-service
zuul.routes.member-service-api.path=/ms/**
zuul.routes.member-service-api.service-id=member-service
zuul.routes.message-service-api.path=/sms/**
zuul.routes.message-service-api.service-id=message-service
#开启zuul限流,默认false
zuul.ratelimit.enabled=true
# 对应存储类型(用来统计存储统计信息)
zuul.ratelimit.repository=jpa
########## 数据源 #########
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=mzj584wanlhy
spring.jpa.database-platform=org.hibernate.dialect.MySQL57InnoDBDialect
spring.jpa.show-sql=true
#局部设置网关与 book-service 微服务通信负载均衡策略
book-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
#端口一般为80 或 443
server.port=443
创建表**rate
**
CREATE TABLE rate (
rate_key VARCHAR(255) NOT NULL,
remaining BIGINT,
remaining_quota BIGINT,
reset BIGINT,
expiration TIMESTAMP,
PRIMARY KEY(rate_key)
);
3.3、配置限流策略
代码语言:javascript复制######默认限流策略全局配置: 对同一个url请求 5秒内最多10次,其余会被限流###########
#每个刷新时间窗口对应的请求数量限制
zuul.ratelimit.default-policy-list[0].limit=10
#每个刷新时间窗口对应的请求时间限制(秒)
zuul.ratelimit.default-policy-list[0].quota=1000
# 刷新时间窗口的时间,默认值 (秒)
zuul.ratelimit.default-policy-list[0].refresh-interval=5
#限流方式
zuul.ratelimit.default-policy-list[0].type=url
####在zuul与book-service通信时,每2秒内,只允许2个请求访问,其余进来的请求会被限制访问,并返回状态码429#####
# 每秒允许多少个请求
zuul.ratelimit.policy-list.message-service-api[0].limit=2
# 刷新时间(单位秒)
zuul.ratelimit.policy-list.message-service-api[0].refresh-interval=2
#限流方式: 可选user(用户限制) origin(请求限制) url(对同一个url访问限制) http_method
zuul.ratelimit.policy-list.message-service-api[0].type=origin
zuul.ratelimit.policy-list.member-service-api[0].limit=2
zuul.ratelimit.policy-list.member-service-api[0].refresh-interval=2
zuul.ratelimit.policy-list.member-service-api[0].type=origin
zuul.ratelimit.policy-list.book-service-api[0].limit=2
zuul.ratelimit.policy-list.book-service-api[0].refresh-interval=2
zuul.ratelimit.policy-list.book-service-api[0].type=origin
四、Zuul自定义过滤器
自定义过滤器,需要继承com.netflix.zuul.ZuulFilter
类,这里模拟一个TOKEN校验的过滤器,具体如下:
package com.codesofun.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @ClassName SecurityFilter
* @Description 自定义安全过滤器
* @Author mozhijun
* @Date 2020/7/9 16:58
* @Version 1.0
**/
@Component
public class SecurityFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
/**
* 执行顺序
*/
@Override
public int filterOrder() {
return 6;
}
/**
* 当前过滤器是否被执行
*/
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
//获取上下文
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
//对该请求禁止路由,也就是禁止访问下游服务
context.setSendZuulResponse(false);
//状态码
context.setResponseStatusCode(403);
context.setResponseBody("{"code":403,"message":"Token is unavailable"}");
return null;
}
//校验Token正确性代码
context.setSendZuulResponse(true);
context.setResponseStatusCode(200);
return null;
}
}
详细代码见仓库:https://gitee.com/xmlvhy/springcloud-learn
参考链接:http://www.itlaoqi.com/
本文作者: [AI码真香](https://www.xmlvhy.com/about)
代码语言:txt复制 本文标题: [SpringCloud入门系列之API网关](https://www.xmlvhy.com/article/detail/91.html)
代码语言:txt复制 本文网址: [https://www.xmlvhy.com/article/91.html](https://www.xmlvhy.com/article/detail/91.html)
代码语言:txt复制 版权说明: 自由转载-非商用-非衍生-保持署名 [ 署名-非商业性使用4.0 国际 (CC BY-NC 4.0) ](https://creativecommons.org/licenses/by-nc/4.0/deed.zh)
类似文章
- SpringCloud入门系列之配置中心
- SpringCloud入门系列之微服务之间的通信
- SpringCloud入门系列之服务链路追踪Sleuth&Zipkin
- SpringCloud入门系列之Eureka注册中心
- Redis 客户端常用命令