Spring Cloud入门3——API Gateway

为什么要使用API Gateway

如果客户端直接调用微服务的话可能会存在以下问题:

1. 移动客户端或者web客户端调用的微服务数量可能非常多。例如,亚马逊的产品最终页要请求数百个微服务。虽然一个客户端可以通过LAN发起很多个请求,但是在公网上这样会很没有效率,这个问题在移动互联网上尤为突出。这个方案同时会导致客户端代码非常复杂。
2. 微服务的协议可能并不是web友好型。一个服务可能是用Thrift的RPC协议,而另一个服务可能是用AMQP消息协议。它们都不是浏览或防火墙友好的,并且最好是内部使用。应用应该在防火墙外采用类似HTTP或者WEBSocket协议。
3. 随着时间的推移,我们可能需要改变系统微服务目前的切分方案。例如,我们可能需要将两个服务合并或者将一个服务拆分为多个。但是,如果客户端直接与微服务交互,那么这种重构就很难实施。

采用API Gateway就可以解决这些问题。


API Gateway是一个服务器,也可以说是进入系统的唯一节点。API Gateway封装内部系统的架构,并且提供API给各个客户端。它还可能有其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等。

如图:


API Gateway负责请求转发、合成和协议转换。所有来自客户端的请求都要先经过API Gateway,然后路由这些请求到对应的微服务。API Gateway将经常通过调用多个微服务来处理一个请求以及聚合多个服务的结果。它可以在web协议与内部使用的非Web友好型协议间进行转换,如 HTTP协议、WebSocket协议。


Spring Cloud提供了Zuul组件来实现API Gateway。

首先还是添加依赖:

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
在application主类中添加@EnableZuulProxy和@SpringCloudApplication
@EnableZuulProxy
@SpringCloudApplication
public class SpringcloudZuulApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringcloudZuulApplication.class, args);
	}
	
}
@SpringCloudApplication注解整合了多个注解,@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker等。可以简化配置。
最后在application.properties配置文件中增加端口以及应用名配置:

spring.application.name=api-gateway
server.port=5555

接下来就是功能了,让API Gateway进行请求的转发。可以这样做。在application配置文件中增加以下配置。

zuul.routes.serviceA.path=/serviceA/**
zuul.routes.serviceA.serviceId=service-A
zuul.routes.serviceB.path=/serviceB/**
zuul.routes.serviceB.serviceId=service-B
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

前四行都是请求映射,意思是访问所有/serviceA路径下的请求都会被转发给serviceId为service-A的微服务,所有/serviceB路径下的请求都会被转发给serviceId为service-B的微服务。

也就是说,访问http://localhost:5555/serviceA/add?a=1&b=2请求会被转发到service-A的服务上,带着参数add?a=1&b=2。
最后一行是在注册中心中注册自己,为了获取serviceId的。


API Gateway除了可以给客户端提供API之外,还可以进行权限控制之类的,也就是AOP操作。在Zuul中,只需要继承ZuulFilter并重载其中的方法就可以了。

public class AccessFilter extends ZuulFilter  {
    private static Logger log = LoggerFactory.getLogger(AccessFilter.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 request to %s", request.getMethod(), request.getRequestURL().toString()));
        Object accessToken = request.getParameter("accessToken");
        if(accessToken == null) {
            log.warn("access token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            return null;
        }
        log.info("access token ok");
        return null;
    }
}
这里有四个方法:

1. filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
pre:可以在请求被路由之前调用
routing:在路由请求时候被调用
post:在routing和error过滤器之后被调用
error:处理请求时发生错误时被调用

即下图:


2. filterOrder:通过int值来定义过滤器的执行顺序

3. shouldFilter:返回一个boolean类型来判断该过滤器是否要执行

4. run:过滤器的具体逻辑。这里简单的进行了判断是否存在accessToken这个参数。

最后让这个类生成相应的实例,让其工作起来。

@Bean
public AccessFilter accessFilter() {
	return new AccessFilter();
}
这样,我们只有访问带有accessToken的参数才可以正确的访问到服务,实现了简单的权限控制。

如:http://localhost:5555/service-A/add?a=1&b=2&accessToken=token



总结

API Gateway有优点也有缺点。

API Gateway的一个最大好处是封装应用内部结构。相比起来调用指定的服务,客户端直接跟gatway交互更简单点。API Gateway提供给每一个客户端一个特定API,这样减少了客户端与服务器端的通信次数,也简化了客户端代码。


API Gateway也有一些缺点。它是一个高可用的组件,必须要开发、部署和管理。还有一个问题,它可能成为开发的一个瓶颈。开发者必须更新API Gateway来提供新服务提供点来支持新暴露的微服务。更新API Gateway时必须越轻量级越好。否则,开发者将因为更新Gateway而排队列。但是,除了这些缺点,对于大部分的应用,采用API Gateway的方式都是有效的。

发布了67 篇原创文章 · 获赞 68 · 访问量 24万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览