1. 什么是服务网关?
服务网关就好比是一个请求的转发者,它能够根据相关的请求规则调用对应的服务提供者,它有点像nginx起到了一个代理的作用,使用服务网关可以实现限流、服务鉴权、请求处理、请求参数验证等操作。
2. 什么是zuul?
zuul是服务网关的实现之一,zuul作为一个边界性质的应用程序,它提供了动态路由、监控、弹性负载和安全功能。Zuul底层利用各种filter实现如下功能:
- 认证和安全 识别每个需要认证的资源,拒绝不符合要求的请求。
- 性能监测 在服务边界追踪并统计数据,提供精确的生产视图。
- 动态路由 根据需要将请求动态路由到后端集群。
- 压力测试 逐渐增加对集群的流量以了解其性能。
- 负载卸载 预先为每种类型的请求分配容量,当请求超过容量时自动丢弃。
- 静态资源处理 直接在边界返回某些响应。
3. 为什么选择zuul?
zuul提供了许多过滤器对请求进行处理,它能够实现认证安全、动态路由、以及性能监测,zuul的生命周期如下图所示
4. 如何使用zuul构建APIGetaway?
4.1 创建一个工程,导入相关maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</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>
4.2 在启动类上添加注解@EnableZullProxy
package com.qingyun.apigetaway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ApiGetawayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGetawayApplication.class, args);
}
}
4.3 这时我们就可以通过服务名(小写)/uri
访问我们的相关资源了
4.4 定制路由名称,将服务名映射成指定名称
要实现路由映射名称定制只需要添加配置信息就好了,如下有三种配置方式
zuul:
routes:
orderService: #第一种方式 zuul.服务名.path: /定制化路径/**
path: /myOrder1/**
productService: /myProduct/** #第二种方式 直接 zuul.服务名: /定制化路径/**
hello:
path: /myHello/**
serviceId: configService #第三种方式 zuul.随便填.path: /定制化路径/** serviceId: 指定的服务名称
我们开启所有端点查看所有的zuul路由映射
management:
endpoints:
web:
exposure:
include: "*"
访问/actuator/router
可以看到里边有我们写的映射,第三种方式没有显示是因为这是我在程序启动之后添加的。
虽然现在实现了路由映射,但是这个配置不够灵活,每次配置的更改都需要进行项目重新启动,不过这个问题也是有解决方案的,那就是通过SpringCloudBus来动态更新配置信息,如果对于动态配置更新不够理解可以看我的另一篇博客(下面部分实现在该博文中可以找到比如服务端):通过SpringCloudBus实现配置更新。
5. 使用SpringCloudBus+Zuul实现动态路由
5.1 在工程中引入SpringCloudBus相关maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
5.1 编写相关配置信息
spring:
cloud:
config:
discovery:
enabled: true #开启配置中心发现
service-id: config-server #配置中心的名称
profile: dev
bus:
id: ${spring.application.name}:${spring.cloud.config.profile}:${random.value}
profiles:
active: dev
5.2 在远程git仓库中添加配置文件,比如apiGetaway-dev.yml
server:
port: 8002
zuul:
routes:
orderService:
path: /myOrder1/**
sensitiveHeaders:
productService: /myProduct/**
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
5.3 编写一个配置类,用于动态刷新zuul配置
package com.qingyun.apigetaway.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.Configuration;
/**
* Created with IntelliJ IDEA.
* User: 李敷斌.
* Date: 2020-02-17
* Time: 19:23
* Explain: Zuul配置类
*/
@Configuration
public class ZuulConfig {
//实现动态配置
@ConfigurationProperties(prefix = "zuul")
@RefreshScope
public ZuulProperties zuulProperties(){
return new ZuulProperties();
}
}
编写完毕后就可以实现动态路由更新了,只要我们在远程git中修改了配置,本地配置都会实时更新。
6. 解决zuul中cookie无法传递的问题
在zuul中之所以cookie不可以传递是因为zuul将cookie视为敏感头,如下源码所示
/**
* List of sensitive headers that are not passed to downstream requests. Defaults to a
* "safe" set of headers that commonly contain user credentials. It's OK to remove
* those from the list if the downstream service is part of the same system as the
* proxy, so they are sharing authentication data. If using a physical URL outside
* your own domain, then generally it would be a bad idea to leak user credentials.
*/
private Set<String> sensitiveHeaders = new LinkedHashSet<>(
Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
所以我们只需要将sensitiveHeaders设置为空就好了,配置如下所示
zuul:
routes:
orderService:
path: /myOrder1/**
sensitiveHeaders:
7. 如何实现zuul高可用?
高可用是为了保障我们程序运行的可靠性,因为服务网关用于连接其他服务,要是服务网关都宕机了那么整个程序也就不可用了,也就是出现了我们常说的单点故障。为了解决这个问题我们可以通过nginx映射多个zuul服务网关实例的方式保证程序的可用性。
众所周知,nginx是一个高性能的反向代理、负载均衡服务器,它相对而言是比较可靠的,nginx+zuul的架构图如下所示。