为什么要使用微服务网关?
不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下问题:
1、客户端会多次请求不同的微服务,增加了客户端的复杂性。
2、存在跨域请求,在一定场景下处理相对复杂。
3、认证复杂,每个服务都需要独立认证。
4、难以重构,随着项目的迭代,可能需要重新划分微服务。
5、某些微服务可能使用了防火墙或浏览器不友好协议,直接访问会有一定的困难。
为了解决这些问题,需使用微服务网关。微服务网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关,如图
微服务网关封装了应用程序的内部结构,客户端只跟网关交互,无需直接调用特定微服务的接口,其优点:
1、易于监控:可在微服务网关收集监控数据并将其推送到外部系统进行分析。
2、易于认证:可在微服务网关上进行认证,在将请求转发到后端的微服务,无需在每个微服务中进行认证。
3、减少了客户端和各个微服务之间的交互次数。
一、Zuul简介
1、身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求。
2、审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
3、动态路由:动态地将请求路由到不同的后端集群。
4、压力测试:逐渐增加指向集群的流量,以了解性能。
5、负载分配:为每一种负载类型分配对应容量,并启用超出限定值的请求。
6、静态响应处理:在边缘位置直接建立部分相应,从而避免其转发到内部集群
7、多区域弹性:跨越AWS Region进行请求路由,旨在实现ELB(Elastic Load Balancing)使用的多样化,以及让系统的边缘更贴近系统的使用者。
zuul有以下功能:
- List item
- Authentication
- Insights
- Stress Testing
- Canary Testing
- Dynamic Routing
- Service Migration
- Load Shedding
- Security
- Static Response handling
- Active/Active traffic management
现在创一个service-zuul工程
在其入口applicaton类加上注解@EnableZuulProxy,开启zuul的功能:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceZuulApplication.class, args);
}
}
加上配置文件application.yml加上以下的配置代码:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8080/eureka/
server:
port: 8088
spring:
application:
name: service-zuul
zuul:
routes:
api-a:
path: /api-a/**
serviceId: eureka-student
api-b:
path: /api-b/**
serviceId: eureka-grade
首先指定服务注册中心的地址为http://localhost:8080/eureka/,服务的端口为8088,服务名为service-zuul;以/api-a/ 开头的请求都转发给eureka-student服务;以/api-b/开头的请求都转发给eureka-grade服务;
这样就可以访问
http://localhost:8080/api-a/**
http://localhost:8080/api-b/**
下所有的接口了。。。。
但是,如果有服务调用了其他服务的接口,它配置的熔断就会不起做用,需要在application.properties中配置:
#断路器超时时间
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 6000
hystrix.command.default.execution.timeout.enabled: true
feign.hystrix.enabled: true
spring.cloud.loadbalancer.retry.enabled: true
#请求处理超时时间
ribbon.ReadTimeout: 6000
#连接超时时间
ribbon.ConnectTimeout: 6000
网关的基本步骤就完成了。。。。。。
服务过滤
zuul不仅只是路由,并且还能过滤,做一些安全验证。继续改造工程;
@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(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if(accessToken == null) {
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
}catch (Exception e){}
return null;
}
log.info("ok");
return null;
}
}
filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
pre:路由之前
routing:路由之时
post: 路由之后
error:发送错误调用
filterOrder:过滤的顺序
shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
这时访问:http://localhost:8088/api-a/students;网页显示:
token is empty
访问 http://localhost:8088/api-a/students?token=1 ; 网页显示: