前记
上一章了解断路器,这章将看看路由网关。
微服务
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。
在 SpringCloud 微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在Git仓库,方便开发人员随时改配置。
Zuul
Zuul 的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如 /api/user 转发到到 user 服务,/api/shop 转发到到 shop 服务。Zuul 默认和 Ribbon 结合实现了负载均衡的功能。
Zuul 功能:
- Authentication
- Insights
- Stress Testing
- Canary Testing
- Dynamic Routing
- Service Migration
- Load Shedding
- Security
- Static Response handling
- Active/Active traffic management
使用
新建一个 Module,命名为 zuulServer,添加依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <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-zuul</artifactId> <version>1.4.4.RELEASE</version> </dependency>
</dependencies>
|
添加注解 @EnableZuulProxy
开启 Zuul 功能(作为服务,其本身也要向 Server 中心注册):
1 2 3 4 5 6 7 8 9
| @EnableZuulProxy @EnableEurekaClient @SpringBootApplication public class ZuulServiceApplication {
public static void main(String[] args) { SpringApplication.run(ZuulServiceApplication.class, args); } }
|
配置文件 application.properties
:
1 2 3 4 5 6 7 8 9 10 11 12
| server.port=10000
spring.application.name=zuulService
eureka.client.service-url.defaultZone=http://localhost:7000/eureka/
# 以 /api-a/ 开头的请求都转发给 ribbonConsumer 服务 zuul.routes.api-a.path=/api-a/** zuul.routes.api-a.service-id=ribbonConsumer # 以 /api-b/ 开头的请求都转发给 feignConsumer 服务 zuul.routes.api-b.path=/api-b/** zuul.routes.api-b.service-id=feignConsumer
|
访问 api-a:
1 2
| $ curl http://localhost:10000/api-a/add\?a\=2\&b\=91 Result: 93, from port: 8000
|
访问 api-b:
1 2
| $ curl http://localhost:10000/api-b/add\?a\=2\&b\=91 Result: 93, from port: 8000
|
可以看到 Zuul 起到了路由作用。
服务过滤
Zuul 还有过滤,安全验证的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| @Component public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
@Override public String filterType() { return "pre"; }
@Override public int filterOrder() { return 0; }
@Override public boolean shouldFilter() { return true; }
@Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); Object token = request.getParameter("token"); if (token == null) { log.warn("token is empty"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); ctx.setResponseBody("token is empty"); return null; } log.info("token ok"); return null; } }
|
测试没有 token 时:
1 2 3 4 5 6
| $ curl -i http://localhost:10000/api-b/add\?a\=2\&b\=91 HTTP/1.1 401 Transfer-Encoding: chunked Date: Mon, 28 May 2018 08:16:09 GMT
token is empty
|
测试有 token 时:
1 2
| $ curl http://localhost:10000/api-b/add\?a\=2\&b\=91\&token\=123 Result: 93, from port: 8000
|
总结
- 不仅仅实现了路由功能来屏蔽诸多服务细节,更实现了服务级别、均衡负载的路由。
- 实现了接口权限校验与微服务业务逻辑的解耦。通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理。
- 实现了断路器,不会因为具体微服务的故障而导致服务网关的阻塞,依然可以对外服务。