SpringCloud系列:6.微服务网关服务Zuul

一、Zuul简介

在微服务场景下,随着业务的发展,原来简单的系统会变得越来越复杂,系统会由原来几个独立的微服务逐渐变成几十个、上百个甚至更多。这样如果每个服务都对外暴露自己的服务接口,将使得微服务的调用变得极其复,例如,我们访问用户微服务时,要调用用户微服务的ip1:port1/api,调用书籍微服务时要调用book-server的ip2:port2/api,随着这样的服务越来越多,基于这样的实现,维护成本将是噩梦级别的。

另外,我们可以想到的一些的公共功能,例如对于客户端的身份验证、业务鉴权、流量与并发控制及响应数据脱敏等控制,难道我们需要每个微服务都放置一遍吗?

显然,SpringCloud不会让这些重复的功能和复杂的设计直接暴露给使用者,所以,API服务网关(API Gateway)应运而生。API服务网关帮助开发者隐藏系统架构实现的细节,提供统一的入口供客户端访问,让微服务使用更为友好。同时通过微服务的统一访问控制,简化了客户端开发的复杂度,降低了客户端与微服务之间的通信次数,客户端不需要与多个微服务之间进行通信,也不需要了解各个微服务的详细信息。而且借助API服务网关可统一做切面任务,避免每个微服务自己开发,提升效率,使系统更加标准化,解决了公共功能重复开发的问题。

Zuul就是API服务网关的一种,是Netflix提供的基于JVM路由和服务端的负载均衡器,其参考GOF设计模式中的外观(Facade)模式,将细粒度的服务组合起来提供了一个粗粒度的服务,以便所有请求都导入一个统一的入口,整个服务只需要暴露一个API,对外屏蔽了服务端的实现细节。

通过Zuul组件,可以完成以下功能:

·动态路由:Zuul路由服务器支持与Eureka服务器的整合,可以动态对注册到Eureka服务器中的微服务进行路由映射。另外,Zuul提供一系列的路由规则配置,可以针对生产中的实际情况进行配置,实现微服务路由的灵活控制。

·监控与审查:通过对一些特定的接口设置访问白名单、访问次数、访问频率等各类设置,可以在不影响微服务实现的情况下,对访问实施监控和审查处理。

·身份认证与安全:通过Zuul可以将认证的部分单独抽取出来,让微服务系统无须关注认证的逻辑,只需要关注业务本身即可。

·压力测试:通过Zuul所提供的过滤器功能可以逐渐增加对某一服务集群的流量,以了解服务性能,从而及早对服务运维架构做出调优。

·金丝雀、A/B测试:新版本、新功能可能都需要测试用户对其的反应,通过API服务网关,可以轻松控制部分用户访问服务实例,并且可以对用户行为进行记录和分析,以便对新版本及新功能进行评价,获取应用的最优方案。

·服务迁移:通过Zuul代理可以处理来自旧端点的客户端上的所有流量,将一些请求重定向到新的端点,从而慢慢地用不同的实现来替换旧端点。

·负载剪裁/限流:为每一个负载类型分配对应的容量,对超过限定值的请求弃用,这样可以防止站点不被未知的大流量冲跨。通常,可以利用API服务网关配置一个阀值,当请求数超过该阀值时会直接返回错误,而不会运行剩下的逻辑。

二、示例演示

继续改造上一章的微服务代码,为我们的微服务项目增加Zuul网关。

创建基于maven的Zuul项目zuul-server,在pom文件中主要引入Eureka和Zuul的依赖。特别注意,zuul-server中使用2.1.1.RELEASE版本springboot会报错,可更换版本为2.0.3.RELEASE,正常启动。

<?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">
	<modelVersion>4.0.0</modelVersion>

	<!-- 这里将项目的父项目设置为Spring Boot,所使用版本为2.1.1.RELEASE -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.3.RELEASE</version>
		<relativePath />
	</parent>

	<!-- 这里设置本项目的groupId、artifactId和版本等信息 -->
	<groupId>com.yanger</groupId>
	<artifactId>zuul-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>zuul-server</name>
	<description>Demo project for SpringCloud</description>

	<properties>
		<!-- 定义项目所使用的编码为UTF-8 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<!-- 项目所用JDK 1.8,也可以使用低版本,但建议还是使用JDK 1.8以上版本 -->
		<java.version>1.8</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>
		<!-- 项目所使用第三方包的版本,统一在一个地方声明版本号,对项目可以进行统一管理,方便以后升级 -->
		<spring-cloud.version>Finchley.SR2</spring-cloud.version>
	</properties>

	<dependencies>

		<!-- 项目所用Spring Boot starters:web -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- eureka服务注册 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
		
		<!-- zuul网关 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>

		<!-- test依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- 热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- optional=true,依赖不会传递 -->
			<optional>true</optional>
			<scope>true</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>
				<configuration>
					<fork>true</fork>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

然后在启动类上@EnableZuulProxy声明这是一个Zuul网关,当然,我们的网关也是要注册到Eureka上的。

看过前面章节的都知道了,接下来就是配置文件了,配置文件中,除了server的基本声明与Eureka注册信息外,额外的就是Zuul的配置了,其中主要的路由规则配置,从展示的配置中,相信即使没有使用过的人也能一眼看明白,其中**表示任意字符,路由规则满足/api/book/**的将调用book-server,而/api/user/**规则的将访问user-server。

这样配置到底有没有作用呢,现在我们来启动我们的服务。分别启动eureka-server、book-server、user-server、zuul-server。

服务全都启动成功后,我们来访问book-server与user-server中的接口。我使用了火狐的rested插件,这里大家可以使用postman或者其他请求调用工具进行测试。

可以看到,我们通过网关调用http://localhost:10840/api/user/user/find/feign/3,成功请求服务获取了完整的请求数据,其中/api/user表明请求user-server,而/user/find/feign/3则去user-server中寻找对应的请求接口,而通过Zuul网关的访问, 我们并不需要关心用户服务的ip和端口。

二、Zuul过滤器

Zuul核心功能除了路由配置以外,还有就是其封装的过滤器,以方便我们做一些公共功能的开发。现在我们在zuul-server中添加一个过滤器,声明一个Filter很简单,在Zuul中,我们可以继承ZuulFilter,实现其提供的抽象方法即可。当然别落下@Component注解。

对于Zuul的过滤器,主要以下四个方法:

·run:方法中是具体的逻辑,这里为了简化,只打印了zuul请求路径。

·filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,pre表示路由之前,routing表示路由之时,post是路由之后,error作用发送错误调用之后。

·filterOrder:过滤的顺序,数字越小表示顺序越靠前。

·shouldFilter:这里可以写逻辑判断,是否要过滤,这里简单返回true,直接过滤。

再次访问之前的方法,我们可以看到zuul-server控制台输出了请求路径信息,表明所有的请求在调用zuul-server时,都进入到ZuulServiceeFilter中。

源码地址: https://github.com/imyanger/springcloud-project/tree/master/p5-zuul

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值