上一篇简单说了SpringCloud与Eureka的集成。主要解决了微服务间的服务注册及调用的问题。这一篇集成Zuul,而后结合SpringCloud、Eureka、Zuul环境下进行真实系统联调,帮助更好的对这些组件的理解。毕竟,实战才是学习最快的方法。
上篇也提到过,微服务下,各个业务模块都被拆分成相互独立的微服务。虽然注册中心(如Eureka)解决了服务内部的注册发现、健康检查等问题。但是如何与外部服务进行通信又是一个新的问题了。
某初创公司,刚刚经历了一次大的架构改革。将原有的单体架构分解成了很多的微服务进行独立部署。这些微服务包括用户鉴权系统、订单系统、定时任务系统等等。而原有的JSP也被改造成基于HTML下的静态页面进行前后端分离部署。
那么问题来了,因为前后端是分开的,前端同学在调用后端不同服务时要定义各种不同的URI进行调用,管理起来太麻烦,而且,这种情况下一旦后端服务邮编,有需要重新对域名进行解析,这也侧面增加了运维同学的工作量。而更可怕的是这又与现在大家都在提倡的DevOps完全相悖了。
是的,用Nginx的确是能帮助解决服务统一入口的问题。但是因为Nginx比较偏运维性质,而且其路由配置全部都是基于配置文件的硬编码方式进行处理。一旦后台服务发生变化,配置也需要及时更改。这样也没有完全解决上述问题。
这时候,网关的出现让我看到了曙光。通过服务名就可以进行路由转发,熔断限流,日志监控,最主要的是可以开发人员自己通过配置就能轻松实现,不用每次都求运维人员去做解析。这样岂不是也是更符合DevOps了呢。
Zuul在英文中是怪兽的意思,寓意看门神兽。由大名鼎鼎的Netflix开源。并被Pivotal集成入Spring Cloud体系。当前流行的为1.X与2.X系列。主要区别为Zuul从2.X系列开始采用非阻塞异步模式,大大提升了其性能。他是基于filter机制进行工作。有统一入口、健康检查、蓝绿部署、金丝雀发布、日志监控、路由转发等功能。也可集成Ribbon、Hystrix增加负载均衡、熔断的功能。
实际开发中可以根据选择去集成Zuul网关。也可直接选择Spring集成好的Spring Cloud Zuul方便更快的使用起来。本篇重点是集成Spring Cloud Zuul。
关于Spring Cloud Zuul与Netflix Zuul相比还是有些许不一样的。他是基于SpringBoot + Netflix Zuul内核而成,去掉了原有的动态过滤器加载。所以生产环境中还是根据需要自己选择。
引入Zuul依赖
主要依赖如下:
<!-- 引入Zuul starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<!-- 连接Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> 创建业务模块provider、consumer,方法跟上一步一样。创建后项目结构如下:
配置Zuul路由转发以及ribbon、hystrix
spring.application.name = zuul-gateway
logging.level.org.spring.framework.security = INFO
#hystrix设置 时间要大于Ribbon时间总和
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = 90000
eureka.instance.instance-id = ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/
#通过eureka发现的服务。使用ribbon
ribbon.ReadTimeout = 20000
ribbon.ConnectTimeout = 20000
zuul.ignoredServices = '*'
#设置不走ribbon的time-out时间
zuul.host.connect-timeout-millis = 20000
zuul.host.socket-timeout-millis = 20000
#只要访问以/api/开头的多层目录都可以路由到服务名为kxtop-provider的服务上.
zuul.routes.kxtop-provider.path = /api/**
zuul.routes.kxtop-provider.service-id= kxtop-provider
zuul.routes.kxtop-provider.stripPrefix = false
#kxtop-consumer配置
zuul.routes.kxtop-consumer.path = /consumer/**
zuul.routes.kxtop-consumer.service-id = kxtop-consumer
zuul.routes.kxtop-consumer.stripPrefix = false
server.port = 4000
management.endpoints.web.exposure.include = * 创建Zuul启动类
@EnableDiscoveryClient //作为Eureka发现者
@EnableZuulProxy //开启Zuul
@SpringBootApplication
public class ZuulGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulGatewayApplication.class);
}
} 分别配置provider、consumer配置文件及启动类
provider
spring.application.name = kxtop-provider
server.port = 5000
eureka.instance.instance-id = ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/
logging.level.org.spring.framework.security = INFO
server.servlet.context-path = /api
management.endpoints.web.exposure.include = *
-------------------------
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class);
}
} consumer
spring.application.name = kxtop-consumer
server.port = 6000
eureka.instance.instance-id = ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/
logging.level.org.spring.framework.security = INFO
server.servlet.context-path = /consumer
management.endpoints.web.exposure.include = *
--------------------------
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
} 整体测试
localhost:8761
分别启动项目Zuul、provider、consumer
服务端口对照
| 服务名 | 端口号 |
|---|---|
| zuul-gateway | 4000 |
| provider | 5000 |
| consumer | 6000 |
postman测试网关调用
provider模块新建TestGatewayController,并重启provider
@RestController
@RequestMapping("/test-gateway")
public class TestGatewayController {
@GetMapping
public String testGateway() {
return "Hi! 我是Consumer服务中的TestGatewayController.";
}
}
下一篇会针对以上的整合做更加详细的配置,我们会基于ZuulGateway去做更丰富测试(比如provider、consumer模块如果是部署集群网关该怎样处理?他们之间的负载均衡策略又是怎样的?连接超时、恶意访问怎样做熔断限流?服务之间如何调用?),进行接近生产级项目的配置。敬请关注!
持续学习,记录点滴。 更多请点击查看原文