前言
看这篇文章之前,我建议还是先看一下我之前写的两篇文章(feign服务调用;负载均衡与熔断)。
spring cloud zuul是一个网关相关技术,它统一代理所有服务的访问路径。并且还可以在访问过程中拦截请求,做一些过滤操作。zuul自带了负载均衡和熔断依赖,那么这些依赖会对原先feign的负载均衡、熔断产生什么影响呢?以及限流操作是怎么实现的,下述文章将会通过例子的方式来讲述。
zuul的负载均衡(不通过消费者调用,直接访问提供者)
准备两个服务
yml配置
provider
server:
port: 8081
spring:
application:
name: provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
provider2
server:
port: 8091
spring:
application:
name: provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
接口
provider
@RestController
public class TestController {
@RequestMapping(value = "/test3")
public String thirdCloud(){
return "test3";
}
provider2
@RestController
public class TestController {
@RequestMapping(value = "/test3")
public String thirdCloud(){ //空参
return "test33332222";
}
以上两个服务为了达到负载均衡的效果。包名,路径映射,eureka注册路径等都一样。
启动服务后可以看到eureka的变化
zuul配置
pom.xml
<?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>com.qiu</groupId>
<artifactId>boot2cloud</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.qiu</groupId>
<artifactId>zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml配置
server:
port: 9999
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
启动类上开启zuul代理功能
@SpringBootApplication
@EnableZuulProxy //开启zuul代理
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
以上,zuul的初步配置就完成了
传统访问
通过zuul网关访问提供者(添加服务名就可以访问到)
zuul访问方式刷新,发现调用的接口是另一个提供者的,说明负载均衡的作用出来了,不需要任何配置,只要有两个服务是集群关系即可自行起效。
自定义zuul访问规则
如果仅仅是上述配置,那么zuul的访问规则是:ip:port /服务名/接口路径
但是如果想改变这个规则,可以在yml文件中进行如下配置
zuul:
routes:
customer: /cus/** #服务名: 代理的路径
provider: /pro/** #服务名: 代理的路径
ignored-services: "*" #规定原来的路径无法访问,必须通过zuul的路由才能访问。
以上配置后重启服务
用http://localhost:9999/provider/test3去访问的时候会出现如下结果。
用http://localhost:9999/pro/test3访问才可以访问的到。
zuul的熔断
我以前的文章介绍过feign它是整合了熔断的,当访问的服务宕掉的时候会返回指定的内容。但是feign的熔断在zuul好像失效了。
所以,只好再配置zuul的熔断了
配置十分简单,不用添加依赖、不用改yml,也不用在启动类添加什么注解,只需要添加一个java代码。
package com.qiu.zuul.mybreak;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author VULCAN
* @create 2020/1/13 1:30
*/
@Component
public class ZuulFallBack implements FallbackProvider {
//熔断配置
@Override
public String getRoute() {
//作用于所有被zuul代理的服务
return "*";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
//添加头信息,必须要添加,不添加则熔断失败
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("reason","theboom");
return httpHeaders;
}
@Override
public InputStream getBody() throws IOException {
//如果熔断了展现出什么信息
byte[] bytes = "your serve has boom".getBytes("UTF-8");
return new ByteArrayInputStream(bytes);
}
@Override
public HttpStatus getStatusCode() throws IOException {
//报错类型400
return HttpStatus.BAD_REQUEST;
}
@Override
public int getRawStatusCode() throws IOException {
//错误代码,和上述HttpStatus一致就行
return 400;
}
@Override
public String getStatusText() throws IOException {
return null;
}
@Override
public void close() {
}
};
}
}
配置完成后,我们重启所有服务,然后在宕掉消费者调用的所有提供者。‘
访问消费者路径http://localhost:9999/cus/feignRibbonTest
出现指定内容,为了更好的展现信息,我这一回使用postman来测试接口
zuul的限流
在一些高并发的项目中,为了保护网站不被恶意攻击(疯狂刷新导致服务器压力过高),限流的作用就体现出来了,它能指定一个规则,哪个ip在多少分钟内能访问多少次,访问次数超过限制后会报错。
zuul本身没有限流的功能,所以我们需要借助另外的依赖。
github地址:https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit
点开他,在下方有说明书
那么根据这个说明书的内容引入这两个maven坐标
<!-- 用于zuul限流-->
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>LATEST</version>
</dependency>
<!-- 基于redis来计数-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
说明书也有yml配置说明
删除里面多余的内容,并启动redis服务,添加进yml
redis: #计数操作在redis里面执行
port: 6379
host: localhost
zuul:
ratelimit:
enabled: true
repository: redis
behind-proxy: true
add-response-headers: true
default-policy-list: #所有服务都有效
- limit: 10 #限制次数,每刷新一次次数+1
quota: 1000 #窗口对应的请求时间限制
refresh-interval: 60 #多少秒后刷新计数
type: #optional #限制类型
- origin #url 包括ip+接口
重新启动服务后,我们对一个服务疯狂刷新。
起初是正常的
但是达到十次之后
用图形化工具打开redis。里面的计数情况:value则是刷新的次数,TTL则是这个String的生命周期,14代表的是还剩下14秒这个key就会被删除。
zuul的过滤
zuul的过滤在这篇文章中暂时不讲,今后会和oauth2整合的时候再讲述。