1.前言
在一个大微服务架构的系统中,可能存在着很多服务,如果将这些服务全部对外暴露,会带来很多问题。比如安全问题,有些核心服务直接对外暴露很容易被攻击;比如身份验证问题,有些接口服务是要求登录的,如果各种服务各自对外暴露,那么这些要求登录的请求第一个触达的服务模块都要向“用户服务模块”查询鉴权结果,这样既对“用户服务模块”造成额外压力,也增加了这些其它服务模块的开发成本,所以应该考虑将身份验证的事情交到网关模块中直接完成;比如运维难度和成本问题,如果每一种服务都各自对外暴露,那么整个系统就需要提供很多个域名(或者引入额外的路由中间件,如:nginx)。为了解决这些问题,给系统添加一个网关是很有必要的。
2.创建一个spring boot 模块
3.添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> <version>2.2.1.RELEASE</version> </dependency>
版本自选。
4.启用zuul
启动类:
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class RouteZuulApplication { public static void main(String[] args) { SpringApplication.run(RouteZuulApplication.class, args); } }
其中, @EnableEurekaClient 注解是将该网关模块声明为eureka服务客户端,从而注册到 eureka server(这个很容易理解,既然作为网关,那么肯定是需要将请求转发到其它服务模块,那么就需要从注册中心获取其它所有服务的信息的); @EnableZuulProxy 注解这是启用 zuul 组件,该组件内置了 ribbon 负载均衡并且默认开启。
5.配置路由
application.properties 配置:
server.port=7100
server.servlet.context-path=/gateway
spring.application.name=gateway
##################### eureka 实例(instance)信息配置 ####################
eureka.instance.appname=${spring.application.name}
#eureka.instance.hostname=localhost
##################### eureka 注册中心(server)特性配置。该模块为服务模块,不是注册中心,所以无需配置 ##################
##################### eureka 客户端(client)特性配置 ####################
#是否向 eureka server 注册服务(默认true)
eureka.client.enabled=true
eureka.client.register-with-eureka=true
#是否向 eureka server 查找服务列表(默认true)
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/server/eureka/
##################### zuul 网关配置 #######################################
zuul.host.max-total-connections=500
zuul.host.max-per-route-connections=50
#开启饥饿加载(zuul内置使用 ribbon 调用远程服务地址,而 ribbon 客户端默认是懒加载的,即第一次调用的时候才加载),配置为 true 代表应用启动的时候就加载。默认false
#zuul.ribbon.eager-load.enabled=true
zuul.routes.user=/user/**
其中:
5.1. zuul.routes 接收一个 Map<String, ZuulProperties.ZuulRoute> 类型的参数集,zuul.routes. 后紧跟的点分串值(上例中的 “user”)就是 map 参数的key,同一个 key 认为是一组配置,通常代表着一种服务;
5.2. path 参数指定路由规则的前缀,即该组路由规则适用于 url 前缀为 /user/** 的请求,/user/** 代表任意以 /user开通的url,/user/*则只能匹配一级;
5.3. service-id 指定服务,可以是服务名(eureka.instance.appname 指定的值);
5.4. 综上,本例中路由规则的含义是:所有 http://hostname:port/user/** 的请求都转发到 sys 服务模块。
上述 zuul.routes.user=/user/** 是一个服务级别的配置例子,就是说 user 服务的所有实例都会在这个路由规则里面,并参与负载均衡和熔断。另外,zuul 也支持更细粒度的配置,也就是指定服务的具体实例的 url 转发规则。这里不详述,请参照官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi__router_and_filter_zuul.html#netflix-zuul-starter
5.5. 关于路由超时配置,zuul 默认的超时时间不是很长,如果后端微服务调用链有耗时较长的,就会有很大概率一定会熔断。想要修改超时时间,分两种情况:
5.5.1. 如果路由规则是使用服务发现的(本例),则配置: ribbon.ReadTimeout 和 ribbon.SocketTimeout ;
5.5.2. 如果路由规则是直接指定服务的 url,则配置: zuul.host.connect-timeout-millis 和 zuul.host.socket-timeout-millis ;
6.验证结果
本文中没有添加新的服务服务,使用的是前文中介绍的 sys 服务模块的 UserController,链接:
Spring Cloud 学习——5.使用 feign 的 hystrix 支持
结果:
从结果看,网关服务已经生效了。
7.验证负载
sys 接收该请求的接口代码:
启动两个 sys 模块的进程实例,多次刷新请求,结果:
从打印结果看,两个 sys 进程实例都打印了请求,并且数量相当,说明负载也生效了。这也说明 zuul 默认是开启负载的,并不需要额外的配置。
8.未完待续
身份验证、支持 https 等相关功能和配置示例待续......