Spring Cloud Zuul 服务网关(路由)
写在前面 本文参考以下文章,请参考原文
Spring Cloud构建微服务架构:服务网关(基础)【Dalston版】
Spring Cloud构建微服务架构:服务网关(路由配置)【Dalston版】
1.微服务架构中 对外服务的权限控制
在微服务架构中,会存在对外服务,需要把服务公开至外部的服务调用方,为了保证对外服务的安全性,我们需要实现对服务访问的权限控制。我们可以在每个对外服务上增加权限控制逻辑,但是这样会带来两个问题:
- 服务权限控制 会贯穿整个对外服务的业务逻辑,破坏了服务集群中REST API 无状态的特点。而且在服务的开发测试过程中,除了考虑实际的业务逻辑,还要考虑对接口访问的控制处理
- 无法直接复用接口。当我们需要对一个现有的微服务接口实现外部服务访问时,必须先在原有接口上增加权限控制的功能,无法直接复用现有接口。
那怎么解决这个问题呢?服务网关
2.服务网关&Spring Cloud Netflix Zuul
在微服务架构中,我们可以把权限控制这样的逻辑 从服务单元中抽离出去,把这些逻辑放在对外访问最前端的地方,也就是服务网关。服务网关是 微服务架构中不可或缺的一部分,它具备服务路由,均衡负载,权限控制等功能,统一向外部系统提供REST API。
Spring Cloud Netflix中的Zuul 就 担任了服务网关的角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。
3.使用Spring Cloud Zuul来实现服务网关 , 验证服务路由功能
step1: 准备服务注册中心eureka-server , 准备好网关内部的微服务 eureka-client 和 eureka-consumer 请参考 Spring Cloud Eureka 服务治理--服务消费 ,Spring Cloud Eureka 服务治理--服务消费
step2:构建服务网关 创建一个基础的Spring Boot项目api-gateway。添加起步依赖 spring-cloud-starter-netflix-zuul,spring-cloud-starter-netflix-eureka-server 。如果不是通过指定serviceId的方式,eureka依赖不需要。Zuul通过整合Spring Cloud Eureka,实现对服务实例的自动化维护。
step3:在配置类添加 @EnableZuulProxy 注解开启Zuul的功能 。在配置类添加@SpringCloudApplication注解 标注这是一个spring cloud项目。
step4:在application.prsoperties文件添加配置
#微服务的名称和端口
spring.application.name: api-gateway
server.port: 1101
#指定服务注册中心的位置
eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/
这样一个基于Spring Cloud Zuul服务网关就创建好了。
step5:分别启动eureka-server , eureka-client 和 eureka-consumer ,api-gatewaty 。并访问 http://localhost:1101/eureka-client/discoveryClient ,该请求将最终被路由到eureka-client的/discoveryClient接口上。
4.Spring Cloud Netflix Zuul 服务路由功能 实现机制
根据以上的例子,可以看到 api-gatewaty 服务网关已经具备了 服务路由功能,把客户请求http://localhost:1101/eureka-client/discoveryClient 路由到了eureka-client服务的/discoveryClient接口上。那么Zuul是怎么实现 服务路由的呢?
a.Spring Cloud Zuul 通过与Spring Cloud Eureka的整合,实现了对服务实例的自动化维护。我们可以把API网关看作是Eureka服务治理下的一个普通微服务应用。它可以实现
- 将自己注册到Eureka服务注册中心上
- 从注册中心获取所有服务以及它们的实例清单
所以,在Eureka的帮助下,API网关服务本身就已经维护了系统中所有serviceId与实例地址的映射关系。
b.当服务有多个实例时,通过Ribbon的负载均衡策略 选择一个具体实例
当有外部请求到达API网关的时候,根据外部请求的URL路径找到最佳匹配的path规则,API网关就可以知道要将该请求路由到哪个具体的serviceId上去。
由于在API网关中已经知道serviceId对应服务实例的地址清单(整合Eureka服务治理),那么只需要通过Ribbon的负载均衡策略,直接在这些清单中选择一个具体的实例进行转发就能完成路由工作了。
c.在当前示例中,当我们这里构建的api-gateway应用启动并注册到eureka之后,服务网关会发现上面我们启动的两个服务eureka-client和eureka-consumer,这时候Zuul就会创建两个路由规则。每个路由规则都包含两部分,一部分是外部请求的匹配规则,另一部分是路由的服务ID。针对当前示例的情况,Zuul会创建下面的两个路由规则:
- 转发到eureka-client服务的请求规则为:/eureka-client/**
- 转发到eureka-consumer服务的请求规则为:/eureka-consumer/**
最后,我们可以通过访问1101端口的服务网关来验证上述路由的正确性:比如访问:http://localhost:1101/eureka-client/discoveryClient ,该请求将最终被路由到eureka-client的/discoveryClient接口上。
5.Spring Cloud Netflix Zuul 服务路由映射机制
5.1 默认情况 不需要显示配置
5.2 在appliction.properties配置 zuul.routes.<route>.path
与zuul.routes.<route>.serviceId
参数对
#对符合/eureka-client-zuul/**规则的请求路径转发到名为eureka-client的服务实例上去
zuul.routes.eureka-client.path=/eureka-client-zuul/**
zuul.routes.eureka-client.serviceId=eureka-client
重启api-gateway服务,访问 http://localhost:1101/eureka-client-zuul/discoveryClient 和 http://localhost:1101/eureka-client/discoveryClient 应该是统一的结果。
5.3 在appliction.properties配置 zuul.routes.<serviceId>=<path>
<serviceId>
用来指定路由的具体服务名<path>
用来配置匹配的请求表达式
#对符合/user-service/**规则的请求路径转发到名为eureka-client的服务实例
zuul.routes.eureka-client=/user-service/**
重启api-gateway服务,访问 http://localhost:1101/user-service/discoveryClient 和 http://localhost:1101/eureka-client/discoveryClient 应该是统一的结果。
注意:对同一个服务,第二种情况和第三种情况不能同时存在,否则配置方式 zuul.routes.<serviceId>=<path> 起作用