是什么
说Zuul之前,我们先来说一下之前我们做过的项目架构,我们之前使用Eureka实现服务注册中心以及服务注册与发现功能,而服务间通过Ribbon或OpenFeign实现服务的消费以及均衡负载。为了使得服务集群更为健壮,使用Hystrix的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延。
在这样的架构中,我们的服务集群虽然注册到了Eureka中,但是确实一个对外的服务,通过负载均衡公开至服务的调用方。这样直接暴露我们的服务地址存在很大的不足:
-
破坏了服务无状态特点。
为了保证对外服务的安全性,我们需要实现对服务访问的权限控制,而开放服务的权限控制机制将会贯穿并污染整个开放服务的业务逻辑,这会带来的最直接问题是,破坏了服务集群中REST API无状态的特点。从具体开发和测试的角度来说,在工作中除了要考虑实际的业务逻辑之外,还需要额外考虑对接口访问的控制处理。
-
无法直接复用既有接口。
当我们需要对一个即有的集群内访问接口,实现外部服务访问时,我们不得不通过在原有接口上增加校验逻辑,或增加一个代理调用来实现权限控制,无法直接复用原有的接口。
为了解决上面的问题,服务网关出现了。
应用服务网关,可以将权限控制从服务单元中抽离出去,而最适合这些逻辑的地方就是处于对外访问对前端的地方。服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由
、均衡负载
功能之外,它还具备了权限控制
等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。
我们看一下加入Zuul后的服务架构:
不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴权、动态路由等等操作。Zuul就是我们服务的统一入口。
实例
我们同样应用之前案例中的微服务项目,在父工程中新建zuul工程。
(1)新建子工程
(2)导入依赖
<?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>eureka-practice</artifactId>
<groupId>com.zhyheima.bj</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zuul</artifactId>
<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>
</project>
因为zuul也是一个服务,并且需要定时拉取服务,所以我们也需要注册到Eureka服务中心。
(3)编写配置
server:
port: 10010 #服务端口
spring:
application:
name: zuul #指定服务名
eureka:
client:
register-with-eureka: true #是否 将自己注入到eureka
fetch-registry: true #是否从eureka服务中抓取已有的 注册信息
service-url: #将生产者分别注册到两个服务中心
defaultZone: http://eureka10086.com:10086/eureka,http://eureka10087.com:10087/eureka
instance:
instance-id: zzhhyy:zuul10010 #注入到eureka后的id标识,不写的标识为ip地址
prefer-ip-address: true #访问路径可以显示ip地址
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 30
#Eureka服务端在收到最后一次心跳后等待时间上限 ,单位为秒(默认是90秒),超时剔除服务
lease-expiration-duration-in-seconds: 90
(4)编写引导类
package com.zhyheima.bj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient //开启eureka客户端
@EnableZuulProxy //开启网关功能
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
我们重新启动,查看eureka注册中心中的信息,发现已经注册成功:
(5)编写路由规则
这里我们配置面向服务的路由,根据服务的名称,去eureka注册中心查找服务对应的所有实例列表。
映射规则:
我们将/item/**开头的请求,代理到以item-server为服务名的服务中。
重启zuul服务,输入访问地址:
http://localhost:10010/server/test/2
http://localhost:10010/consumer/test/2
查看访问成功:
(6)路由前缀
配置示例:
zuul:
routes:
item-server: /server/** # 这里是映射路径
item-consumer: /consumer/**
prefix: /api # 添加路由前缀
我们通过zuul.prefix=/api
来指定了路由的前缀,这样在发起请求时,路径就要以/api开头。
(7)zuul提供的其他属性
ignored-patterns属性,用来忽略不希望路由的URL路径
zuul.ignored-patterns: /upload/**
ignored-services属性,进行服务过滤
zuul:
ignored-services:
- upload-service # 忽略upload-service服务